GrDateTimePicker
Берут, когда момент, а не день.
Когда брать
- момент, а не день — начало встречи, дедлайн, время публикации: дата без времени здесь означала бы полночь, чего пользователь не имел в виду;
- выбор из нескольких шагов — день, час, минута;
autoApply: falseдаёт подтверждение, чтобы значение не уезжало после первого же клика; - нужны секунды —
enableSecondsдобавляет третью колонку; - на бэкенд уходит строка —
valueAdapter="isoDateTime"отдаёт'2026-08-12T14:30:00'без смещения: это то, что человек видит на часах.
Когда взять другое
| Нужно | Берите |
|---|---|
| Только дата | GrDatePicker |
| Только время | GrTimePicker |
| Период «с — по» | GrDateRangePicker |
| Сетка месяца без поля | GrCalendar |
| Показать момент, а не выбрать | GrRelativeTime |
Период с временем на границах этот пакет не закрывает: GrDateRangePicker
работает с датами. Собирается из двух GrDateTimePicker с проверкой порядка на
стороне формы.
`autoApply` здесь значит не то же, что у даты
У выбора одной даты клик по дню — это и есть готовое значение, и подтверждать
нечего. Здесь значение собирается минимум из двух частей, поэтому «применить»
означает «я закончил», а не повторяет уже сделанное. Дефолт — true: чаще
достаточно даты плюс часа, и лишняя кнопка на каждом выборе раздражает.
Ручной ввод
editable включает набор с клавиатуры: одна строка задаёт и дату, и время.
<GrDateTimePicker v-model="startsAt" editable />
Разбор идёт от Intl: где в строке дата, а где время, какой у частей порядок и чем они
разделены, знает локаль, а не паттерн. Поэтому набирать можно как удобно — 8/14/2026 10:15,
8/14/2026, 10:15, 08.14.2026 10:15: разделители разбору безразличны, он смотрит на группы цифр.
Локали, в которых время идёт перед датой (vi — 15:30 12/8/26), разбираются так же.
Набранная дата без времени время не сбрасывает — остаётся то, что стоит в модели; при пустой модели это полночь. Не набранное просто не меняется.
Текст подтверждает сам себя, минуя autoApply. Проп управляет панелью, где выбор многошаговый
и «применить» значит «я закончил». Enter в поле — это уже законченное действие, и уход в черновик
выглядел бы как «ничего не произошло»: поле-то показывает модель.
Панель идёт за набором. Как только дата набрана целиком, она подсвечена в сетке, и сетка
перешла на её месяц; набранный час подсвечен в колонке часов, минуты — в минутах. Модель не
меняется: её меняет Enter или уход фокуса. Набирать вслепую, глядя на панель с прежним значением,
— это ровно та ошибка, которую поле должно было убрать.
Запрещённое значение текстом не принимается — ни дата из disabledDates, ни момент за min или
max. Правило одно на клик и на Enter, иначе поле обходило бы ограничения панели.
Неразобранный текст на уходе фокуса откатывается к модели; apply-on-blur="false" оставляет
подтверждение только за Enter. Плейсхолдер по умолчанию — подсказка формата (MM/DD/YYYY, HH:MM
буквами локали), потому что порядок частей у локалей разный.
С editable поле показывает значение цифрами, а не Aug 12, 2026, 09:30: набор обязан читать
обратно то, что показан, иначе правка числа прямо в поле оставила бы разбору две группы цифр вместо
трёх и молча откатилась бы. Свой format это правило перебивает — тогда за читаемость отвечает
потребитель.
Маски у поля нет намеренно: она угадывала бы границу между датой и временем и мешала бы стирать.
Разбор работает по цифрам 0–9. Локали с собственными цифрами (ar-EG, fa-IR) набором пока не
поддерживаются — показ у них правильный, а ввод нужно вести европейскими цифрами.
Установка
npm i @feugene/granularity-chronoИмпорт
import { GrDateTimePicker } from '@feugene/granularity-chrono/components/GrDateTimePicker'API
API этого компонента ещё не посчитан: генератор витрины пока обходит только ядро. Пока его нет, справочник — в документации пакета.
Примеры 3
Basic
<script setup lang="ts">
import { ref } from 'vue'
// `GrDateTimePicker` подставляется авто-импортом (`unplugin-vue-components`).
const value = ref<string | null>('2026-08-12T14:30:00')
</script>
<template>
<div class="grid max-w-[360px] gap-4">
<!-- Сетка и колонки в одной панели: смена дня сохраняет время, смена
времени сохраняет день. -->
<GrDateTimePicker
v-model="value"
value-adapter="isoDateTime"
:minute-step="15"
clearable
placeholder="Pick date and time"
aria-label="Meeting start"
/>
<p class="showcase-demo-text text-sm">
<span class="opacity-70">value=</span><code>{{ value ?? '—' }}</code>
</p>
</div>
</template>Confirm
<script setup lang="ts">
import { ref } from 'vue'
// `GrDateTimePicker` подставляется авто-импортом (`unplugin-vue-components`).
const value = ref<string | null>('2026-08-12T09:00:00')
const changes = ref(0)
</script>
<template>
<div class="grid max-w-[360px] gap-4">
<!-- `auto-apply="false"`: панель правит черновик, а модель меняется
кнопкой. Счётчик показывает, что до подтверждения её никто не трогал. -->
<GrDateTimePicker
v-model="value"
:auto-apply="false"
value-adapter="isoDateTime"
:minute-step="30"
aria-label="Appointment"
@change="changes += 1"
/>
<p class="showcase-demo-text text-sm">
<span class="opacity-70">value=</span><code>{{ value ?? '—' }}</code>
<span class="opacity-70"> · changes=</span><code>{{ changes }}</code>
</p>
</div>
</template>Editable
<script setup lang="ts">
import { ref } from 'vue'
// `GrDateTimePicker` подставляется авто-импортом.
/**
* Момент, который быстрее набрать, чем найти кликами.
*
* Локаль здесь не для украшения: она задаёт и порядок частей, и разделители,
* и то, чем разбор считает набранное. Два поля рядом показывают это без слов.
*/
const TODAY = new Date(2026, 7, 12)
const ru = ref<Date | null>(new Date(2026, 7, 12, 9, 30))
const us = ref<Date | null>(new Date(2026, 7, 12, 9, 30))
</script>
<template>
<div class="grid gap-4 justify-items-start">
<div class="grid gap-3 sm:grid-cols-2 w-full">
<GrDateTimePicker
v-model="ru"
editable
:today="TODAY"
locale="ru-RU"
aria-label="Начало, русская локаль"
/>
<GrDateTimePicker
v-model="us"
editable
:today="TODAY"
locale="en-US"
aria-label="Start, US locale"
/>
</div>
<p class="showcase-demo-text text-sm opacity-70">
Наберите дату руками: слева ждут <strong>ДД.ММ.ГГГГ</strong>, справа — <strong>MM/DD/YYYY</strong>.
Порядок частей не зашит в компонент, его знает локаль; разделители разбору безразличны —
точка, слэш и пробел равноценны, потому что считаются группы цифр, а не символы между ними.
</p>
<p class="showcase-demo-text text-sm opacity-70">
Панель идёт за набором: дата набрана целиком — она подсвечена, и сетка перешла на её месяц;
набран час — подсвечен час, дописаны минуты — минуты. Модель при этом не меняется, её меняет
<strong>Enter</strong> или уход фокуса. Набирать вслепую, глядя на панель с прежним значением,
— ровно та ошибка, которую поле и должно было убрать.
</p>
<p class="showcase-demo-text text-sm opacity-70">
Наберите одну дату без времени — время останется прежним: не набранное не меняется. Наберите
мусор и уйдите фокусом — поле вернётся к значению. Поле показывает значение цифрами именно
потому, что их можно править на месте: с «12 авг. 2026 г.» правка числа оставила бы разбору
две группы цифр вместо трёх и молча откатилась бы.
</p>
</div>
</template>