DateTimePicker
让用户通过日历和时间滚轮或时钟表盘选择日期、时间或日期加时间,也可以选择其中任何一种的范围;它显示为对话框,或显示为从文本字段下方展开的表面。
- 类别
- 选择
- 令牌
comp.date-time-picker- 层级
- 组合
- 构成自
- Calendar, Modal layer
- Web
tanrei-date-time-pickerschedule - SwiftUI
tanreiDateTimePickerradio_button_unchecked - Jetpack Compose
TanreiDateTimePickerradio_button_unchecked - Flutter
TanreiDateTimePickerradio_button_unchecked - React Native
DateTimePickerradio_button_unchecked
生成自 docs/status/status.json, specs/date-time-picker.spec.json
日期时间选择器(DateTimePicker)是一个表面,里面容纳日历、时间区域,或两者兼有。mode 是 date、time 或 date-time,range 则为其中任何一种加上开始和结束。它可以作为遮罩之上的对话框打开(modal),也可以作为一个表面,在打开它的文本字段或按钮下方打开(docked)。它的值是字符串:2026-09-17、19:30 或 2026-09-17T19:30,不含秒和时区。
目前仅在 Web 上;其他平台在计划中
Web 组件按本页的描述实现了选择器:范围的两端是由一条短横线连接的两个字段,AM 和 PM 是时间中不显眼的一部分,输入方式标签页只画图标,滚轮接受键入的数字。本页的演示就是这个组件。SwiftUI、Compose、Flutter 和 React Native 尚未实现它。它们的包里仍保留着已停用的日期选择器和时间选择器的代码,本页不对其作说明。
用按钮打开:停靠式的日期,以及模态的时间
选择器是受控的:由你设置 open,它通过 close 请求关闭。它在触发 change 之前先设置自己的 value(或 start 和 end),并且不会向打开它的文本字段写入任何内容。
<!-- 选择时间的模态选择器,可以从任何按钮打开。 -->
<tanrei-button id="alarm-button" variant="outlined">闹钟</tanrei-button>
<tanrei-date-time-picker id="alarm" mode="time" value="07:30" minute-step="5" label="闹钟"></tanrei-date-time-picker>
<!-- 文本字段下方的停靠式选择器,由文本字段的选择器按钮打开。 -->
<tanrei-text-field id="due" label="截止日期" type="date" picker picker-label="选择日期"></tanrei-text-field>
<tanrei-date-time-picker id="due-picker" presentation="docked" anchor="due" label="截止日期"></tanrei-date-time-picker>
<!-- 营业时间:一段时间范围。结束时间等于或早于开始时间时,表示在次日。 -->
<tanrei-date-time-picker id="hours" mode="time" range start="09:00" end="17:30" label="营业时间"></tanrei-date-time-picker>
<script type="module">
import '@tanrei/web/components/date-time-picker';
const alarm = document.querySelector('#alarm');
document.querySelector('#alarm-button').addEventListener('click', () => (alarm.open = true));
alarm.addEventListener('change', (e) => save(e.detail.value)); // "07:35":alarm.value 已经是新的值
// 选择器从不自行关闭。e.detail.reason 为 escape、back、outside、tab、focus-out、cancel、confirm 或 select。
alarm.addEventListener('close', () => (alarm.open = false));
// 文本字段只提出请求;由产品打开选择器,并把值写回去。
const field = document.querySelector('#due');
const due = document.querySelector('#due-picker');
field.addEventListener('pickerrequest', (e) => {
Object.assign(due, { value: e.detail.value, min: e.detail.min, max: e.detail.max, open: true });
});
due.addEventListener('change', (e) => (field.value = e.detail.value));
due.addEventListener('close', () => (due.open = false));
const hours = document.querySelector('#hours');
hours.addEventListener('change', (e) => saveHours(e.detail.start, e.detail.end));
hours.addEventListener('close', () => (hours.open = false));
</script>import { useState } from 'react';
import { DateTimePicker, TextField } from '@tanrei/react';
const [due, setDue] = useState('');
const [open, setOpen] = useState(false);
<TextField
id="due"
label="截止日期"
type="date"
value={due}
picker
pickerLabel="选择日期"
onChange={(e) => setDue(e.currentTarget.value)}
onPickerRequest={() => setOpen(true)}
/>
<DateTimePicker
presentation="docked"
anchor="due"
label="截止日期"
open={open}
value={due}
onChange={(e) => setDue(e.detail.value)}
onClose={() => setOpen(false)}
/>
// 模态的日期加时间,以 15 分钟为步长。
<DateTimePicker
mode="date-time"
minuteStep={15}
label="会议开始"
open={meetingOpen}
value={meeting}
onChange={(e) => setMeeting(e.detail.value)}
onClose={() => setMeetingOpen(false)}
/>这里没有 SwiftUI、Compose、Flutter 和 React Native 的示例,因为这些平台尚未实现选择器。它在这些平台上将使用的名称,见规格中的平台对照表。
| 以前 | 现在 |
|---|---|
| 日期选择器,模态或停靠式 | date 模式的 DateTimePicker,modal 或 docked |
| 带范围的日期选择器 | mode 为 date,加上 range |
| 时间选择器 | time 模式的 DateTimePicker。表盘是一种输入方式;滚轮是另一种,也是默认的方式 |
| 时间选择器的 AM 和 PM 分段 | 时段(上午或下午):小时滚轮和分钟滚轮旁边的第三个短滚轮,或者表盘模式下分钟旁边的选择框 |
| 在选择器里键入日期或时间 | type 为 date、time 或 date-time 的文本字段,它的选择器按钮请求产品打开这个选择器 |
| 嵌在页面里的月份网格 | 日历 |
| 两个选择器的令牌 | 表面、页眉、时间区域和操作使用 comp.date-time-picker.*,网格使用 comp.calendar.* |
这个组件新增的内容:date-time 模式、时间范围(结束时间可以落在次日)、滚轮和 minuteStep。
在 Web 上,以前的两个元素——一个选择日期,一个选择时间——已经不存在。两者都是 <tanrei-date-time-picker>,带 mode="date" 或 mode="time"。停靠式选择器仍然接受 anchor 和 opener,也就是它放在其下方的元素和打开它的元素的 id;选择器也仍然通过 open 打开,并在收到 close 后关闭。表盘是 entry-mode="dial"。
- Material 3 的停靠式和模态日期选择器,是
date模式的 DateTimePicker;它的日期范围选择器是同一个组件加上range。 - Material 3 的时间选择器是
time模式的 DateTimePicker。m3-like 预设只提供表盘,使用 Material 较大的选择框和表盘,并把文本操作放在末尾。 - Material 的全屏范围选择器,以及用来切换到文本输入的铅笔和键盘切换按钮,没有对应物:文本输入由文本字段负责。
- Apple 的滚轮式时间选择器就是滚轮;cupertino 预设只提供滚轮,并带有 Apple 的灰色条带。
- Flutter 的
showDatePicker和showTimePicker对应showTanreiDateTimePicker,SwiftUI 中弹出显示的选择器对应.tanreiDateTimePicker修饰符,Compose 的选择器对话框对应TanreiDateTimePicker。React Native 上是DateTimePicker,它不是同名的社区包。
下面的演示用 Web 的 inline 属性把打开的表面原地画出来,这个属性用于文档和测试。产品里的选择器在页面之上打开。
日期:模态,带页眉和操作;停靠式,选中某一天即提交
时间:默认的滚轮,以及表盘(12 小时制)
在次日结束的时间范围,以及以 15 分钟为步长的 24 小时制
日期加时间,以及日期范围
构成
| 部件 | 说明 |
|---|---|
1 scrim · 可选 | The modal layer's scrim over everything behind a modal picker (MDL-1). It blocks presses, and a press on it dismisses the picker. |
2 container | The raised surface that holds everything else: centred in the window (modal) or below its anchor (docked). |
3 header · 可选 | The title row — the picker's label at the start and, when the picker sets a time, the entry-mode tabs at the end — and, in a modal picker that sets a date, the chosen value in large type below it. |
4 entry-mode-tabs · 可选 | Tanrei Tabs of the secondary variant, each drawing a glyph alone: the keyboard glyph for the wheels at the start and the schedule glyph for the dial at the end. They choose how the time is set, and their words are their accessible names only. Drawn only while the system offers both (comp.date-time-picker.time.entry-modes). |
5 divider · 可选 | The hairline below the header of a modal picker that shows the chosen value. |
6 calendar · 可选 | A Tanrei Calendar, for the date or the range of dates. Present while mode is date or date-time. |
7 time-section · 可选 | Everything that sets a time, top to bottom: the range display across its whole width, then the time display (dial mode) and the wheels or the dial. The period of a 12-hour time is a part of the wheels and of the time display, not a row of its own. Present while mode is time or date-time. |
8 range-display · 可选 | The two ends of a range that has a time: the start's range field, an en dash and the end's range field, in reading order, filling the width of the time section because everything below it sets the end it names. No word says which end is which; the order and the dash do. Present in a range that has a time. |
9 range-field · 可选 | One end of the range in the range display: its time on a container that the person presses to make the wheels or the dial set that end. The one being set is drawn as selected, with the mark the dial mode gives the unit it sets. |
10 range-separator · 可选 | The en dash between the two range fields. |
11 wheels · 可选 | The hour wheel and the minute wheel with the separator between them and, with a 12-hour clock, the period wheel beside them. The chosen value of each stands on that wheel's own selection container (on one band across all of them in a system that joins them), and a press on the hour's or the minute's lets the person type the number. Each wheel is a spin button for assistive technology. |
12 time-display · 可选 | Dial mode: the hour and the minute, each in a selector box that the person presses or focuses to set that unit on the dial, and that the arrow keys adjust; the one whose unit the dial shows is selected. With a 12-hour clock the period selector stands in the same row. It is the row next to the dial, with nothing between them. |
13 period · 可选 | Before or after noon (AM, PM), drawn as the last part of the time — or its first, where the locale writes the period before the hour — and never as tabs: in the wheels mode a short wheel of the two names beside the minute wheel, in the dial mode a narrow selector beside the minute selector that shows the pending period and changes to the other when pressed. It is smaller and quieter than the hour and the minute and never carries the mark of the unit being set. Present with a 12-hour clock. |
14 separator · 可选 | The locale's separator between the hour and the minute (":" in most locales), between the wheels and in the time display. |
15 dial · 可选 | Dial mode: a round clock face with the hours (two rings for a 24-hour clock) or the minutes, which the person presses or drags to set the selected unit. |
16 handle · 可选 | The circle over the chosen value on the dial, joined to the dial's centre by the track; the number under it is drawn in the handle's content color. |
17 error · 可选 | The line that says a range's end is before its start (date-time ranges). |
18 actions · 可选 | Cancel and OK: Tanrei Buttons that the picker places as a full-width Button group places a dismissive and a confirming item, in the variant comp.date-time-picker.actions.variant names. Absent from a docked picker that sets a date only. |
19 focus-ring | Gap-then-ring indicator around the selector, period selector, range field or wheel that has keyboard focus. The calendar, the tabs and the Buttons draw their own. |
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
open | boolean | false | Whether the picker is shown. The product opens it (from a Text field's trailing button, or from any button). Where open is a plain value (web, Compose, React Native) the product closes it by setting open to false when the picker emits close; where it is a binding or a controller (SwiftUI, Flutter) the picker closes itself through it (DTM-5). |
presentation | modal | docked | "modal" | modal: a dialog over a scrim, with a header and Cancel and OK; the choice is committed by OK. docked: a surface below an anchor (the product's field or button) that the rest of the page stays usable around; a date alone is committed by choosing it, and anything with a time by OK. |
mode | date | time | date-time | "date" | What is chosen: a calendar date, a time of day, or a date with a time of day. |
range | boolean | false | Chooses a span, from start to end, instead of one value: a span of dates, of times (opening hours; the end may fall on the next day) or of dates with times (a booking). |
value | string | "" | The chosen value when range is false; empty when none is chosen. An ISO 8601 calendar date in mode date ("2026-09-17"), 24-hour hours and minutes in mode time ("19:30", as an HTML time input holds it), and a local date and time joined by T in mode date-time ("2026-09-17T19:30", as an HTML datetime-local input holds it). No value has seconds or a time zone. |
start | string | "" | The first value of the chosen span when range is true, in the mode's form (as value); empty when none is chosen. |
end | string | "" | The last value of the chosen span when range is true, in the mode's form; empty while only start is chosen. Never before start, except in mode time, where an end at or before start falls on the next day. |
min | string | "" | The earliest value that can be chosen, in the mode's ISO 8601 form — the form the Text field it opens from takes: a calendar date in mode date ("2026-09-17"), a time of day in mode time ("09:00"), and a date and time in mode date-time ("2026-09-17T09:00"), where a calendar date alone bounds the dates and not the times. Empty for no limit. It bounds the calendar by its date and the time by its time (DTM-49). |
max | string | "" | The latest value that can be chosen, in the mode's ISO 8601 form, as min ("2026-09-30", "17:00", "2026-09-30T17:00"); empty for no limit. It bounds the calendar by its date and the time by its time (DTM-49). |
disabledDates | strings | | Dates inside min and max that cannot be chosen, as ISO 8601 calendar dates; with the platform's isDateDisabled predicate, passed to the calendar (CAL-16). |
today | string | "" | The date the calendar draws as today, as an ISO 8601 calendar date; empty uses the device's current date. Set it in tests. |
firstDayOfWeek | locale | sunday | monday | tuesday | wednesday | thursday | friday | saturday | "locale" | The weekday in the calendar's first column, passed to it. |
locale | string | "" | A BCP 47 language tag ("en-US", "ja-JP") for month, weekday and period names, digits, date and time forms, the separator between hours and minutes, the first day of the week and the preferred clock. Empty uses the platform's current locale. |
startView | day | year | "day" | Whether the calendar opens on the days of a month or on the list of years, passed to it. |
showAdjacentDays | boolean | false | Whether the calendar shows the days of the previous and next month in its spare cells, passed to it (CAL-15). |
hourCycle | locale | h12 | h23 | "locale" | h12: hours 1 to 12 with a period (AM, PM). h23: hours 00 to 23. locale takes the locale's preferred clock. Values are 24-hour in every cycle. |
minuteStep | number | 1 | The minutes a person can choose: every minute (1), or every 5, 10, 15 or 30 minutes. The minute wheel lists only those minutes, the dial snaps to them, and a typed minute is rounded down to one. |
entryMode | wheels | dial | "wheels" | How the time is set when the picker opens: on wheels, which also take a typed number, or on a clock dial. The person can switch with the entry-mode tabs while it is open. Ignored when the system offers one mode only (comp.date-time-picker.time.entry-modes). |
unit | hour | minute | "hour" | Dial mode: the unit the dial shows, and the selector that takes focus, when the picker opens. minute suits a product that mostly adjusts minutes. |
layout | auto | vertical | horizontal | "auto" | vertical: the calendar above the time section (and, in the dial mode, the time display above the dial). horizontal: side by side, for a short window or a wide one (in the dial mode, the time display beside the dial, with the range display across both). auto chooses horizontal only when the window is too short for vertical and wide enough for horizontal. |
label | string | "" | Names the picker, in the product's language ("Select date", "Check-in"): the accessible name of its surface and the start of its title row. Required, and this instance's alone: the picker has no words for it and the product's words have none, because what is being chosen differs from one picker to the next. Empty, the title row draws no words, the surface has no name, and it is reported. |
dateLabel | string | "" | What the header shows for a date that is not chosen yet: the date of a single value, and either end of a range, in the product's language ("Date"). The product's: Tanrei has no words for it. Empty reads the product's words. |
startLabel | string | "" | Range: the accessible name of the start's range field and the description of the calendar's start day. It is never drawn, in the product's language ("Start"). The product's: Tanrei has no words for it. Empty reads the product's words. |
endLabel | string | "" | Range: the accessible name of the end's range field and the description of the calendar's end day. It is never drawn, in the product's language ("End"). The product's: Tanrei has no words for it. Empty reads the product's words. |
confirmLabel | string | "" | The label of the button that commits the choice, in the product's language ("OK"). The product's: Tanrei has no words for it. Empty reads the product's words. |
cancelLabel | string | "" | The label of the button that closes the picker without committing, in the product's language ("Cancel"). The product's: Tanrei has no words for it. Empty reads the product's words. |
previousMonthLabel | string | "" | Passed to the calendar, in the product's language ("Previous month"). The product's: Tanrei has no words for it. Empty reads the product's words. |
nextMonthLabel | string | "" | Passed to the calendar, in the product's language ("Next month"). The product's: Tanrei has no words for it. Empty reads the product's words. |
yearViewLabel | string | "" | Passed to the calendar, in the product's language ("Choose a year"). The product's: Tanrei has no words for it. Empty reads the product's words. |
todayLabel | string | "" | Passed to the calendar, in the product's language ("Today"). The product's: Tanrei has no words for it. Empty reads the product's words. With neither, the platform's own word in the locale, where it has one. |
hourLabel | string | "" | The accessible name of the hour wheel and the hour selector, in the product's language ("Hour"). The product's: Tanrei has no words for it. Empty reads the product's words. With neither, the platform's own word in the locale, where it has one. |
minuteLabel | string | "" | The accessible name of the minute wheel and the minute selector, in the product's language ("Minute"). The product's: Tanrei has no words for it. Empty reads the product's words. With neither, the platform's own word in the locale, where it has one. |
wheelsLabel | string | "" | The accessible name of the entry-mode tab that shows the wheels; the tab draws the keyboard glyph alone, in the product's language ("Wheels"). The product's: Tanrei has no words for it. Empty reads the product's words. |
dialLabel | string | "" | The accessible name of the entry-mode tab that shows the dial; the tab draws the schedule glyph alone, in the product's language ("Dial"). The product's: Tanrei has no words for it. Empty reads the product's words. |
entryModeLabel | string | "" | The accessible name of the row of entry-mode tabs, in the product's language ("Time input"). The product's: Tanrei has no words for it. Empty reads the product's words. |
periodLabel | string | "" | The accessible name of the period (AM or PM): the period wheel in the wheels mode and the period selector in the dial mode, in the product's language ("Period"). The product's: Tanrei has no words for it. Empty reads the product's words. With neither, the platform's own word in the locale, where it has one. |
rangeLabel | string | "" | The accessible name of the range display, the group of the two range fields, in the product's language ("Range"). The product's: Tanrei has no words for it. Empty reads the product's words. |
nextDayLabel | string | "" | Mode time with a range: added after the end's time, in its range field and its accessible name, while the end falls on the next day ("6:00 AM next day"), in the product's language. The product's: Tanrei has no words for it. Empty reads the product's words. |
rangeErrorText | string | "" | Mode date-time with a range: the error line shown while the end is before the start, in the product's language ("End must be after start"). The product's: Tanrei has no words for it. Empty reads the product's words. |
事件
| 事件 | 说明 |
|---|---|
change | The person committed a choice that differs from value (or from start and end): by OK, or by choosing a date in a docked picker that sets a date only. Carries the new value, or the new start and end, in the mode's form. Emitted before the close it causes. |
close | The picker asks to be closed. Carries the reason, named escape, back, outside, tab, focus-out, cancel, confirm, select or anchor-hidden (in the platform's casing). Emitted after change when both are emitted. |
状态
行为
以 EARS 形式写成的需求。每个平台的实现都按这些 ID 逐条测试。需求原文取自规格文件,原样以英文呈现。
| ID | 需求 |
|---|---|
DTM-1 | WHEN open becomes true WHILE presentation is modal THE date-time picker SHALL present its container as a modal overlay on its modal layer, in the platform's own modal presentation (named in the platform notes): centred in the window's safe area, at least comp.date-time-picker.modal.container.margin from every edge and from the on-screen keyboard, above everything in its window with the layer's scrim in comp.date-time-picker.modal.scrim.color and comp.date-time-picker.modal.scrim.blur over the whole window behind it (MDL-1); it SHALL make everything outside it inert, keep the content behind it from scrolling and keep focus inside it, as its modal layer does (MDL-2, MDL-3, MDL-4), and draw the container in comp.date-time-picker.modal.container.color with comp.date-time-picker.modal.container.elevation and comp.date-time-picker.modal.container.shape corners eased by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0). |
DTM-2 | WHEN open becomes true WHILE presentation is docked THE date-time picker SHALL present its container in the platform's overlay layer (the web's top layer through the popover API, an overlay SwiftUI draws above its anchor, Compose's Popup, Flutter's Overlay, React Native's overlay layer that TanreiProvider renders), comp.date-time-picker.docked.offset below its anchor with the start edges aligned; WHERE the space below has less room than the surface needs within comp.date-time-picker.docked.viewport-margin of the edge of the visible part of the window, above the on-screen keyboard while one is shown, and the space above has more it SHALL flip above the anchor, it SHALL shift along the anchor to stay within that margin, and SHALL keep following the anchor while it moves. It SHALL draw the container in comp.date-time-picker.docked.container.color with comp.date-time-picker.docked.container.elevation and comp.date-time-picker.docked.container.shape corners eased by sys.shape.corner-smoothing, and SHALL NOT trap focus, make the rest of the screen inert or draw a scrim: it is an operated overlay that is not modal. WHEN the layout direction is right-to-left start and end SHALL mirror. |
DTM-3 | WHEN the date-time picker opens THE date-time picker SHALL move focus into it, because it is an operated overlay in both presentations: to the calendar's active day (CAL-10) while mode is date or date-time, or to its displayed year in the year view; in mode time to the hour wheel in the wheels mode, or to the selector of unit in the dial mode. Focus SHALL move when it opens, not when its motion ends. |
DTM-4 | WHEN the date-time picker closes THE date-time picker SHALL return focus to the element that had it when the picker opened (the anchor or the opener, for a docked picker) or, where that element no longer exists or cannot take focus, to the platform's default for a closed overlay, and SHALL restore the content behind a modal picker to what it was before, as its modal layer does (MDL-2, MDL-5); focus SHALL move when it closes, not when its motion ends. |
DTM-5 | WHEN the user presses Escape or the platform's back (Android's back gesture or button, the iOS accessibility escape gesture), presses the scrim of a modal picker (as its modal layer answers these, MDL-6) or outside a docked picker and its anchor, presses Tab or Shift+Tab out of a docked picker or moves focus out of it, activates Cancel or OK, or completes a choice in a docked picker that sets a date only (DTM-7) THE date-time picker SHALL emit close once with that reason (escape, back, outside, tab, focus-out, cancel, confirm or select) and SHALL be closed: through its binding or controller where open is one (SwiftUI, Flutter), and by the product setting open to false where open is a plain value (web, Compose, React Native). A close for any reason but confirm and select SHALL commit nothing, and Tab or Shift+Tab SHALL then move focus on from the anchor as they would have from it. Whether a press outside a docked picker also reaches the element under it SHALL follow the platform and be stated in its README, as for the menu. |
DTM-6 | WHILE presentation is modal, or mode is time or date-time, THE date-time picker SHALL hold the person's choice as a pending choice that starts, when it opens, as value (or as start and end) — a value the product sets while it is open SHALL NOT change it — SHALL show it in the header, the calendar, the range display, the wheels, the time display, the period and the dial, and SHALL commit it only WHEN OK is activated: it SHALL then emit change once with the pending choice in the mode's form if it differs from the one the picker opened with, and after that emit close with confirm. OK SHALL be disabled while the pending choice is incomplete (no date; no start or no end in a range) or a date-time range's end is before its start (DTM-33). |
DTM-7 | WHILE presentation is docked and mode is date, WHEN the user chooses a day that completes a choice (any available day; the end of a range) THE date-time picker SHALL emit change once with the new choice if it differs from value (or from start and end), and then emit close with select; choosing a range's start SHALL emit nothing and keep the picker open. Such a picker SHALL draw no actions. |
DTM-8 | THE date-time picker SHALL read and write value, start and end in the mode's form: "YYYY-MM-DD" in mode date, 24-hour "HH:MM" in mode time, "YYYY-MM-DDTHH:MM" in mode date-time. WHEN it opens with a time part empty (value, start or end empty, in mode time or date-time) it SHALL start that pending time at the device's current local time; WHEN a pending time's minute, from value or the device, is not a multiple of minuteStep it SHALL round it down to the step, so that the minute wheel and the dial can show it, and OK SHALL then commit the rounded time. In mode date-time a date chosen before its time keeps the pending time, and a date not yet chosen leaves the choice incomplete (DTM-6). |
DTM-9 | THE date-time picker SHALL lay out, from top to bottom, the header (DTM-10), the body and the actions (DTM-34), and between the body and the actions the error line while it is shown (DTM-33); it SHALL inset the body, the error line and the actions by comp.date-time-picker.container.padding-inline on both sides, and the body by comp.date-time-picker.container.padding-block above and below. The body SHALL hold the calendar while mode is date or date-time and the time section while mode is time or date-time: WHILE the vertical layout is used the calendar above the time section, and WHILE the horizontal layout is used side by side, the calendar at the start, comp.date-time-picker.container.gap apart; in mode time the horizontal layout SHALL keep the range display across the whole time section (DTM-12) and SHALL put, below it, the time display in a start column and the dial in an end column, each centred on the other, so that the time display stands beside the dial; in the wheels mode, which has one row below the range display, the horizontal layout SHALL draw the time section as the vertical one does. layout vertical and horizontal SHALL choose that layout; layout auto SHALL choose horizontal only WHEN the window's height less the margins is smaller than the vertical layout needs and its width less the margins can hold the horizontal layout, and otherwise vertical, deciding again when the window changes. |
DTM-10 | THE date-time picker SHALL draw a title row — label at the start in comp.date-time-picker.header.label.typescale and comp.date-time-picker.header.label.color, and the entry-mode tabs (DTM-13) at the end while they are drawn — in a modal picker always, and in a docked one only while the entry-mode tabs are drawn. WHILE presentation is modal and mode is date or date-time it SHALL draw below the title row, comp.date-time-picker.header.gap apart, the pending choice in comp.date-time-picker.header.value.typescale and comp.date-time-picker.header.value.color — a date in the locale's form with the abbreviated weekday, month and day ("Thu, Sep 17", "9月17日(木)"), with the time as the locale writes it in the clock in use in mode date-time ("Thu, Sep 17, 7:30 PM"), and a range as its start and end joined by an en dash ("Sep 10 – Sep 16"), each of the two an isolated run written as the locale writes it and the two in reading order, so that in a right-to-left layout the start stands at the right of the dash and the end at its left, with the year added to each date not in the current year — a date not chosen yet, the single value's or either end's of a range, written as dateLabel in comp.date-time-picker.header.placeholder.color, and never as a word for start or end, which the order and the dash already say; and below the header a divider of comp.date-time-picker.divider.width in comp.date-time-picker.divider.color across the container. THE date-time picker SHALL inset the header by comp.date-time-picker.header.padding-inline-start at the start, comp.date-time-picker.header.padding-inline-end at the end and comp.date-time-picker.header.padding-block above and below; the header SHALL grow with enlarged text, and its value SHALL wrap rather than be cut. THE date-time picker SHALL set the header's value's letter-spacing by the script of its text, as every title is set (PRS-20): no negative letter-spacing WHERE its language is Chinese, Japanese or Korean, and none WHERE its script joins its letters or stacks marks on them. |
DTM-11 | WHILE mode is date or date-time THE date-time picker SHALL show a Tanrei Calendar in single mode, or in range mode while range is true, giving it the pending dates, the dates of min and max (DTM-49), disabledDates and the isDateDisabled predicate, today, firstDayOfWeek, locale, startView, showAdjacentDays, startLabel, endLabel, previousMonthLabel, nextMonthLabel, yearViewLabel and todayLabel, and no label of its own (the picker's surface names it); a choice in the calendar SHALL change the pending dates and nothing else. It SHALL NOT change the calendar's tokens. WHILE range is true and mode is date-time, WHEN a start is chosen in the calendar the start's range field SHALL be selected, and WHEN an end is chosen the end's (DTM-15). |
DTM-12 | WHILE mode is time or date-time THE date-time picker SHALL draw the time section as rows, top to bottom and comp.date-time-picker.container.gap apart: the range display while range is true (DTM-15); the time display in the dial mode (DTM-21); and the wheels (DTM-18) or the dial (DTM-23). The time section SHALL be as wide as its widest row needs, never narrower than comp.date-time-picker.dial.container.size where the space it is given allows, and, WHILE the system offers both entry modes (DTM-13), as wide in the one as in the other — the wider of what the two need — so that switching the mode does not change the picker's width. The range display SHALL span the whole width of the time section in every layout — both columns in the horizontal layout of mode time (DTM-9) — because it is the first branch: which end everything below it shows and sets; every other row SHALL be centred. The time display SHALL be the row next to the dial in every layout — above it in the vertical layout, beside it in the horizontal one — with nothing between the two. The period of a 12-hour time SHALL be a part of the time display and of the wheels (DTM-14) and SHALL have no row of its own: THE date-time picker SHALL draw no row of tabs in the time section, and the entry-mode tabs of the title row (DTM-13) SHALL be its only tabs, Tanrei Tabs of the secondary variant whose variant and tokens the picker SHALL NOT change. |
DTM-13 | WHILE mode is time or date-time and comp.date-time-picker.time.entry-modes is both THE date-time picker SHALL draw the entry-mode tabs at the end of the title row: two tabs that hug their content, each an icon-only tab that draws a glyph of the system's icon set and keeps its word as its accessible name — the keyboard glyph named wheelsLabel first (at the start), because the wheels are where a number is typed (DTM-43), and the schedule glyph named dialLabel second — in a row named entryModeLabel whose panel is the time section, with the tab of the mode shown selected. THE date-time picker SHALL draw no word in these tabs; the glyphs' size, family and mirroring are the Tabs' own, and the icon set marks neither as mirrored. entryMode SHALL choose the mode shown WHEN the picker opens, and WHEN the other tab is selected THE date-time picker SHALL show that mode and keep the pending time, ending a typed entry first (DTM-45). WHILE comp.date-time-picker.time.entry-modes is wheels or dial THE date-time picker SHALL draw no entry-mode tabs and show that mode whatever entryMode says. |
DTM-14 | WHILE the 12-hour clock is used THE date-time picker SHALL draw the period — before or after noon — as a part of the time, and never as tabs, as a switch that spans the time section or as anything that reads as a choice above the time: in the wheels mode as the period wheel (DTM-46) and in the dial mode as the period selector, in the row of the hour and the minute. The period SHALL stand comp.date-time-picker.period.gap after the minute, or, WHERE the locale writes the period before the hour ("午前7:30"), the same gap before the hour. The period selector SHALL be a container at least comp.date-time-picker.period.container.width wide and as tall as the hour and minute selectors, with comp.date-time-picker.selector.container.shape corners eased by sys.shape.corner-smoothing, holding the name of the pending period as the locale writes it ("AM" or "PM"; "午前" or "午後") centred in comp.date-time-picker.period.label.typescale, and growing wider rather than cutting a longer name. It SHALL be drawn from the unselected selector's tokens in every state (comp.date-time-picker.unselected.selector.container.color, comp.date-time-picker.unselected.selector.label.color, comp.date-time-picker.unselected.selector.outline.color and comp.date-time-picker.unselected.selector.outline.width) and SHALL never be drawn from the selected condition: selected marks the unit the dial sets, and the period is not one, so the mark stays with the hour or the minute and the period stays the quiet part of the time. DTM-27 to DTM-32 SHALL hold for the period selector as for a selector of the unselected condition. WHEN the user activates the period selector by pointer, touch, Enter or Space THE date-time picker SHALL make the other period the pending period and keep the hour's number (7 before noon becomes 7 after noon, 19:00), show the new name at once, and SHALL NOT change the unit the dial shows, which selector is selected or where focus is. WHILE the 24-hour clock is used THE date-time picker SHALL draw no period. |
DTM-15 | WHILE range is true and mode is time or date-time THE date-time picker SHALL draw the range display: the start's range field, an en dash and the end's range field, in reading order and comp.date-time-picker.range-field.gap apart, in a group named rangeLabel, as the first row of the time section and across its whole width (DTM-12). Each range field SHALL be a container at least comp.date-time-picker.range-field.container.height tall with comp.date-time-picker.selector.container.shape corners eased by sys.shape.corner-smoothing, padded by comp.date-time-picker.range-field.container.padding-inline at each end, holding its end's pending time as the locale writes a time in the clock in use ("9:00 AM", "17:30"), centred, in comp.date-time-picker.range-field.label.typescale, with nextDayLabel added after the end's time while it falls on the next day (DTM-33); the two SHALL be equally wide and SHALL together fill the width of the time section less the dash and its gaps — never less than the wider one needs — so that the dash stands at the middle of the section and the range display is as wide as everything it governs. THE date-time picker SHALL draw each range field's container, label and outline from the selector tokens of its condition (comp.date-time-picker.unselected.selector.container.color, comp.date-time-picker.unselected.selector.label.color, comp.date-time-picker.unselected.selector.outline.color and comp.date-time-picker.unselected.selector.outline.width, and the same parts of selected): selected for the end the time section sets and unselected for the other, so that the end being set carries the mark the dial mode gives the unit being set. The dash SHALL be drawn in comp.date-time-picker.range-field.label.typescale and comp.date-time-picker.separator.color and be hidden from assistive technology. THE date-time picker SHALL draw no word for start or for end. The start's range field SHALL be selected when the picker opens, and the wheels, the time display, the period and the dial SHALL show and set the pending time of the end whose range field is selected. |
DTM-16 | THE date-time picker SHALL use the clock that hourCycle names: WHILE it is h12 hours SHALL run from 1 to 12 with a period; WHILE it is h23 hours SHALL run from 00 to 23 with no period; WHILE it is locale THE date-time picker SHALL use the locale's preferred clock, taking a locale that counts 0 to 11 as h12 and one that counts 1 to 24 as h23. WHERE the platform reports that the person chose 12- or 24-hour time for the whole device, that choice SHALL win over the locale's while hourCycle is locale; a platform that does not report it uses the locale alone. Values SHALL be 24-hour in every cycle. |
DTM-17 | THE date-time picker SHALL offer as minutes only the multiples of minuteStep from 00 up to 59: every minute for 1, and 00, 05 … 55 for 5, 00 … 50 for 10, 00, 15, 30, 45 for 15, and 00 and 30 for 30. WHEN minuteStep is not one of 1, 5, 10, 15 and 30 THE date-time picker SHALL behave as for 1 and in debug builds report the value. |
DTM-18 | WHILE the wheels mode is shown THE date-time picker SHALL draw the hour wheel, the separator and the minute wheel, always in that order from left to right, comp.date-time-picker.wheel.gap apart: each wheel comp.date-time-picker.wheel.width wide and comp.date-time-picker.wheel.height tall, a column of rows comp.date-time-picker.wheel.row.height tall holding its values in order (the hours of the clock in use, written as the locale writes an hour of it; the minutes of DTM-17 with two digits; both in the locale's digits) centred in comp.date-time-picker.wheel.label.typescale, running on past its ends from the first value again, so that the pending value sits in the middle row. Behind the middle row of each wheel THE date-time picker SHALL draw that wheel's selection container, as wide as the wheel and one row tall, in comp.date-time-picker.wheel.selection.container.color with comp.date-time-picker.wheel.selection.container.shape corners eased by sys.shape.corner-smoothing, so that the hour and the minute each stand on a ground of their own with the separator between the two grounds, as the selectors of the dial mode's time display do (DTM-21); WHILE comp.date-time-picker.wheel.selection.span is joined it SHALL instead draw one such container behind the middle row of both wheels and the separator. The values on a selection container SHALL be drawn in comp.date-time-picker.wheel.selected-label.color and the others in comp.date-time-picker.wheel.label.color. With the 12-hour clock the period wheel stands beside them (DTM-46), with its own selection container or, WHILE the span is joined, on the same band, which then runs behind all three. The separator SHALL be the locale's, level with the middle row, in comp.date-time-picker.wheel.label.typescale and comp.date-time-picker.separator.color. |
DTM-19 | WHEN the user drags or scrolls a wheel THE date-time picker SHALL move its rows with the pointer, and WHEN the drag ends SHALL let a fling carry on and slow down, then settle the nearest available row (DTM-50) on the selection container — over comp.date-time-picker.motion.wheel-duration with comp.date-time-picker.motion.wheel-easing when the wheel is not already moving — and make that row's value the pending hour or minute once it has settled; a drag released after the pointer has not moved for longer than the time after which the platform's velocity tracker takes a pointer as stopped (40 milliseconds in Android's VelocityTracker, Jetpack Compose's VelocityTracker and Flutter's VelocityTracker) or, where the platform names none (the web, SwiftUI, React Native), 40 milliseconds has no velocity, so THE date-time picker SHALL settle the nearest available row without carrying the wheel on; WHEN the user presses a row above or below the selection container THE date-time picker SHALL settle that row on it the same way — or, where that row is unavailable, the available row nearest it — and a press on the middle row that ends without a drag SHALL begin a typed entry (DTM-43). Moving a wheel SHALL NOT change the other wheel or the period, wrapping included (12 to 1 and 23 to 00 for hours, the last minute to 00), except where an hour leaves the time outside min and max, which DTM-49 then moves into them. WHERE motion is reduced a wheel SHALL settle at once and a fling SHALL stop where the drag ends. |
DTM-20 | THE date-time picker SHALL make the hour wheel and the minute wheel each one focusable adjustable control (a spin button) named hourLabel or minuteLabel (the period wheel's name and keys are DTM-47's), whose value is its value as drawn, with the period's name added to the hour's value while the 12-hour clock is used ("7 AM"): Up Arrow SHALL make its value the next available one and Down Arrow the previous one (DTM-50), wrapping from the last value to the first and back without changing the other unit or the period, each moving the rows over comp.date-time-picker.motion.wheel-duration (at once where motion is reduced); WHILE minuteStep is 1 Page Up and Page Down SHALL move the minute by five; Home and End SHALL set the first and the last available value; assistive technology's increment and decrement actions SHALL do what Up Arrow and Down Arrow do. The rows off the selection container SHALL be hidden from assistive technology. WHEN a wheel receives keyboard focus THE date-time picker SHALL show the focus ring around the wheel's selection container (around the wheel's part of it while the containers are joined), without animation; focus gained by pointer or touch SHALL NOT show it. Focus that a typed entry moves to the minute wheel (DTM-44) is keyboard focus, and a wheel that has focus becomes keyboard-focused WHEN a key or typed text works it — a digit, a key that moves it, a key that ends its entry — however focus first reached it. A digit typed while a wheel has focus SHALL begin a typed entry (DTM-43). A wheel SHALL draw no hover or press state: pressing a wheel starts a drag or, on its middle row, a typed entry. |
DTM-21 | WHILE the dial mode is shown THE date-time picker SHALL draw the time display as the hour selector, the separator and the minute selector, comp.date-time-picker.selector.gap apart, always in that order from left to right: each selector a container at least comp.date-time-picker.selector.container.width wide and comp.date-time-picker.selector.container.height tall with comp.date-time-picker.selector.container.shape corners eased by sys.shape.corner-smoothing, in the container color of its condition with an outline of its condition's width and color (comp.date-time-picker.unselected.selector.container.color, comp.date-time-picker.unselected.selector.outline.width and comp.date-time-picker.unselected.selector.outline.color, and so on), holding its value centred in comp.date-time-picker.selector.label.typescale and its condition's label color; the hour SHALL be written as the locale writes an hour of the clock in use ("7" in en-US with h12, "07" with h23) and the minute with two digits, both in the locale's digits; the separator SHALL be the locale's, in comp.date-time-picker.separator.typescale and comp.date-time-picker.separator.color. The selector whose unit the dial shows SHALL be drawn from the selected condition and the other from unselected. With the 12-hour clock the period selector stands in the same row, after the minute or before the hour (DTM-14). |
DTM-22 | THE date-time picker SHALL make each selector a focusable adjustable control (a spin button) named hourLabel or minuteLabel, whose value is its text as drawn with the period's name added to the hour's in the 12-hour clock: Up Arrow and Right Arrow SHALL make its value the next one and Down Arrow and Left Arrow the previous one (the next and previous available value, DTM-50; the minutes of DTM-17 for minutes), wrapping without changing the other unit or the period; WHILE minuteStep is 1 Page Up and Page Down SHALL move the minute by five; Home and End SHALL set the first and the last available value; assistive technology's increment and decrement actions SHALL do what Up Arrow and Down Arrow do. WHEN a selector receives focus or is pressed THE date-time picker SHALL show its unit on the dial and draw it as selected. A digit typed on a keyboard while a selector has focus SHALL be read as a wheel's typed entry is (DTM-44, DTM-45) — the same values, the same rounding to minuteStep, the hour's entry moving focus to the minute selector — with what has been typed shown as the selector's text; the dial mode SHALL NOT raise an on-screen keyboard. |
DTM-23 | WHILE the dial mode is shown THE date-time picker SHALL draw the dial as a circle of diameter comp.date-time-picker.dial.container.size in comp.date-time-picker.dial.container.color holding numbers at equal angles clockwise from the top: for hours with the 12-hour clock 12 at the top and 1 to 11; for hours with the 24-hour clock 00 at the top and 01 to 11 on the outer ring, and 12 at the top and 13 to 23 on an inner ring; for minutes 00 at the top and then every five minutes (05 to 55) while minuteStep is 1 or 5, and every step (10 to 50, 15 to 45, or 30) while it is larger; in the locale's digits, in comp.date-time-picker.dial.label.typescale and comp.date-time-picker.dial.label.color. The outer ring's numbers SHALL be centred on a circle whose radius is half comp.date-time-picker.dial.container.size less comp.date-time-picker.dial.padding less half comp.date-time-picker.dial.handle.size, and the inner ring's on a circle smaller by comp.date-time-picker.dial.handle.size. The dial SHALL run clockwise in every layout direction. |
DTM-24 | THE date-time picker SHALL draw the handle as a circle of diameter comp.date-time-picker.dial.handle.size in comp.date-time-picker.dial.handle.color centred where the pending value lies on the dial (an hour at its number, on the inner ring for 12 to 23 in 24-hour; a minute on the outer ring at six degrees a minute), a line of comp.date-time-picker.dial.track.width in comp.date-time-picker.dial.track.color from the dial's centre to the handle's centre, and a dot of diameter comp.date-time-picker.dial.center.size in comp.date-time-picker.dial.track.color at the centre; the part of a number that lies under the handle SHALL be drawn in comp.date-time-picker.dial.selected-label.color, and WHILE the minute dial shows a minute that is not a multiple of five the handle SHALL hold a dot of diameter comp.date-time-picker.dial.center.size in comp.date-time-picker.dial.selected-label.color at its centre. |
DTM-25 | WHEN the user presses or drags on the dial THE date-time picker SHALL move the handle, without animation, to the available value (DTM-50) whose angle from the dial's centre is nearest the pointer's (on the hour dial of the 24-hour clock, on the ring whose radius is nearer the pointer's distance from the centre; on the minute dial, to the nearest minute of DTM-17) and make it the pending hour or minute as it moves; WHEN a press or drag on the hour dial ends THE date-time picker SHALL show the minute dial, draw the minute selector as selected, and move focus to the minute selector if focus was on the hour selector. The dial SHALL be hidden from assistive technology, whose controls are the selectors (DTM-22). |
DTM-26 | WHEN the dial changes between hours and minutes THE date-time picker SHALL cross-fade its numbers and move the handle to the new unit's value over comp.date-time-picker.motion.dial-duration with comp.date-time-picker.motion.dial-easing, and WHEN the pending hour or minute changes by a key, a typed entry, an action of assistive technology or a range field it SHALL move the handle along the shorter arc over the same duration and easing; WHEN the entry-mode tabs switch between wheels and dial it SHALL cross-fade the two over the same duration and easing; WHERE motion is reduced it SHALL make these changes at once. |
DTM-27 | WHILE a selector or a range field is hovered, keyboard-focused or pressed THE date-time picker SHALL render its container, label, outline and opacity from the selector tokens of its condition in the highest-precedence active state, with precedence pressed over focused over hovered; focus gained by pointer or touch SHALL NOT select the focused state. WHEN these colors change between states or conditions THE date-time picker SHALL animate them over comp.date-time-picker.motion.state-duration with comp.date-time-picker.motion.state-easing, and SHALL change them at once where motion is reduced. |
DTM-28 | WHEN a selector or a range field receives keyboard focus THE date-time picker SHALL show the focus ring around its container without animation; focus gained by pointer or touch SHALL NOT show it. |
DTM-29 | WHEN the date-time picker's selector or range field is pressed by pointer, touch, Enter or Space THE date-time picker SHALL show the pressed state without delay and SHALL keep it visible for at least sys.motion.duration.press-hold, even when the press ends sooner. |
DTM-30 | WHILE pressed THE date-time picker's selector or range field SHALL answer as sys.behavior.pressed-feedback names: overlay applies the pressed tokens to the whole container at once; ripple grows the pressed state layer from the point of contact (from the center for keyboard activation); dim applies the pressed opacity to the whole control and draws no state layer; none draws no answer to the press. Under ripple and dim only the container color stays with the state under the press; label, outline, opacity and shape still come from the pressed tokens. Under none every part stays with the state under the press. The ripple grows over comp.date-time-picker.motion.feedback-duration with comp.date-time-picker.motion.state-easing, fades over comp.date-time-picker.motion.state-duration with comp.date-time-picker.motion.state-easing once the press has ended and press-hold has passed, and appears whole where motion is reduced. |
DTM-31 | THE date-time picker's selector and range field and the wheels' selection containers SHALL ease their corners by sys.shape.corner-smoothing (0 is a quarter circle, 0.6 the iOS continuous corner; a platform with only the OS curve draws it for any amount above 0), and its selector, range field and wheels SHALL show their keyboard focus as sys.behavior.focus-style names (ring or glow); a platform that cannot draw a choice SHALL fall back to the first value and state that in its README. |
DTM-32 | WHERE a selector or a range field would be smaller than the minimum target THE date-time picker SHALL make it at least sys.target.touch in each dimension for touch input and sys.target.pointer for fine pointers, because the selectors, and the range fields, sit side by side and cannot extend their hit areas over each other; a platform that cannot tell the input type SHALL use sys.target.touch. A wheel's rows SHALL each be at least the same target tall. |
DTM-33 | WHILE range is true and mode is time, WHEN the pending end is at or before the pending start THE date-time picker SHALL keep it as a time on the next day, add nextDayLabel after it in the end's range field (DTM-15) and commit it as it is. WHILE range is true, mode is date-time and the pending end is before the pending start THE date-time picker SHALL show rangeErrorText as the error line, in comp.date-time-picker.error.typescale and comp.date-time-picker.error.color, announce it once, politely, WHEN it appears, expose it as the description of the end's range field, and that field as invalid where the platform has that state for a button, and keep OK disabled; WHEN the end is no longer before the start it SHALL remove the line. |
DTM-34 | WHILE presentation is modal, or mode is time or date-time, THE date-time picker SHALL draw Cancel and OK as Tanrei Buttons of the medium size labelled cancelLabel and confirmLabel, in the variant comp.date-time-picker.actions.variant names, placed as a standard Button group places a dismissive and a confirming item (BGR-13 to BGR-19): Cancel at the start and OK at the end of a row, OK on top of a column, with focus and reading order following that order, comp.date-time-picker.actions.gap apart, with comp.date-time-picker.actions.padding-block above and below. WHILE comp.date-time-picker.actions.arrangement is fill they SHALL share the container's inner width equally, and WHILE it is end they SHALL keep their own widths, aligned to the end; either SHALL stack into a column WHEN a label does not fit its place on one line, deciding again when the width or the text size changes. THE date-time picker SHALL NOT change the Buttons' size or tokens; WHEN Cancel is activated it SHALL emit close with cancel. |
DTM-35 | WHEN a modal picker opens THE date-time picker SHALL fade its scrim in with its container (MDL-7), and make its container appear as every modal surface appears: from sys.motion.appear.opacity, sys.motion.appear.scale, sys.motion.appear.distance and sys.motion.appear.blur to whole, grown about its centre and travelling up into place — on both axes WHERE sys.behavior.appearance is unfold — over comp.date-time-picker.modal.motion.open-duration with comp.date-time-picker.modal.motion.open-easing, and WHEN it closes take the container back the same way to where it started while fading the scrim out, over comp.date-time-picker.modal.motion.close-duration with comp.date-time-picker.modal.motion.close-easing, a motion turned round going on from the opacity and the size it has reached; WHEN a modal picker is mounted with open true it SHALL appear without its motion while the document has not yet been first painted, and with it when it is mounted after that. WHEN a docked picker opens it SHALL fade its container in and grow it from the edge that faces the anchor over comp.date-time-picker.docked.motion.open-duration with comp.date-time-picker.docked.motion.open-easing, and WHEN it closes fade it out over comp.date-time-picker.docked.motion.close-duration with comp.date-time-picker.docked.motion.close-easing. WHERE motion is reduced a modal picker SHALL only fade its container in and out, over sys.motion.role.reduced, with no scale, distance or blur, and a docked one SHALL appear and disappear at once, and both SHALL appear and disappear at once on a platform whose reduced-motion setting removes every animation (Android's). |
DTM-36 | WHEN the parts of a modal picker do not fit in the window's height less the margins THE date-time picker SHALL keep the header and the actions in place and scroll the body and the error line between them, and WHEN the header and the actions alone leave no room it SHALL scroll all of its parts together; WHEN a docked picker is taller than the room left beside its anchor it SHALL limit its height to that room and scroll. WHERE the window is narrower than the picker's parts THE date-time picker SHALL be as wide as the window less the margins, let the calendar narrow as CAL-25 says, the entry-mode tabs scroll or truncate as tabs do and the range fields narrow equally, wrapping their text rather than cutting it, and never be wider than the window. Its wheels, selectors, period, range fields and dial numbers SHALL grow with enlarged text rather than clip it. |
DTM-37 | THE date-time picker SHALL expose its surface as a dialog named by label — its modal layer's modal dialog WHILE presentation is modal (MDL-10) — its entry-mode tabs as a tab list with its panel (DTM-13), the period as a spin button of two values (DTM-47), the range display as a group named rangeLabel that holds its two range fields as buttons (DTM-42), each wheel and each selector as a spin button (DTM-20, DTM-22) that stays one while a number is typed into it (DTM-43), the error line as the description of the end's range field while it is shown, and Cancel and OK by their labels; the dial, its numbers and the handle SHALL be hidden from assistive technology. A docked picker SHALL expose, on the element a person presses to open it, that it opens a dialog and whether it is open, where the platform has that property: that element is its anchor unless the platform takes a separate opener, as a Text field anchors the picker and its trailing button opens it. |
DTM-38 | THE date-time picker SHALL take month, weekday and period names, digits, date and time forms, the separator between hours and minutes, the first day of the week and the preferred clock from locale, or from the platform's current locale while locale is empty. Every date SHALL be a Gregorian calendar date and every time a time of day, without a time zone. |
DTM-39 | WHEN the layout direction is right-to-left THE date-time picker SHALL mirror its layout — the title row (the label at the right, the entry-mode tabs at the left, the wheels' tab still first), the columns of the horizontal layout, the side of the time the period stands on (after the minute is at the left of the time, before the hour at its right, DTM-14), the range display (the start's range field at the right of the dash and the end's at its left, each time an isolated run written as the locale writes it, as the header's range is, DTM-10) and the actions — and SHALL NOT mirror the order of the hour, the separator and the minute in the wheels and the time display, which is written left to right as a time is, nor the dial, which runs clockwise, nor the arrow keys of an hour or minute selector (DTM-22), where Right Arrow is the next value in every layout direction, nor those of the period (DTM-47), nor the period wheel, whose two names are one above the other, nor the order in which typed digits are read (DTM-44). |
DTM-40 | WHEN presentation, mode, hourCycle, entryMode, unit, layout, startView or firstDayOfWeek names a value the date-time picker does not define THE date-time picker SHALL behave as its default value and in debug builds report the unknown value; WHEN value, start or end is not empty and not in the mode's form, value is set while range is true or start or end while it is false, a date-time end is before its start, today or an entry of disabledDates is not an ISO 8601 calendar date, or min or max is not in a form the mode takes for it (a calendar date in mode date; a time of day in mode time; a date and time, or a calendar date, in mode date-time) THE date-time picker SHALL ignore it and in debug builds report it; WHEN min is later than max, or no time of minuteStep lies between them (DTM-49), THE date-time picker SHALL ignore both and report it in debug builds. |
DTM-41 | THE date-time picker SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the date-time picker is shown THE date-time picker SHALL draw itself for the new direction at once, without a motion of its own, keeping its open state, the pending choice and its focus, a docked container placed again by the new direction (DTM-2). |
DTM-42 | WHEN the user activates a range field that is not selected by pointer, touch, Enter or Space THE date-time picker SHALL make it the selected one, show its end's pending time in the wheels, the time display, the period and the dial (moving them as DTM-26 says, the dial keeping the unit it shows), end a typed entry first (DTM-45) and keep focus where it is; WHEN the selected range field is activated THE date-time picker SHALL change nothing. Each range field SHALL be a Tab stop of its own, the start's before the end's, and focus alone SHALL NOT select one, so that Tab passes the end's range field on its way to the wheels without changing which end they set. THE date-time picker SHALL expose each range field as a button named startLabel or endLabel followed by its time as drawn ("Start, 9:00 AM"; "End, 6:00 AM next day"), with its selected state (the pressed state of a toggle button where a button has no selected state, as on the web). Selecting a range field SHALL change no pending time and emit nothing. |
DTM-43 | WHILE the wheels mode is shown, WHEN the user presses the middle row of the hour wheel or the minute wheel and releases without dragging past the platform's touch slop (8 points where the platform names none), or types a digit while that wheel has focus, THE date-time picker SHALL begin a typed entry on that wheel: it SHALL give the wheel focus, ask the platform for its number keyboard where an on-screen keyboard is in use, keep the wheel a spin button for assistive technology, and for as long as the entry lasts draw the wheel's selection container, the value on it and its outline from the selected selector's tokens (comp.date-time-picker.selected.selector.container.color, comp.date-time-picker.selected.selector.label.color, comp.date-time-picker.selected.selector.outline.color and comp.date-time-picker.selected.selector.outline.width) — on the wheel's own part of the container while comp.date-time-picker.wheel.selection.span is joined — so that the unit being typed carries the mark the dial mode gives the unit being set, changing between the two looks as DTM-27 says. A press that begins an entry SHALL leave the wheel's value shown, as the text the first digit replaces; the rows above and below SHALL stay, and a press on one of them SHALL still settle it (DTM-19). Focus that reaches a wheel by Tab, or WHEN the picker opens (DTM-3), SHALL NOT begin an entry or raise the on-screen keyboard, and a modal picker SHALL stay clear of the on-screen keyboard as DTM-1 says. |
DTM-44 | WHILE a wheel takes a typed entry THE date-time picker SHALL read digits, ASCII or the locale's, and show what has been typed on the wheel's middle row in place of its value. The first digit SHALL replace the value. A second digit SHALL join the first WHERE the two make a value of the unit — an hour of the clock in use (1 to 12 with the 12-hour clock, 0 to 23 with the 24-hour clock), or a minute from 0 to 59 — and WHERE they do not, which only an hour can meet, the hour's entry SHALL end with the first digit and the second SHALL begin the minute's, so that 1 3 0 types half past one in the 12-hour clock. THE date-time picker SHALL end an entry, keeping what it read (DTM-45), WHEN it has two digits or one digit that no second digit could join (2 to 9 for the 12-hour hour, 3 to 9 for the 24-hour hour, 6 to 9 for the minute); an hour's entry that ends by its digits SHALL move focus to the minute wheel, where the next digit begins an entry, so that 7 3 0 and 0 7 3 0 both type half past seven. WHEN the locale's separator between hours and minutes, a colon, a full stop or a space is typed on the hour wheel THE date-time picker SHALL end the hour's entry and move focus to the minute wheel the same way. Backspace SHALL remove the last digit typed. Every other character SHALL be ignored, text that is pasted SHALL be read as its characters typed in order, and a typed entry SHALL never change the period (DTM-14). |
DTM-45 | WHEN a typed entry ends — by its digits (DTM-44), by Enter or the keyboard's action key, by Tab or focus leaving the wheel, by the on-screen keyboard being dismissed, by a press elsewhere in the picker, or by the wheel being dragged or scrolled — THE date-time picker SHALL make what it read the wheel's pending value WHERE it is a value of the unit, rounding a minute down to a multiple of minuteStep as DTM-8 does (a typed 50 is 45 with a step of 15) and taking an hour of the 12-hour clock in the pending period, and SHALL keep the value the wheel had WHERE nothing was typed, what was typed is not a value of the unit (0 alone for the 12-hour hour), or it is a value DTM-50 makes unavailable. It SHALL then show the pending value on the middle row, moving the rows to it over comp.date-time-picker.motion.wheel-duration with comp.date-time-picker.motion.wheel-easing (at once where motion is reduced), draw the selection container as it was before the entry, and expose the spin button's new value to assistive technology. WHEN Escape is pressed during a typed entry THE date-time picker SHALL end it, keep the value the wheel had and stay open, the press closing nothing (DTM-5); Enter SHALL end the entry without activating OK. WHILE an entry lasts Up Arrow, Down Arrow, Page Up, Page Down, Home and End SHALL first end it, keeping what it read, and then act as DTM-20 says. A typed entry SHALL be checked against nothing else: min and max are answered as DTM-49 and DTM-50 say; a range's end at or before its start is answered as DTM-33 says, whichever way it was set; and the time is committed by OK alone (DTM-6), so that a typed entry emits nothing. |
DTM-46 | WHILE the wheels mode is shown and the 12-hour clock is used THE date-time picker SHALL draw the period wheel beside the hour and minute wheels, at the side DTM-14 names and comp.date-time-picker.period.gap from them: a wheel at least comp.date-time-picker.period.container.width wide and as tall as the others, with rows of comp.date-time-picker.wheel.row.height holding the two names of the period as the locale writes them, the one before noon above the one after, centred in comp.date-time-picker.period.label.typescale, and not running on past its ends, so that the pending period sits in the middle row and the other in the row above or below it. It SHALL draw its selection container behind its middle row as the other wheels do (DTM-18), its own or its part of the joined band, with the name on it in comp.date-time-picker.wheel.selected-label.color and the other in comp.date-time-picker.wheel.label.color. THE period wheel SHALL be dragged, scrolled and settled as a wheel is (DTM-19), stopping at its first and its last name: WHEN it settles on the other name THE date-time picker SHALL make that period the pending period and keep the hour's number, and it SHALL settle back to the pending name from a name DTM-50 makes unavailable; a press on the other name's row SHALL settle it; and a press on the middle row that ends without a drag SHALL settle the other name too, because the period begins no typed entry (DTM-43): a typed letter sets it at once (DTM-47). It SHALL draw no hover or press state, as a wheel draws none (DTM-20). |
DTM-47 | THE date-time picker SHALL make the period — the period wheel or the period selector — one focusable adjustable control (a spin button) named periodLabel, whose value is the name of the pending period as drawn and which has two values, the one before noon first: Up Arrow and Down Arrow, and on the period selector Right Arrow and Left Arrow too, SHALL make the other period the pending period, in every layout direction; Home SHALL set the period before noon and End the one after; Enter and Space SHALL do what Up Arrow does; assistive technology's increment and decrement actions SHALL do what Up Arrow and Down Arrow do. The period SHALL be one Tab stop, where it is drawn: after the minute's, or before the hour's where it stands before the hour. WHEN it receives keyboard focus THE date-time picker SHALL show the focus ring around the period selector (DTM-28) or around the period wheel's selection container (DTM-20); taking focus SHALL change neither the period, the unit the dial shows nor which selector is selected, and WHEN the picker opens focus SHALL still go to the hour (DTM-3), wherever the period stands. A key, a press or a typed letter that asks for a period DTM-50 makes unavailable SHALL change nothing. A change of the period, however it is made, SHALL keep the hour's number and the minute (unless DTM-49 moves the time into min and max), leave the dial's handle where it is, change the value the hour's spin button exposes ("7 PM"), set the end whose range field is selected in a range (DTM-15), and commit nothing by itself (DTM-6). WHEN the person types, while the period has focus, the first character of the name of a period in the locale — compared without case, so A or P in English — THE date-time picker SHALL make that period the pending period, and WHERE the locale's two names begin with the same character (午前 and 午後) typing it SHALL make the other period the pending period, as a browser's own time field and the common time inputs do, so that a person who types a time types its period too; every other character typed while the period has focus, a digit among them, SHALL be ignored, and a typed entry of the hour or the minute still never changes the period (DTM-44). |
DTM-48 | THE date-time picker SHALL have no words of its own: it SHALL take dateLabel, startLabel, endLabel, confirmLabel, cancelLabel, previousMonthLabel, nextMonthLabel, yearViewLabel, todayLabel, hourLabel, minuteLabel, wheelsLabel, dialLabel, entryModeLabel, periodLabel, rangeLabel, nextDayLabel and rangeErrorText from the instance's prop and, WHILE that is empty, from the product's words of the same name; WHILE neither gives hourLabel, minuteLabel, periodLabel or todayLabel it SHALL take that word from the platform's locale data WHERE the platform has the locale's own name for the hour, the minute, the day period or the present day; label SHALL be the instance's alone; and it SHALL take no other word from anywhere. IF a word that is drawn is given by none of them THE date-time picker SHALL draw in its place a mark without words where one says the same — the glyph close for cancelLabel and the glyph check for confirmLabel, each in an icon-only Button of the same variant and size in the same place, and +1 in the locale's digits for nextDayLabel — and otherwise SHALL draw nothing and keep the place's height: the header's place for a date not chosen, the error line of DTM-33, whose other answers stand, and the title's words WHILE label is empty. IF a control or a group has no accessible name THE date-time picker SHALL still draw it and keep it working. In debug builds it SHALL report each missing word once, naming the prop. |
DTM-49 | WHILE mode is time or date-time THE date-time picker SHALL offer as times only those between min and max, both included: in mode time the times of day from min's to max's; in mode date-time, on the date of min the times from its time on, on the date of max the times up to its time, and every time of the days between — a bound that is a calendar date bounding the dates alone; and in a range each end by its own pending date. It SHALL take as the earliest time it offers the first minute of minuteStep at or after min, and as the latest the last one at or before max (a min of 09:07 with a step of 15 offers 09:15 first), so that it never offers a time that the Text field it opens from, which gives it its min and max with its request (TXI-33), refuses (TXI-46). WHEN the pending time of an end falls before the earliest time offered for it THE date-time picker SHALL make it that earliest time, and WHEN it falls after the latest, that latest time — as the picker opens with a value or a device time outside them (DTM-8), as a date chosen in the calendar is the date of a bound, and as an hour or a period that is set leaves the time outside them (7:30 AM under a min of 09:00 set to 9 is 9:00) — so that the pending time is always one that can be chosen and OK never commits a time min and max refuse; this is the only way one unit of the time changes another (DTM-19, DTM-47). WHILE mode is date-time THE date-time picker SHALL give the calendar the dates of min and max, and for min the date of the earliest time offered where minuteStep carries it into the next day. |
DTM-50 | WHILE mode is time or date-time THE date-time picker SHALL treat as unavailable an hour none of whose minutes of minuteStep it offers (DTM-49) — an hour of the 12-hour clock being one of the pending period —, a minute it does not offer in the pending hour, and a period none of whose times it offers. It SHALL keep every unavailable value in its place on the wheels, the period wheel and the dial and never leave one out, so that the values keep the order and the places a person knows them by and a wheel still runs on past its ends; and it SHALL draw an unavailable value at comp.date-time-picker.time.unavailable-opacity of its color. No entry mode SHALL make an unavailable value the pending one: a wheel or the period wheel that a drag, a fling, a scroll or a press would settle on one SHALL settle on the nearest available row instead, the one back toward where it came from on a tie (DTM-19, DTM-46); Up Arrow and Down Arrow, Right Arrow and Left Arrow on a selector, and assistive technology's increment and decrement SHALL make the value the next or the previous available one, passing over the unavailable ones and wrapping as DTM-20 and DTM-22 say; Page Up and Page Down SHALL move by five or, where that value is unavailable, to the available value nearest it on the way; Home and End SHALL set the first and the last available value; a press or a drag on the dial SHALL take the available value nearest the pointer (DTM-25); a typed entry that ends on an unavailable value SHALL keep the value it had (DTM-45); and a key, a press or a typed letter that asks for an unavailable period SHALL change nothing (DTM-47). THE date-time picker SHALL expose as the minimum and the maximum of each spin button — the hour, the minute and the period — the smallest and the largest of its available values, so that assistive technology, which never hears an unavailable value as a spin button's value, hears the range a person can reach; the rows off the selection container and the dial stay hidden from it (DTM-20, DTM-25). |
DTM-51 | WHEN the anchor of an open docked picker is no longer drawn: taken out of the page, given no box (on the web display none on it or on an ancestor), made invisible (visibility hidden) or skipped by its platform's content visibility (on the web content-visibility hidden, or auto while it is off screen), THE date-time picker SHALL emit close once with the reason anchor-hidden, choosing nothing, and SHALL NOT place its container against the anchor while it is not drawn, because a container with nothing beside it no longer says what it belongs to; WHEN it then closes THE date-time picker SHALL return focus as DTM-4 says. WHEN the anchor is drawn again while the picker is still open THE date-time picker SHALL follow it again, and emit close again the next time it is no longer drawn. A modal picker is placed against no anchor, and SHALL NOT close for this. |
DTM-52 | WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on the host, by the attribute or by the ARIA property that reflects it, THE date-time picker SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on its surface, the dialog it is in every presentation — an id reference by the elements it names in the host's tree or a tree around it, a description after its own. WHILE label is not empty it is the surface's name, over a name given so; WHILE label is empty, a name given so is the surface's name, and the title row still draws no words (DTM-48). WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE date-time picker SHALL take it off that element. |
各平台名称对照
对等并不意味着 API 完全相同。同一份契约,由各平台以自己的惯用方式表达。
| 规格 | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| 组件 | tanrei-date-time-picker | tanreiDateTimePicker | TanreiDateTimePicker | TanreiDateTimePicker | DateTimePicker |
open · 属性 | open | isPresented | visible | showTanreiDateTimePicker | visible |
presentation · 属性 | presentation | presentation | presentation | TanreiDateTimePickerAnchor | presentation |
mode · 属性 | mode | mode | mode | mode | mode |
range · 属性 | range | range | range | range | range |
value · 属性 | value | selection | value | value | value |
start · 属性 | start | range | start | start | start |
end · 属性 | end | range | end | end | end |
min · 属性 | min | minDate | min | firstDate | min |
max · 属性 | max | maxDate | max | lastDate | max |
disabledDates · 属性 | disabledDates | disabledDates | disabledDates | disabledDates | disabledDates |
today · 属性 | today | today | today | currentDate | today |
firstDayOfWeek · 属性 | firstDayOfWeek | firstDayOfWeek | firstDayOfWeek | firstDayOfWeek | firstDayOfWeek |
locale · 属性 | locale | locale | locale | locale | locale |
startView · 属性 | startView | startView | startView | startView | startView |
showAdjacentDays · 属性 | showAdjacentDays | showsAdjacentDays | showAdjacentDays | showAdjacentDays | showAdjacentDays |
hourCycle · 属性 | hourCycle | hourCycle | hourCycle | hourCycle | hourCycle |
minuteStep · 属性 | minuteStep | minuteStep | minuteStep | minuteStep | minuteStep |
entryMode · 属性 | entryMode | entryMode | entryMode | entryMode | entryMode |
unit · 属性 | unit | unit | unit | unit | unit |
layout · 属性 | layout | layout | layout | layout | layout |
label · 属性 | label | label | label | label | label |
dateLabel · 属性 | dateLabel | dateLabel | dateLabel | dateLabel | dateLabel |
startLabel · 属性 | startLabel | startLabel | startLabel | startLabel | startLabel |
endLabel · 属性 | endLabel | endLabel | endLabel | endLabel | endLabel |
confirmLabel · 属性 | confirmLabel | confirmLabel | confirmLabel | confirmLabel | confirmLabel |
cancelLabel · 属性 | cancelLabel | cancelLabel | cancelLabel | cancelLabel | cancelLabel |
previousMonthLabel · 属性 | previousMonthLabel | previousMonthLabel | previousMonthLabel | previousMonthLabel | previousMonthLabel |
nextMonthLabel · 属性 | nextMonthLabel | nextMonthLabel | nextMonthLabel | nextMonthLabel | nextMonthLabel |
yearViewLabel · 属性 | yearViewLabel | yearViewLabel | yearViewLabel | yearViewLabel | yearViewLabel |
todayLabel · 属性 | todayLabel | todayLabel | todayLabel | todayLabel | todayLabel |
hourLabel · 属性 | hourLabel | hourLabel | hourLabel | hourLabel | hourLabel |
minuteLabel · 属性 | minuteLabel | minuteLabel | minuteLabel | minuteLabel | minuteLabel |
wheelsLabel · 属性 | wheelsLabel | wheelsLabel | wheelsLabel | wheelsLabel | wheelsLabel |
dialLabel · 属性 | dialLabel | dialLabel | dialLabel | dialLabel | dialLabel |
entryModeLabel · 属性 | entryModeLabel | entryModeLabel | entryModeLabel | entryModeLabel | entryModeLabel |
periodLabel · 属性 | periodLabel | periodLabel | periodLabel | periodLabel | periodLabel |
rangeLabel · 属性 | rangeLabel | rangeLabel | rangeLabel | rangeLabel | rangeLabel |
nextDayLabel · 属性 | nextDayLabel | nextDayLabel | nextDayLabel | nextDayLabel | nextDayLabel |
rangeErrorText · 属性 | rangeErrorText | rangeErrorText | rangeErrorText | rangeErrorText | rangeErrorText |
change · 事件 | change | selection | onChange | onChanged | onChange |
close · 事件 | close | onClose | onClose | onClose | onClose |
| 备注 | Attributes are kebab-case (disabled-dates is a space-separated list of ISO dates, first-day-of-week, start-view, show-adjacent-days, hour-cycle, minute-step, entry-mode, wheels-label, …); isDateDisabled is a property only. entryMode is not HTML's global inputmode. value, start and end are the strings of <input type=date>, type=time and type=datetime-local, set before change fires; close is a CustomEvent whose detail.reason is the reason. A modal picker is a native <dialog> opened with showModal() in the shadow root, with ::backdrop as the scrim; its cancel becomes close with escape when an Escape key caused it, and with back otherwise. A docked picker takes anchor and opener (element ids), sets aria-haspopup="dialog", aria-controls and aria-expanded on the opener, and is a manual popover in the top layer with its own light dismiss so that close carries its reason. Inside the shadow root: a <tanrei-calendar>; one <tanrei-tabs variant="secondary"> row, the entry-mode tabs, which hugs and whose two <tanrei-tab>s are label-hidden with icon="keyboard" and icon="schedule", and whose panel is the time section; the period as an element with role spinbutton (aria-valuemin="1", aria-valuemax="2", aria-valuenow and the period's name as aria-valuetext), part="period" — a third wheel of two rows that does not loop in the wheels mode, a button-like cell in the time display in the dial mode — placed before the hour when formatToParts gives the dayPeriod part before the hour part; the range display as a role="group" with two <button part="range-field" aria-pressed> and an aria-hidden dash, in a grid with two equal columns that fills the time section's inline size (and both columns of the horizontal layout of mode time); wheels and selectors as elements with role spinbutton, a wheel's middle row being an <input inputmode="numeric" role="spinbutton"> that is read-only until a typed entry begins (a tap that ends without a drag, or a digit key), so that a drag raises no keyboard; the dial drawn with pointer events and aria-hidden; Cancel and OK as <tanrei-button>s placed by the button group's placement code, with the variant read from the resolved comp.date-time-picker.actions.variant. The entry modes offered are read from the resolved comp.date-time-picker.time.entry-modes once per system. Locale data from Intl.DateTimeFormat (formatToParts with hour12 for the period names and the separator; resolvedOptions().hourCycle for the preferred clock); without locale it reads the nearest lang attribute, then navigator.language. It uses the package's locale helpers, overlay placement and dial (clock.ts). A value outside min and max (DTM-50) is a wheel row or a dial number with data-unavailable, faded by opacity; a spin button's aria-valuemin and aria-valuemax are its first and last available values. The inline attribute, for tests, draws the open surface in place (DTM-1's verify). Words: the element has no words of its own. A words attribute (confirm-label, cancel-label, hour-label and the others) left empty read the product's words, set once with setWords() from @tanrei/web; the element draws again when they change. Where neither the instance nor the product gives them, the hour's, the minute's and the period's names are Intl.DisplayNames(locale, { type: 'dateTimeField' }) (hour, minute, dayPeriod) and the present day's word is Intl.RelativeTimeFormat's for day 0. | Planned. A view modifier, as .sheet and .popover are: .tanreiDateTimePicker(isPresented:, selection: Binding<DateComponents?>, mode:, presentation:, …) for one value and .tanreiDateTimePicker(isPresented:, range: Binding<TanreiDateTimeRange>, mode:, …) for a span, where TanreiDateTimeRange holds start and end as DateComponents?; the overload is range, and mode chooses which components are read and written (year, month and day; hour and minute; or both), so no time zone enters. Writing the binding is change; the picker writes false to isPresented itself and calls onClose with the reason. The words are fields of a TanreiDateTimePickerLabels passed as labels:, whose field names are the spec's. locale defaults to the \.locale environment; the preferred clock comes from DateFormatter.dateFormat(fromTemplate: "j", …). Modal: .fullScreenCover with a clear background and the system transition off, as the dialog. Docked: drawn in its anchor's overlay and placed by Tanrei. The calendar is TanreiCalendar, the entry-mode tabs TanreiTabs (each with a glyph and labelStyle: .iconOnly), the period one view with .accessibilityAdjustableAction and .accessibilityValue (a third wheel in the wheels mode, a pressable cell in the dial mode), the range fields two Buttons with the .isSelected trait in an accessibility container, a typed entry a hidden TextField with .keyboardType(.numberPad) on iOS and .onKeyPress for digits elsewhere, the actions TanreiButtons; the wheels are Tanrei's own (a scroll view with .scrollTargetBehavior(.viewAligned) per wheel) with .accessibilityAdjustableAction, not the system's wheel picker, whose look no token reaches. Snapshot harness: TanreiDateTimePickerSurface drawn in place on the fixture's stage. The product's words are read from the \.tanreiWords environment value. | Planned. TanreiDateTimePicker(visible, onClose, presentation, mode, range, value, start, end, onChange, min, max, disabledDates, isDateDisabled, today, firstDayOfWeek, locale, startView, showAdjacentDays, hourCycle, minuteStep, entryMode, unit, layout, labels). Values are TanreiDateTime(date: TanreiDate?, time: TanreiTime?), of which mode says which half is read (API 23 has no java.time); onChange receives a TanreiDateTimeSelection(value, start, end); the caller keeps the state (hoisting) and sets visible to false from onClose, which carries the reason. The words, label among them, are fields of a TanreiDateTimePickerLabels. Modal: a Dialog window with the platform width and dim off, as TanreiDialog. Docked: a Popup inside the anchor's Box, as TanreiMenu. The calendar is TanreiCalendar, the entry-mode tabs TanreiTabs (icon-only), the period one node with progressBarRangeInfo over two steps, stateDescription for its name and setProgress (a third wheel in the wheels mode, a clickable cell in the dial mode), the range fields two boxes with Role.Button and selected semantics, a typed entry a BasicTextField with KeyboardType.Number behind the wheel's middle row and onPreviewKeyEvent for digits, the actions TanreiButtons; each wheel is a LazyColumn with snapping fling and progressBarRangeInfo / setProgress semantics; the dial is pointerInput with clearAndSetSemantics {}. Snapshot harness: TanreiDateTimePickerContent drawn in place on the fixture's stage. The product's words are read from LocalTanreiWords. | Planned. Flutter's idiom, as its own date and time pickers: a modal picker is showTanreiDateTimePicker(context:, mode:, range:, value:, start:, end:, firstDate:, lastDate:, …), which pushes a modal route that draws the scrim as its barrier and returns a Future<TanreiDateTimeSelection?>, completed with the committed choice on OK and with null otherwise; onChanged and onClose are also called, in that order. A docked picker is TanreiDateTimePickerAnchor(controller:, builder:, …), shaped like the menu's anchor and shown in the Overlay. firstDate, lastDate and currentDate keep Flutter's names. Values are DateTimes of which only the parts mode names are read. Month, weekday and period names, date forms, the separator and the preferred clock come from TanreiDateLocalizations (English built in, no intl dependency), and MediaQuery.alwaysUse24HourFormatOf wins for hourCycle locale. The calendar is TanreiCalendar, the entry-mode tabs TanreiTabBar (icon-only), the period one widget under Semantics with value, increasedValue, decreasedValue, onIncrease and onDecrease (a third wheel that does not loop in the wheels mode, a pressable cell in the dial mode), the range fields two widgets under Semantics(button: true, selected:), a typed entry an EditableText with TextInputType.number behind the wheel's middle row and a Focus onKeyEvent for digits, the actions TanreiButtons; each wheel is a ListWheelScrollView.useDelegate with a looping child delegate and a FixedExtentScrollPhysics, under Semantics with increasedValue, decreasedValue, onIncrease and onDecrease. Snapshot harness: a golden of the whole stage after showTanreiDateTimePicker (modal), or of TanreiDateTimePicker drawn in place (docked). The product's words are read from the TanreiWords inherited widget, which the app fills from its own localizations. | Planned. Controlled: visible, onClose({ reason }) and onChange({ value, start, end }), the values being the mode's ISO strings, never Date objects; the caller moves them and sets visible to false. A product that also uses the community package of the same name imports this one under another name. A modal picker is presented in a transparent Modal with animationType="none", statusBarTranslucent and navigationBarTranslucent, as the dialog; a docked picker takes anchorRef and is drawn on the overlay layer that TanreiProvider renders, placed by measuring the anchor, with Android's back (BackHandler) as close. The calendar is the package's Calendar, the entry-mode tabs its Tabs (icon-only), the period one view with the adjustable role, accessibilityValue.text and the increment and decrement actions (a third wheel in the wheels mode, a Pressable cell in the dial mode), the range fields two Pressables with the button role and accessibilityState.selected, a typed entry a TextInput with keyboardType="number-pad" behind the wheel's middle row, the actions its Buttons; each wheel is a FlatList with snapToInterval and the adjustable role with the increment and decrement actions; the dial uses the responder system and is hidden from accessibility. Locale data from Hermes's Intl.DateTimeFormat. Snapshot harness: DateTimePickerSurface drawn in place on the fixture's stage. The product's words are read from the TanreiWordsProvider context. |
令牌
| 令牌 | 引用 | 解析值(浅色) |
|---|---|---|
--tanrei-comp-date-time-picker-actions-arrangement | — | 0 |
--tanrei-comp-date-time-picker-actions-gap | sys.space.space200 | 16px |
--tanrei-comp-date-time-picker-actions-padding-block | sys.space.space150 | 12px |
--tanrei-comp-date-time-picker-actions-variant | — | 1 |
--tanrei-comp-date-time-picker-container-gap | sys.space.space200 | 16px |
--tanrei-comp-date-time-picker-container-padding-block | sys.space.space100 | 8px |
--tanrei-comp-date-time-picker-container-padding-inline | sys.space.space150 | 12px |
--tanrei-comp-date-time-picker-dial-center-size | — | 8px |
--tanrei-comp-date-time-picker-dial-container-color | sys.color.surface-dim | |
--tanrei-comp-date-time-picker-dial-container-size | — | 256px |
--tanrei-comp-date-time-picker-dial-handle-color | sys.color.primary | |
--tanrei-comp-date-time-picker-dial-handle-size | — | 48px |
--tanrei-comp-date-time-picker-dial-label-color | sys.color.on-surface | |
--tanrei-comp-date-time-picker-dial-padding | sys.space.space100 | 8px |
--tanrei-comp-date-time-picker-dial-selected-label-color | sys.color.on-primary | |
--tanrei-comp-date-time-picker-dial-track-color | sys.color.primary | |
--tanrei-comp-date-time-picker-dial-track-width | sys.border.thick | 2px |
--tanrei-comp-date-time-picker-divider-color | sys.color.outline-variant | |
--tanrei-comp-date-time-picker-divider-width | sys.border.hairline | 1px |
--tanrei-comp-date-time-picker-docked-container-color | sys.color.surface-bright | |
--tanrei-comp-date-time-picker-docked-container-elevation | sys.elevation.level2 | 0px 0px 0px 1px rgb(0 0 0 / 0.08), 0px 1px 2px 0px rgb(0 0 0 / 0.04) |
--tanrei-comp-date-time-picker-docked-container-shape | sys.shape.corner.medium | 8px |
--tanrei-comp-date-time-picker-docked-motion-close-duration | sys.motion.role.appear.anchored.exit | 250ms |
--tanrei-comp-date-time-picker-docked-motion-close-easing | sys.motion.easing.exit | cubic-bezier(0.3, 0, 1, 1) |
--tanrei-comp-date-time-picker-docked-motion-open-duration | sys.motion.role.appear.anchored.enter | 300ms |
--tanrei-comp-date-time-picker-docked-motion-open-easing | sys.motion.easing.enter | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-date-time-picker-docked-offset | sys.space.space50 | 4px |
--tanrei-comp-date-time-picker-docked-viewport-margin | sys.space.space100 | 8px |
--tanrei-comp-date-time-picker-error-color | sys.color.error | |
--tanrei-comp-date-time-picker-focused-opacity | — | 1 |
--tanrei-comp-date-time-picker-header-gap | sys.space.space50 | 4px |
--tanrei-comp-date-time-picker-header-label-color | sys.color.on-surface-variant | |
--tanrei-comp-date-time-picker-header-padding-block | sys.space.space200 | 16px |
--tanrei-comp-date-time-picker-header-padding-inline-end | sys.space.space150 | 12px |
--tanrei-comp-date-time-picker-header-padding-inline-start | sys.space.space300 | 24px |
--tanrei-comp-date-time-picker-header-placeholder-color | sys.color.on-surface-variant | |
--tanrei-comp-date-time-picker-header-value-color | sys.color.on-surface | |
--tanrei-comp-date-time-picker-hovered-opacity | — | 1 |
--tanrei-comp-date-time-picker-modal-container-color | sys.color.surface-bright | |
--tanrei-comp-date-time-picker-modal-container-elevation | sys.elevation.level3 | 0px 0px 0px 1px rgb(0 0 0 / 0.08), 0px 1px 1px 0px rgb(0 0 0 / 0.04), 0px 4px 8px -4px rgb(0 0 0 / 0.04), 0px 16px 24px -8px rgb(0 0 0 / 0.06) |
--tanrei-comp-date-time-picker-modal-container-margin | sys.space.space200 | 16px |
--tanrei-comp-date-time-picker-modal-container-shape | sys.shape.corner.large | 12px |
--tanrei-comp-date-time-picker-modal-motion-close-duration | comp.modal-layer.motion.exit-duration | 300ms |
--tanrei-comp-date-time-picker-modal-motion-close-easing | comp.modal-layer.motion.exit-easing | cubic-bezier(0.3, 0, 1, 1) |
--tanrei-comp-date-time-picker-modal-motion-open-duration | comp.modal-layer.motion.enter-duration | 350ms |
--tanrei-comp-date-time-picker-modal-motion-open-easing | comp.modal-layer.motion.enter-easing | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-date-time-picker-modal-scrim-blur | comp.modal-layer.scrim.blur | 0px |
--tanrei-comp-date-time-picker-modal-scrim-color | comp.modal-layer.scrim.color | |
--tanrei-comp-date-time-picker-motion-dial-duration | sys.motion.role.selection.travel | 250ms |
--tanrei-comp-date-time-picker-motion-dial-easing | sys.motion.easing.spatial | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-date-time-picker-motion-feedback-duration | sys.motion.role.feedback | 450ms |
--tanrei-comp-date-time-picker-motion-state-duration | sys.motion.role.state.compact | 200ms |
--tanrei-comp-date-time-picker-motion-state-easing | sys.motion.easing.state | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-date-time-picker-motion-wheel-duration | sys.motion.duration.medium1 | 250ms |
--tanrei-comp-date-time-picker-motion-wheel-easing | sys.motion.easing.standard-decelerate | cubic-bezier(0, 0, 0, 1) |
--tanrei-comp-date-time-picker-period-container-width | — | 56px |
--tanrei-comp-date-time-picker-period-gap | sys.space.space100 | 8px |
--tanrei-comp-date-time-picker-pressed-opacity | — | 1 |
--tanrei-comp-date-time-picker-range-field-container-height | — | 48px |
--tanrei-comp-date-time-picker-range-field-container-padding-inline | sys.space.space200 | 16px |
--tanrei-comp-date-time-picker-range-field-gap | sys.space.space100 | 8px |
--tanrei-comp-date-time-picker-selected-focused-selector-container-color | — | |
--tanrei-comp-date-time-picker-selected-focused-selector-label-color | — | |
--tanrei-comp-date-time-picker-selected-focused-selector-outline-color | — | |
--tanrei-comp-date-time-picker-selected-focused-selector-outline-width | — | 2px |
--tanrei-comp-date-time-picker-selected-focused-selector-state-layer-color | — | |
--tanrei-comp-date-time-picker-selected-hovered-selector-container-color | — | |
--tanrei-comp-date-time-picker-selected-hovered-selector-label-color | — | |
--tanrei-comp-date-time-picker-selected-hovered-selector-outline-color | — | |
--tanrei-comp-date-time-picker-selected-hovered-selector-outline-width | — | 2px |
--tanrei-comp-date-time-picker-selected-hovered-selector-state-layer-color | — | |
--tanrei-comp-date-time-picker-selected-pressed-selector-container-color | — | |
--tanrei-comp-date-time-picker-selected-pressed-selector-label-color | — | |
--tanrei-comp-date-time-picker-selected-pressed-selector-outline-color | — | |
--tanrei-comp-date-time-picker-selected-pressed-selector-outline-width | — | 2px |
--tanrei-comp-date-time-picker-selected-pressed-selector-state-layer-color | — | |
--tanrei-comp-date-time-picker-selected-selector-container-color | sys.color.surface-dim | |
--tanrei-comp-date-time-picker-selected-selector-label-color | sys.color.on-surface | |
--tanrei-comp-date-time-picker-selected-selector-outline-color | sys.color.primary | |
--tanrei-comp-date-time-picker-selected-selector-outline-width | sys.border.thick | 2px |
--tanrei-comp-date-time-picker-selected-selector-state-layer-color | comp.date-time-picker.selected.selector.label.color | |
--tanrei-comp-date-time-picker-selector-container-height | — | 80px |
--tanrei-comp-date-time-picker-selector-container-shape | sys.shape.corner.medium | 8px |
--tanrei-comp-date-time-picker-selector-container-width | — | 96px |
--tanrei-comp-date-time-picker-selector-gap | sys.space.space50 | 4px |
--tanrei-comp-date-time-picker-separator-color | sys.color.on-surface | |
--tanrei-comp-date-time-picker-time-entry-modes | — | 0 |
--tanrei-comp-date-time-picker-time-unavailable-opacity | sys.state.disabled-content-opacity | 0.38 |
--tanrei-comp-date-time-picker-unselected-focused-selector-container-color | — | |
--tanrei-comp-date-time-picker-unselected-focused-selector-label-color | — | |
--tanrei-comp-date-time-picker-unselected-focused-selector-outline-color | — | |
--tanrei-comp-date-time-picker-unselected-focused-selector-outline-width | — | 1px |
--tanrei-comp-date-time-picker-unselected-focused-selector-state-layer-color | — | |
--tanrei-comp-date-time-picker-unselected-hovered-selector-container-color | — | |
--tanrei-comp-date-time-picker-unselected-hovered-selector-label-color | — | |
--tanrei-comp-date-time-picker-unselected-hovered-selector-outline-color | — | |
--tanrei-comp-date-time-picker-unselected-hovered-selector-outline-width | — | 1px |
--tanrei-comp-date-time-picker-unselected-hovered-selector-state-layer-color | — | |
--tanrei-comp-date-time-picker-unselected-pressed-selector-container-color | — | |
--tanrei-comp-date-time-picker-unselected-pressed-selector-label-color | — | |
--tanrei-comp-date-time-picker-unselected-pressed-selector-outline-color | — | |
--tanrei-comp-date-time-picker-unselected-pressed-selector-outline-width | — | 1px |
--tanrei-comp-date-time-picker-unselected-pressed-selector-state-layer-color | — | |
--tanrei-comp-date-time-picker-unselected-selector-container-color | sys.color.surface-dim | |
--tanrei-comp-date-time-picker-unselected-selector-label-color | sys.color.on-surface | |
--tanrei-comp-date-time-picker-unselected-selector-outline-color | — | |
--tanrei-comp-date-time-picker-unselected-selector-outline-width | sys.border.hairline | 1px |
--tanrei-comp-date-time-picker-unselected-selector-state-layer-color | comp.date-time-picker.unselected.selector.label.color | |
--tanrei-comp-date-time-picker-wheel-gap | sys.space.space50 | 4px |
--tanrei-comp-date-time-picker-wheel-height | — | 240px |
--tanrei-comp-date-time-picker-wheel-label-color | sys.color.on-surface-variant | |
--tanrei-comp-date-time-picker-wheel-row-height | — | 48px |
--tanrei-comp-date-time-picker-wheel-selected-label-color | sys.color.on-surface | |
--tanrei-comp-date-time-picker-wheel-selection-container-color | sys.color.surface-dim | |
--tanrei-comp-date-time-picker-wheel-selection-container-shape | sys.shape.corner.medium | 8px |
--tanrei-comp-date-time-picker-wheel-selection-span | — | 0 |
--tanrei-comp-date-time-picker-wheel-width | — | 80px |
--tanrei-comp-date-time-picker-dial-label-typescale | sys.typescale.body-large | 400 16px/1.625 |
--tanrei-comp-date-time-picker-error-typescale | sys.typescale.body-small | 400 13px/1.5385 |
--tanrei-comp-date-time-picker-header-label-typescale | sys.typescale.label | 500 14px/1.4286 |
--tanrei-comp-date-time-picker-header-value-typescale | sys.typescale.heading-2 | 500 24px/1.3333 |
--tanrei-comp-date-time-picker-period-label-typescale | sys.typescale.heading-5 | 500 16px/1.5 |
--tanrei-comp-date-time-picker-range-field-label-typescale | sys.typescale.heading-5 | 500 16px/1.5 |
--tanrei-comp-date-time-picker-selector-label-typescale | sys.typescale.display | 450 48px/1.0833 |
--tanrei-comp-date-time-picker-separator-typescale | sys.typescale.display | 450 48px/1.0833 |
--tanrei-comp-date-time-picker-wheel-label-typescale | sys.typescale.heading-3 | 500 20px/1.4 |
测试样例
作为基准的渲染结果。所有平台都以相同的 ID 为每个样例截取快照,以便相互比较。
modal-date
open: true mode: date value: 2026-09-17 today: 2026-09-24 locale: en-US label: Select date dateLabel: Date confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today 单独绘制在 480 × 720 的窗口中modal-date-empty
open: true mode: date today: 2026-09-24 locale: en-US label: Select date dateLabel: Date confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today 单独绘制在 480 × 720 的窗口中modal-date-range
open: true mode: date range: true start: 2026-09-10 end: 2026-09-16 today: 2026-09-24 locale: en-US label: Select dates dateLabel: Date startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today 单独绘制在 480 × 720 的窗口中modal-date-range-start
open: true mode: date range: true start: 2026-09-10 today: 2026-09-24 locale: en-US label: Select dates dateLabel: Date startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today 单独绘制在 480 × 720 的窗口中modal-date-year
open: true mode: date value: 2026-09-17 today: 2027-01-15 locale: en-US startView: year label: Select date dateLabel: Date confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today 单独绘制在 480 × 720 的窗口中modal-time
open: true mode: time value: 07:30 locale: en-US hourCycle: h12 label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-24h
open: true mode: time value: 19:30 locale: en-US hourCycle: h23 label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-ja
open: true mode: time value: 07:30 locale: ja-JP hourCycle: h12 label: 時刻を選択 confirmLabel: OK cancelLabel: キャンセル hourLabel: 時 minuteLabel: 分 wheelsLabel: ホイール dialLabel: ダイヤル entryModeLabel: 時刻の入力方法 periodLabel: 午前/午後 单独绘制在 480 × 720 的窗口中modal-time-step
open: true mode: time value: 07:45 locale: en-US hourCycle: h12 minuteStep: 15 label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-bounded
open: true mode: time value: 09:30 min: 09:15 max: 17:45 locale: en-US hourCycle: h23 minuteStep: 15 label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-dial
open: true mode: time value: 07:30 locale: en-US hourCycle: h12 entryMode: dial label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-dial-minute
open: true mode: time value: 19:45 locale: en-US hourCycle: h12 entryMode: dial unit: minute label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-dial-minute-between
open: true mode: time value: 07:32 locale: en-US hourCycle: h12 entryMode: dial unit: minute label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-dial-step
open: true mode: time value: 07:20 locale: en-US hourCycle: h12 minuteStep: 10 entryMode: dial unit: minute label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-dial-24h
open: true mode: time value: 19:30 locale: en-US hourCycle: h23 entryMode: dial label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-dial-bounded
open: true mode: time value: 09:30 min: 09:15 max: 17:45 locale: en-US hourCycle: h12 minuteStep: 15 entryMode: dial label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中modal-time-dial-ja
open: true mode: time value: 19:30 locale: ja-JP hourCycle: h12 entryMode: dial label: 時刻を選択 confirmLabel: OK cancelLabel: キャンセル hourLabel: 時 minuteLabel: 分 wheelsLabel: ホイール dialLabel: ダイヤル entryModeLabel: 時刻の入力方法 periodLabel: 午前/午後 单独绘制在 480 × 720 的窗口中modal-time-dial-rtl
open: true mode: time value: 19:30 locale: en-US hourCycle: h12 entryMode: dial label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period direction: rtl 单独绘制在 480 × 720 的窗口中modal-time-range
open: true mode: time range: true start: 09:00 end: 17:30 locale: en-US hourCycle: h12 label: Select times startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period rangeLabel: Range nextDayLabel: next day 单独绘制在 480 × 720 的窗口中modal-time-range-overnight
open: true mode: time range: true start: 22:00 end: 06:00 locale: en-US hourCycle: h23 label: Select times startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period rangeLabel: Range nextDayLabel: next day 单独绘制在 480 × 720 的窗口中modal-time-range-dial
open: true mode: time range: true start: 09:00 end: 17:30 locale: en-US hourCycle: h12 entryMode: dial label: Select times startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period rangeLabel: Range nextDayLabel: next day 单独绘制在 480 × 720 的窗口中modal-time-range-dial-horizontal
open: true mode: time range: true start: 09:00 end: 17:30 locale: en-US hourCycle: h12 entryMode: dial layout: horizontal label: Select times startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period rangeLabel: Range nextDayLabel: next day 单独绘制在 800 × 640 的窗口中modal-time-range-rtl
open: true mode: time range: true start: 09:00 end: 17:30 locale: en-US hourCycle: h12 label: Select times startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period rangeLabel: Range nextDayLabel: next day direction: rtl 单独绘制在 480 × 720 的窗口中modal-time-horizontal
open: true mode: time value: 07:30 locale: en-US hourCycle: h12 entryMode: dial layout: horizontal label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 800 × 640 的窗口中modal-time-wheels-horizontal
open: true mode: time value: 07:30 locale: en-US hourCycle: h12 layout: horizontal label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 800 × 640 的窗口中modal-date-time
open: true mode: date-time value: 2026-09-17T19:30 today: 2026-09-24 locale: en-US hourCycle: h12 layout: horizontal label: Select date and time dateLabel: Date confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 800 × 640 的窗口中modal-date-time-range
open: true mode: date-time range: true start: 2026-09-10T09:00 end: 2026-09-16T17:00 today: 2026-09-24 locale: en-US hourCycle: h12 layout: horizontal label: Select dates and times dateLabel: Date startLabel: Start endLabel: End confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period rangeLabel: Range rangeErrorText: End must be after start 单独绘制在 800 × 640 的窗口中docked-date
open: true presentation: docked mode: date value: 2026-09-17 today: 2026-09-24 locale: en-US label: Select date dateLabel: Date previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today 单独绘制在 480 × 720 的窗口中docked-date-range
open: true presentation: docked mode: date range: true start: 2026-09-10 end: 2026-09-16 today: 2026-09-24 locale: en-US label: Select dates dateLabel: Date startLabel: Start endLabel: End previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today 单独绘制在 480 × 720 的窗口中docked-time
open: true presentation: docked mode: time value: 07:30 locale: en-US hourCycle: h12 label: Select time confirmLabel: OK cancelLabel: Cancel hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 480 × 720 的窗口中docked-date-time
open: true presentation: docked mode: date-time value: 2026-09-17T19:30 today: 2026-09-24 locale: en-US hourCycle: h12 layout: horizontal label: Select date and time dateLabel: Date confirmLabel: OK cancelLabel: Cancel previousMonthLabel: Previous month nextMonthLabel: Next month yearViewLabel: Choose a year todayLabel: Today hourLabel: Hour minuteLabel: Minute wheelsLabel: Wheels dialLabel: Dial entryModeLabel: Time input periodLabel: Period 单独绘制在 800 × 640 的窗口中生成自 specs/date-time-picker.spec.json, tokens/comp/date-time-picker.tokens.json, design/tokens/
当用户要选择日期或时间,而看到日历或时钟会有帮助时,使用日期时间选择器:星期几、还有多久、哪几个小时。从文本字段的选择器按钮打开它,这样已经知道值的用户仍然可以直接输入;也可以从任何按钮打开它。如果选择日期本身就是页面的任务,则改为把日历放在页面里。
| 你需要 | 设置 |
|---|---|
| 一个日期 | mode 为 date(默认)。要快速选择,用文本字段下方的 docked;日期值得占用整个屏幕时,用 modal |
| 一段日期范围 | mode 为 date,加上 range |
| 一个时间 | mode 为 time |
| 营业时间、班次、免打扰时段 | mode 为 time,加上 range。结束时间等于或早于开始时间时,落在次日 |
| 一次预约 | mode 为 date-time |
| 从某一时刻到另一时刻的预订 | mode 为 date-time,加上 range |
disabledDates、today、firstDayOfWeek、startView 和 showAdjacentDays 会传给日历,含义与日历中相同。min 和 max 与文本字段的一样,采用该模式的格式:date 模式下是日期,time 模式下是 09:00 这样的时间,date-time 模式下是 2026-09-17T09:00 这样的日期和时间。日历得到它们的日期,时间部分只提供两者之间的时间。在 date-time 模式下,边界只在它自己那一天限制时间,只有日期的边界只限制日期。
选择器是受控的。你在文本字段的 pickerRequest 或按钮的处理函数里设置 open 来打开它,它会带着原因触发 close。在 Web、Compose 和 React Native 上,由你把 open 设回 false;在 SwiftUI 和 Flutter 上,由绑定或路由来关闭它。
- 模态,或任何带时间的选择器。 选择器持有一个待定的选择,并在按下“确定”时提交:如果选择有变化,它先触发
change,再触发带confirm的close。选择不完整时,“确定”处于禁用状态。“取消”、Escape、返回操作和在遮罩上按下都会关闭它,不提交任何内容。它打开期间你设置的值不会改变待定的选择。 - 停靠式,仅日期。 选中使选择完整的那一天时,选择器立即提交并关闭(
select)。它没有操作按钮。选择范围的开始日期后,它保持打开。 - 回写。 选择器不向文本字段写入任何内容。请在
change里设置文本字段的value。选择器关闭时,会把焦点交还给之前持有焦点的元素,通常是文本字段的选择器按钮。
产品之所以留在文本字段和选择器之间,是因为它常常要根据文本字段并不知道的信息来配置选择器:由两个文本字段组成的范围、分钟步长、判定日期的函数。
在 Web 上,停靠式选择器接受 anchor,即它放在其下方的元素的 id;由另一个元素打开它时,还接受 opener。以文本字段作为锚点时,它会把文本字段的选择器按钮标记为打开对话框的控件。
从上到下依次是:页眉、主体和操作。
| 部件 | 说明 |
|---|---|
| 页眉 | 向起始侧对齐的标题行:说明所选内容的 label(例如“入住”);选择器要设置时间时,标题行末尾还有输入方式标签页。选择器自己没有可用作 label 的文字:没有它,标题行不绘制任何文字。带日期的模态选择器还会在它下面显示待定的值(“9月17日周四”“9月10日 – 9月16日”,尚未选择的日期则显示 dateLabel),页眉下方有一条细线。 |
| 日历 | 用于 date 和 date-time。选择器把自己的属性传给日历,不改变它的样式。 |
| 时间区域 | 用于 time 和 date-time。从上到下依次是:设置了 range 时横跨整个区域的范围显示;表盘模式下的时间显示;滚轮或表盘。时段与小时和分钟位于同一行。 |
| 操作 | “取消”和“确定”,一行占满宽度的 tonal 按钮,按各自的任务排列,与对话框中相同。 |
layout 为 vertical 时,日历叠在时间区域上方;为 horizontal 时,两者并排。对于表盘模式下只选时间的选择器,horizontal 把时间显示放在表盘旁边。默认值 auto 只在窗口的高度不足以容纳垂直布局、宽度又足以容纳水平布局时才选择水平布局。各部件放不下时,页眉和操作留在原位,主体在它们之间滚动。
- 滚轮还是表盘。 滚轮是默认方式,排在前面。表盘就是钟面,时间显示(小时选择框和分钟选择框)是它旁边的一行。
entryMode决定选择器打开时使用哪一种,用户可以用输入方式标签页切换:标题行末尾两个纯图标的标签页,滚轮是键盘图标,表盘是时钟图标。它们的文字(wheelsLabel、dialLabel)是它们的无障碍名称。只提供一种方式的产品设置comp.date-time-picker.time.entry-modes,这时不绘制标签页。 - 键入数字。 在滚轮当前选中的值上按下,或者在滚轮持有焦点时键入一个数字,就开始一次键入:在触摸设备上会弹出数字键盘。键入两位数字,或者键入一位后面不可能再接第二位的数字,键入就结束;小时键入完成后会转到分钟,所以
730就是 7:30。表盘模式的选择框以同样的方式读取键盘上的数字。完整的日期仍然在文本字段里输入。 - 时制。
hourCycle默认取自区域设置,也可以设为h12或h23。无论哪种时制,值都是 24 小时制的。 - 时段。 在 12 小时制下,AM 或 PM 是时间的一部分,而不是时间上方的一个开关。在滚轮模式下,它是第三个短滚轮;在表盘模式下,它是一个窄的选择框,按下就换成另一个值。它位于分钟之后;在把它写在前面的区域设置中(例如日语),则位于小时之前。更改它时,小时的数字保持不变,变的是上半天还是下半天。它画得不显眼,从不带上“正在设置的单位”的标记。
- 分钟步长。
minuteStep(1、5、10、15 或 30)决定分钟滚轮的行和表盘上的数字。不在步长上的时间,无论是设置的还是键入的,都向下舍入到步长。 - 范围。
min和max之外的时间仍留在滚轮和表盘上原来的位置,以淡色绘制(comp.date-time-picker.time.unavailable-opacity)。它们不能被选中:滚轮停在最近的可选时间上,方向键跳到下一个可选的值,表盘取最近的可选数字,键入范围之外的数字不会被采用。可选的最早时间是min向上取整到minuteStep,最晚时间是max向下取整。待定的时间在范围之外时,或新的小时、时段会让它落到范围之外时,它会变为较近的那个边界。 - 时间为空时,从当前时间开始。
日期范围在日历里选择:先选开始,再选结束。
带时间的范围把两端显示为由一条短横线连接的两个范围字段:“上午9:00 – 下午5:30”。没有任何文字说明哪个是开始、哪个是结束;顺序和短横线说明了这一点。正在设置的字段被标记为选中,下方的滚轮或表盘显示并设置它的时间。按下另一个字段,就改为设置那一端。仅仅获得焦点不会切换,所以 Tab 可以经过一个字段而不改变正在设置的是哪一端。在日期加时间的范围里,在日历中选择开始日期会选中开始的字段,选择结束日期会选中结束的字段。
- 结束时间等于或早于开始时间的时间范围在次日结束,结束的字段会说明这一点(
nextDayLabel)。 - 结束早于开始的日期加时间范围会显示
rangeErrorText,并让“确定”保持禁用。
Tanrei 不自带任何文字:选择器显示或朗读的每一个词都是你的。label 说明这一个选择器选的是什么,写在它自己身上。其余的文字,无论选择器画在哪里,说法都一样,所以像本页这样,按语言为整个产品只给一次:
import { setWords } from '@tanrei/web';
setWords(
{
confirmLabel: '确定',
cancelLabel: '取消',
dateLabel: '日期',
startLabel: '开始',
endLabel: '结束',
rangeLabel: '范围',
nextDayLabel: '次日',
rangeErrorText: '结束时间必须晚于开始时间',
hourLabel: '小时',
minuteLabel: '分钟',
periodLabel: '上午或下午',
wheelsLabel: '滚轮',
dialLabel: '表盘',
entryModeLabel: '时间输入方式',
previousMonthLabel: '上个月',
nextMonthLabel: '下个月',
yearViewLabel: '选择年份',
todayLabel: '今天',
},
{ lang: 'zh-CN' },
);这段调用就是本页实际运行的那一段:上面的示例只带 label,这些文字一个也没有写。某个选择器的说法不同时,由它自己给出(confirm-label="预订"),而属性总是优先。没有这些文字时,选择器仍然可以使用:“取消”和“确定”是只有图标的按钮,分别画着关闭和对勾的字形;跨夜的结束时间读作 +1;尚未选择的日期什么都不画;调试构建会逐一报告缺少的文字。小时、分钟和时段的名称,以及表示今天的那个词,在你没有给出时取自浏览器的区域数据。
- 从文本字段的选择器按钮打开选择器,这样值也可以直接输入。
- 用你的产品的语言,把
label设置为所选的内容(“入住”“会议开始”),并设置选择器显示的其他文字。 - 只有部分分钟有意义时使用
minuteStep,例如预订时每 15 分钟一档。 - 给选择器设置与它所服务的文本字段相同的
min、max和disabledDates,让两者接受相同的日期和时间。字段的pickerRequest带有它的min和max。
- 不要把日期时间选择器作为输入用户已知日期(例如出生日期)的唯一方式。让用户可以直接输入。
- 不要按选择器分别设置输入方式或操作的外观。它们是产品级的设置,在层里定义。
- 不要在
change之前把值写入文本字段。选择器只在按下“确定”时提交,在停靠式日期选择器中则在选中某一天时提交。 - 在 Web、Compose 或 React Native 上,不要在
close之后让open保持为 true。在这些平台上,选择器从不自行关闭。 - 不要在产品里使用 Web 的
inline属性。它只绘制表面,不具备浮层的行为。
- 角色
dialog- 标注
- The surface is a dialog named by label. The calendar, the tabs and the Buttons label themselves from the words the picker gives them: the calendar's days by their full dates, the entry-mode tabs by wheelsLabel and dialLabel, which are their names though they draw glyphs alone, in a row named entryModeLabel. The range display is a group named rangeLabel whose two range fields are buttons named startLabel and endLabel with their times, each exposing whether it is the one being set; no word for start or end is drawn, so these names are what tells assistive technology which is which. The hour and minute wheels and selectors are spin buttons named by hourLabel and minuteLabel, whose values are read as drawn (the hour with its period in a 12-hour clock), and they stay spin buttons while a number is typed into them. The period is a third spin button beside them, named periodLabel, whose value is the locale's name for before or after noon. The dial is a pointer surface hidden from assistive technology: everything it does, the selectors do too.
- 最小目标
- 即使外观尺寸更小,点击区域也满足最小目标尺寸。 minimum 32px · pointer 44px · spacing 8px · touch 48px
键盘操作
| 按键 | 动作 |
|---|---|
| Tab / Shift+Tab | Modal: moves through the entry-mode tabs, the calendar (its view toggle, its navigation buttons and its active day), the two range fields, the hour, the minute and the period (the period first where the locale writes it first), and Cancel and OK, in reading order, wrapping; focus never leaves. Docked: the same without wrapping; leaving the picker closes it (reason tab). |
| Arrow keys in the calendar | As the calendar: by day or week, changing the month as needed (CAL-11). |
| Left / Right Arrow on the entry-mode tabs | Select the other tab: the other entry mode. |
| Enter / Space on a range field | Makes the wheels or the dial set that end of the range. Focus alone does not. |
| Up / Down Arrow on a wheel / a selector | The next or previous available value, wrapping without changing the other unit or the period; a time outside min and max is passed over. |
| Up / Down Arrow, Enter / Space on the period | The other period (AM or PM), keeping the hour's number. Home is before noon, End after noon; on the dial mode's period selector Left and Right Arrow do the same as Up and Down. |
| Digits on a wheel / a selector | Type the hour or the minute; a finished hour moves on to the minute, and the hour-and-minute separator does too. Backspace removes the last digit. |
| Page Up / Page Down on the minute wheel / selector | Five minutes later or earlier, while minuteStep is 1. |
| Home / End on a wheel / a selector | The first or last available value of its unit. |
| Enter / Space | Choose the active day; activate the focused button or tab; change the period on the period; end a typed entry, keeping it. |
| Escape | During a typed entry, ends it and keeps the value before it. Otherwise closes the picker without committing (reason escape) and returns focus to where it was. |
备注
- The selectors, the period selector and the range fields are at least the minimum target in both dimensions and a wheel's rows at least the target's height (DTM-32); the dial is larger than the target. The calendar's cells, the tabs and the Buttons meet the target themselves (CAL-1, TAB-5, BTN-5).
- Focus: a modal picker is a modal overlay — it keeps focus in and draws a scrim. A docked picker is an operated overlay that is not modal: it takes focus and returns it to its anchor, but Tab leaves it and closes it.
- Typing a whole date or time is still the Text field's job (a trailing icon-only Button opens this picker), with its own reading rules for a date in the locale's order. Here a wheel takes only its own number: a press on its chosen value, or a digit on a keyboard, types the hour or the minute (DTM-43 to DTM-45), so a person who types reaches a time in three or four keys, and a person who does not still reaches every value by the arrow keys, by dragging and by assistive technology's increment and decrement.
- The two ends of a range are not tabs: tabs say one of several views, and the two ends are two values that are both always shown. They are two buttons in a named group, each read with its name, its time and whether it is the one being set ("Start, 9:00 AM, selected"). The dash between them is decoration and is hidden; the names carry what the dash and the order show.
- The entry-mode tabs draw glyphs alone. Their accessible names are wheelsLabel and dialLabel, so a screen reader reads "Wheels, tab, 1 of 2"; both words are the product's.
- Escape ends a typed entry before it closes the picker, as it ends any edit inside a dialog first: one press never both discards a number and dismisses the surface.
- The period is not tabs: tabs say that what is below them is one of several views, and AM or PM is a part of one value. It is exposed as the third field of a time, as the AM/PM field of a native time input is: a spin button of two values named periodLabel ("Period, PM"), which Up and Down Arrow, a press, and assistive technology's increment and decrement change. The hour's own value repeats the period ("7 PM"), so a person who never reaches the period control still hears which half of the day is set.
- The dial mode's period selector shows the pending period alone and changes to the other when pressed. It is one target the height of the selectors: two names stacked in that height would be two targets shorter than the minimum, each over the other's edge (DTM-32). In the wheels mode both names are in view, as every value of a wheel's neighbourhood is.
- The picker has no words of its own. Month, weekday and period names, digits and date and time forms are the platform's locale data, in the locale the picker was given. Every other word it shows or announces is the product's: a prop of this instance, or the product's words set once. Its name, label, is this instance's alone.
- The web exposes each wheel and selector with role spinbutton, aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext, a wheel on an input whose inputmode is numeric so that a touch keyboard is the number pad, and each range field as a button with aria-pressed in a role group; SwiftUI with the adjustable trait (accessibilityAdjustableAction) and a number-pad text field for an entry; Compose with progressBarRangeInfo and setProgress semantics and KeyboardType.Number; Flutter with Semantics increasedValue, decreasedValue, onIncrease and onDecrease and TextInputType.number; React Native with the adjustable role, the increment and decrement actions and a number-pad TextInput.
- Text size: at 200% the wheels, the selectors and the dial's numbers grow; a modal picker scrolls between its header and its actions when the window is short (DTM-36), and the horizontal layout keeps a phone held sideways usable.
- How a state looks is a value decision of the active design system; components read the state's tokens and never compute the effect themselves.
- A time outside min and max keeps its place on the wheels and the dial, drawn faded, and is passed over: a wheel settles on the nearest available row, the arrow keys go on to the next available value, and the dial takes the available value nearest the pointer, as the out-of-range values of a native time picker are dimmed and not chosen. Assistive technology never hears one as a spin button's value: each spin button's minimum and maximum are its first and last available values. Leaving them out instead would move every value after them, so that the place a person knows a time by (12 at the top of the dial, the next hour below this one) would change with the bounds.
生成自 specs/date-time-picker.spec.json, tokens/sys/measure.tokens.json
- 表面是一个以
label命名的对话框。模态选择器把焦点限制在自身之内,并绘制遮罩;停靠式选择器会取得焦点,并把焦点交还给它的锚点,但 Tab 会离开它并将它关闭。打开时焦点移入:移到日历的活动日期,或移到小时。 - 日历、标签页和按钮用选择器给它们的文字为自己命名。输入方式标签页是真正的标签页列表,虽然只画图标,朗读时仍带有名称和位置(“滚轮,标签页,第 1 个,共 2 个”)。
- 范围的两端是一个以
rangeLabel命名的组里的两个按钮,各自朗读名称、时间,以及它是否是正在设置的那一端(“开始,上午9:00”)。startLabel和endLabel从不绘制:它们的作用是告诉辅助技术哪一端是哪一端。短横线是隐藏的。 - 小时和分钟的滚轮与选择框是微调按钮,用方向键、Page Up 和 Page Down 以及 Home 和 End 操作,并按绘制的样子朗读(12 小时制下小时带着它的时段)。向其中键入数字时,它们仍然是微调按钮。时段是第三个微调按钮,有两个值,以
periodLabel命名。键入时段名称的首字母(英语中为 A 或 P)即设为该时段。min和max之外的时间永远不会成为微调按钮的值,每个微调按钮的最小值和最大值是它第一个和最后一个可选的值。表盘对辅助技术隐藏:它能做的一切,选择框也都能做。 - Escape 首先结束正在进行的键入,保留键入之前的值。没有键入时,它关闭选择器而不提交,并把焦点交还给原来的位置。
- 结束早于开始的日期加时间范围会以礼貌(polite)的方式朗读一次,并作为描述出现在结束的范围字段上。
- 每个选择框、范围字段和滚轮的行都不小于最小目标;文本放大时,滚轮、选择框、时段和表盘上的数字会随之变大,而不是把文本裁掉。在窄窗口中,选择器永远不会比窗口更宽:日历的单元格和范围字段会变窄。
- 从右到左的布局会镜像标题行、列、范围显示、时段所在的一侧,以及操作。小时、分隔符和分钟保持这个顺序,表盘仍按顺时针方向排列。
已知的平台差距:
- SwiftUI、Compose、Flutter 和 React Native 尚未实现 DateTimePicker:各平台跟上时会按这份规格来实现。
- Web:结束的范围字段是一个按钮,而按钮没有无效状态,所以范围错误只能以它的描述和朗读的形式到达辅助技术。
- Web:浏览器不报告设备全局的 12 小时制或 24 小时制选择,所以
hourCycle为locale时只依据区域设置。 - Web:在停靠式选择器之外按下会关闭它,这次按下也会到达它下面的元素,与菜单的情况相同。
- Web:停靠式选择器由脚本定位,尚未使用 CSS 锚点定位。
- Web:滚轮、表盘和日历的拖动尚未在真机上用手指检查过,并且有一些测试在 Firefox 和 WebKit 中失败。
- 滚轮与表盘的直径和选择框的宽度都不一致;是否应当一致尚未决定。
- 给每个选择器一个说明所选内容的
label(“入住”“会议时间”)。它只属于这一个选择器:没有它,标题行不绘制任何文字,对话框也没有名称。 - 给出选择器显示或朗读的其他每一个词:写在选择器上,或者像本页这样,用
setWords()为整个产品只给一次。Tanrei 不自带任何文字:各个操作(confirmLabel、cancelLabel)、dateLabel、nextDayLabel、rangeErrorText、日历的六个文字,以及只会被听到的名称(wheelsLabel、dialLabel、entryModeLabel、rangeLabel、startLabel、endLabel)。没有这些文字时,凡是有标记能表达同样意思的地方,选择器就在原处画上标记——只有图标的关闭和对勾按钮、跨夜的结束时间后面的+1——并在开发时逐一报告缺少的文字。小时、分钟和时段的名称,以及表示今天的那个词,在你没有给出时取自浏览器的区域数据。参见产品的文字。 - 从一个说明了自己会打开什么的控件打开它,例如以
pickerLabel(“选择日期”)命名的文本字段选择器按钮。 - 在
change里设置文本字段的value;在open只是普通值的平台上,在close里关闭选择器。 - 同时通过文本字段提供键入的方式。