ionbase-ui 0.59.0 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AgentActivity.d.ts +2 -1
- package/dist/components/AgentActivity.d.ts.map +1 -1
- package/dist/components/AgentActivity.js +4 -17
- package/dist/components/AgentActivity.js.map +1 -1
- package/dist/components/Calendar.d.ts +20 -0
- package/dist/components/Calendar.d.ts.map +1 -0
- package/dist/components/Calendar.js +151 -0
- package/dist/components/Calendar.js.map +1 -0
- package/dist/components/CalendarPopover.d.ts +26 -0
- package/dist/components/CalendarPopover.d.ts.map +1 -0
- package/dist/components/CalendarPopover.js +45 -0
- package/dist/components/CalendarPopover.js.map +1 -0
- package/dist/components/DateField.d.ts +15 -0
- package/dist/components/DateField.d.ts.map +1 -0
- package/dist/components/DateField.js +74 -0
- package/dist/components/DateField.js.map +1 -0
- package/dist/components/DatePicker.d.ts +81 -0
- package/dist/components/DatePicker.d.ts.map +1 -0
- package/dist/components/DatePicker.js +102 -0
- package/dist/components/DatePicker.js.map +1 -0
- package/dist/components/DateRangePicker.d.ts +117 -0
- package/dist/components/DateRangePicker.d.ts.map +1 -0
- package/dist/components/DateRangePicker.js +152 -0
- package/dist/components/DateRangePicker.js.map +1 -0
- package/dist/components/Header.d.ts +10 -0
- package/dist/components/Header.d.ts.map +1 -1
- package/dist/components/Header.js +18 -3
- package/dist/components/Header.js.map +1 -1
- package/dist/components/NumberInput.d.ts +63 -0
- package/dist/components/NumberInput.d.ts.map +1 -0
- package/dist/components/NumberInput.js +102 -0
- package/dist/components/NumberInput.js.map +1 -0
- package/dist/components/PromptInput.d.ts +89 -0
- package/dist/components/PromptInput.d.ts.map +1 -0
- package/dist/components/PromptInput.js +130 -0
- package/dist/components/PromptInput.js.map +1 -0
- package/dist/components/SegmentedControl.d.ts +63 -0
- package/dist/components/SegmentedControl.d.ts.map +1 -0
- package/dist/components/SegmentedControl.js +79 -0
- package/dist/components/SegmentedControl.js.map +1 -0
- package/dist/components/Sidebar.d.ts +109 -0
- package/dist/components/Sidebar.d.ts.map +1 -0
- package/dist/components/Sidebar.js +106 -0
- package/dist/components/Sidebar.js.map +1 -0
- package/dist/components/Stepper.d.ts +73 -0
- package/dist/components/Stepper.d.ts.map +1 -0
- package/dist/components/Stepper.js +82 -0
- package/dist/components/Stepper.js.map +1 -0
- package/dist/components/ToolCall.d.ts +66 -0
- package/dist/components/ToolCall.d.ts.map +1 -0
- package/dist/components/ToolCall.js +78 -0
- package/dist/components/ToolCall.js.map +1 -0
- package/dist/components/agent-status.d.ts +14 -0
- package/dist/components/agent-status.d.ts.map +1 -0
- package/dist/components/agent-status.js +16 -0
- package/dist/components/agent-status.js.map +1 -0
- package/dist/components/index.d.ts +17 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +8 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/iso-date.d.ts +53 -0
- package/dist/components/iso-date.d.ts.map +1 -0
- package/dist/components/iso-date.js +102 -0
- package/dist/components/iso-date.js.map +1 -0
- package/dist/figma-descriptions.json +107 -52
- package/dist/figma-map.json +735 -2
- package/dist/meta/AgentActivityStep.json +2 -2
- package/dist/meta/DatePicker.json +270 -0
- package/dist/meta/DateRangePicker.json +284 -0
- package/dist/meta/Header.json +32 -2
- package/dist/meta/NumberInput.json +407 -0
- package/dist/meta/PromptInput.json +212 -0
- package/dist/meta/SegmentedControl.json +217 -0
- package/dist/meta/SegmentedControlItem.json +122 -0
- package/dist/meta/Sidebar.json +150 -0
- package/dist/meta/SidebarItem.json +184 -0
- package/dist/meta/SidebarSection.json +131 -0
- package/dist/meta/Stepper.json +135 -0
- package/dist/meta/StepperStep.json +148 -0
- package/dist/meta/Tabs.json +5 -0
- package/dist/meta/ToolCall.json +192 -0
- package/dist/meta/components.json +5784 -3297
- package/dist/meta/contrast.json +7776 -2478
- package/dist/meta/index.json +139 -2
- package/dist/meta/patterns/AgentRun.json +27 -0
- package/dist/meta/patterns/Form.json +9 -0
- package/dist/meta/patterns/PageShell.json +43 -3
- package/dist/meta/patterns/Wizard.json +20 -1
- package/dist/meta/patterns/index.json +10 -1
- package/dist/styles/date-picker.css +420 -0
- package/dist/styles/date-range-picker.css +280 -0
- package/dist/styles/header.css +26 -0
- package/dist/styles/index.css +15 -0
- package/dist/styles/number-input.css +83 -0
- package/dist/styles/prompt-input.css +127 -0
- package/dist/styles/segmented-control.css +182 -0
- package/dist/styles/sidebar.css +307 -0
- package/dist/styles/stepper.css +250 -0
- package/dist/styles/tool-call.css +202 -0
- package/llms.txt +2 -2
- package/package.json +20 -19
- package/LICENSE +0 -21
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"note": "the step in plain language"
|
|
44
44
|
},
|
|
45
45
|
"detail": {
|
|
46
|
-
"accepts": "text",
|
|
47
|
-
"note": "the result, a count, a tool name — whatever makes the step checkable"
|
|
46
|
+
"accepts": "text, ToolCall, ApprovalGate",
|
|
47
|
+
"note": "the result, a count, a tool name — whatever makes the step checkable. Block content is valid here: a ToolCall as evidence under the step, or the ApprovalGate the step is waiting on"
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"a11y": {
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "DatePicker",
|
|
3
|
+
"source": "src/components/DatePicker.tsx",
|
|
4
|
+
"propsType": "DatePickerProps",
|
|
5
|
+
"description": "DatePicker — a segmented date field with a calendar attached.\n\nWHY NOT `<input type=\"date\">`\n\nThe native control is genuinely good on mobile and genuinely unusable as a\ndesign system component on desktop: its calendar cannot be styled at all, it\ncannot express an unavailable date that is not part of a continuous min/max\nrange, and Safari on macOS renders no calendar button whatsoever. A system\nwhose date field looks like a different control in every browser is not a\ndesign system, so this rebuilds it — and pays for that by having to rebuild\nthe keyboard handling and the screen-reader semantics the native control gave\naway for free. React Aria's `useDatePicker` is what builds them back.\n\nTHE VALUE IS A STRING, THE DISPLAY IS NOT\n\n`value` is always `YYYY-MM-DD` in the Gregorian calendar. What the user SEES\nis their own locale's field order and their own calendar system, resolved\nfrom `Intl` — so a German reader edits DD.MM.YYYY and the value still comes\nback as `2026-04-12`. See `iso-date.ts` for why the public type is not\nreact-aria's `CalendarDate`.\n\nTHE FIELD IS EDITABLE WITHOUT THE CALENDAR, AND THAT IS THE POINT\n\nTyping a date is faster than clicking one for anybody who knows the date they\nwant, and paging a calendar back to a birth year is miserable. The segments\ntake digits and arrow keys directly; the calendar is for the cases where the\ndate is being chosen rather than recalled.",
|
|
6
|
+
"import": "import { DatePicker } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "A segmented date field with a calendar attached, taking and returning a YYYY-MM-DD string.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"the user picks one calendar date — an event date, a due date, a birthday",
|
|
11
|
+
"the date has to be typed as well as clicked, because the user often already knows it",
|
|
12
|
+
"some dates must be refused individually rather than as a continuous range"
|
|
13
|
+
],
|
|
14
|
+
"useInstead": [
|
|
15
|
+
{
|
|
16
|
+
"when": "the user picks a start and an end",
|
|
17
|
+
"use": "DateRangePicker",
|
|
18
|
+
"why": "two DatePickers cannot stop the end preceding the start, cannot show the days between them, and give the user two calendars to reconcile from memory"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"when": "the value is a month or a year rather than a day",
|
|
22
|
+
"use": "Select",
|
|
23
|
+
"why": "a calendar grid to choose 'March' is twelve options rendered as thirty-one"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"when": "the field is one of a short, known set of dates the product defines",
|
|
27
|
+
"use": "Select or RadioGroup",
|
|
28
|
+
"why": "picking from four delivery slots is a choice from a list, not a date"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"when": "a time of day is part of the value",
|
|
32
|
+
"use": "Input",
|
|
33
|
+
"why": "this picker is fixed to day granularity; a time picker is not yet in this system"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"variants": {
|
|
37
|
+
"size": {
|
|
38
|
+
"sm": {
|
|
39
|
+
"use": "dense forms, table filters"
|
|
40
|
+
},
|
|
41
|
+
"md": {
|
|
42
|
+
"use": "the default"
|
|
43
|
+
},
|
|
44
|
+
"lg": {
|
|
45
|
+
"use": "prominent single-field forms"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"a11y": {
|
|
50
|
+
"guarantees": [
|
|
51
|
+
"each editable segment is its own tab stop, as in Chrome's native <input type=date>; the locale's separators are not, and arrow keys move between segments as well, so neither convention has to be learned",
|
|
52
|
+
"the segments sit in one labelled group, so the field's name is announced once on entry rather than repeated per segment",
|
|
53
|
+
"each segment announces its own name, value and bounds, so 'month, 4, minimum 1, maximum 12' is heard rather than an opaque number",
|
|
54
|
+
"field order and separators come from Intl, so a German reader edits DD.MM.YYYY and a US reader MM/DD/YYYY from the same component and the same value",
|
|
55
|
+
"the calendar overlay is modal: focus moves into the grid, the rest of the page is hidden from assistive tech, Escape closes it and focus returns to the field",
|
|
56
|
+
"every day cell carries the full date as its accessible name in the reader's own language, so the narrow weekday headers are never load-bearing",
|
|
57
|
+
"unavailable and disabled days are distinguished visually and in the accessible name, not by colour alone",
|
|
58
|
+
"today is marked with a dot rather than a ring, so it cannot be mistaken for a second selected day",
|
|
59
|
+
"the selected fill and the segment focus box are redeclared under forced-colors, where background-color is discarded"
|
|
60
|
+
],
|
|
61
|
+
"requires": [
|
|
62
|
+
"`label`, or an `aria-label` when no visible label is rendered",
|
|
63
|
+
"`calendarLabel` wording if 'Open calendar' is wrong for the context — it is the button's whole accessible name"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"antiPatterns": [
|
|
67
|
+
{
|
|
68
|
+
"dont": "passing a Date object, a timestamp, or a locale-formatted string as `value`",
|
|
69
|
+
"why": "the value is a calendar date with no time and no zone, spelled YYYY-MM-DD. `new Date('2026-04-12')` parses as UTC midnight and displays as the 11th for every reader west of Greenwich. A malformed value throws with the prop name rather than rendering an empty field"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"dont": "using `isDateUnavailable` to express a lower or upper bound",
|
|
73
|
+
"why": "`minValue` and `maxValue` also disable the navigation arrows past the bound, so the user cannot page into a month with nothing selectable in it. A predicate is for the holes inside the bounds"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"dont": "hiding the field and leaving only the calendar button",
|
|
77
|
+
"why": "typing a date is faster than clicking one for anyone who already knows it, and paging a calendar back to a birth year is the worst interaction in any form"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"dont": "styling a day cell with :hover for the keyboard highlight",
|
|
81
|
+
"why": "use [data-selected], [data-today], [data-disabled] and [data-unavailable]. Pointer hover and keyboard focus are different states here and a grid where they disagree has two apparent cursors"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"dont": "reading the posted form value from the segments",
|
|
85
|
+
"why": "they are spinbuttons with no name. Pass `name` and the component posts the ISO value in a hidden input"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"dont": "wrapping it in a <label>",
|
|
89
|
+
"why": "the group is a set of spinbuttons rather than one form control, so there is nothing for htmlFor to point at. Pass `label` and react-aria wires the name through aria-labelledby"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"dont": "adding a roving tabindex so the field becomes one tab stop",
|
|
93
|
+
"why": "it buys back two tabs per field and costs the ability to Tab straight to the year, which is the segment users most often fix on its own. It also diverges from the native date input, which is the convention they already have"
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
"slots": {
|
|
97
|
+
"label": {
|
|
98
|
+
"expects": "what the date is for — 'Event starts', not 'Date'"
|
|
99
|
+
},
|
|
100
|
+
"description": {
|
|
101
|
+
"expects": "helper text under the field; replaced by `errorMessage` when `isInvalid`"
|
|
102
|
+
},
|
|
103
|
+
"errorMessage": {
|
|
104
|
+
"expects": "what is wrong and what would be right, shown only when `isInvalid`"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"stylesheet": "src/styles/date-picker.css",
|
|
108
|
+
"tokens": [
|
|
109
|
+
"--border-focus",
|
|
110
|
+
"--border-subtle",
|
|
111
|
+
"--border-width-default",
|
|
112
|
+
"--border-width-thick",
|
|
113
|
+
"--font-family-sans",
|
|
114
|
+
"--font-weight-medium",
|
|
115
|
+
"--font-weight-regular",
|
|
116
|
+
"--font-weight-semibold",
|
|
117
|
+
"--icon-disabled",
|
|
118
|
+
"--icon-interactive",
|
|
119
|
+
"--icon-on-color",
|
|
120
|
+
"--icon-primary",
|
|
121
|
+
"--icon-secondary",
|
|
122
|
+
"--icon-size-sm",
|
|
123
|
+
"--ion-calendar-day-size",
|
|
124
|
+
"--ion-input-icon-size",
|
|
125
|
+
"--ion-shadow-shadow-lg",
|
|
126
|
+
"--radius-2xs",
|
|
127
|
+
"--radius-full",
|
|
128
|
+
"--radius-md",
|
|
129
|
+
"--radius-sm",
|
|
130
|
+
"--spacing-12",
|
|
131
|
+
"--spacing-2",
|
|
132
|
+
"--spacing-24",
|
|
133
|
+
"--spacing-32",
|
|
134
|
+
"--spacing-4",
|
|
135
|
+
"--spacing-6",
|
|
136
|
+
"--spacing-8",
|
|
137
|
+
"--surface-hover",
|
|
138
|
+
"--surface-primary",
|
|
139
|
+
"--surface-raised",
|
|
140
|
+
"--text-default",
|
|
141
|
+
"--text-disabled",
|
|
142
|
+
"--text-on-color",
|
|
143
|
+
"--text-secondary",
|
|
144
|
+
"--text-tertiary",
|
|
145
|
+
"--type-body-sm",
|
|
146
|
+
"--type-body-sm-line-height",
|
|
147
|
+
"--type-caption",
|
|
148
|
+
"--type-caption-line-height"
|
|
149
|
+
],
|
|
150
|
+
"props": {
|
|
151
|
+
"label": {
|
|
152
|
+
"type": "React.ReactNode",
|
|
153
|
+
"required": false,
|
|
154
|
+
"origin": "own",
|
|
155
|
+
"description": "Field label. Required for a usable control — see `a11y.requires`."
|
|
156
|
+
},
|
|
157
|
+
"description": {
|
|
158
|
+
"type": "React.ReactNode",
|
|
159
|
+
"required": false,
|
|
160
|
+
"origin": "own",
|
|
161
|
+
"description": "Helper text below the field."
|
|
162
|
+
},
|
|
163
|
+
"errorMessage": {
|
|
164
|
+
"type": "React.ReactNode",
|
|
165
|
+
"required": false,
|
|
166
|
+
"origin": "own",
|
|
167
|
+
"description": "Replaces the helper text when `isInvalid` is set."
|
|
168
|
+
},
|
|
169
|
+
"isInvalid": {
|
|
170
|
+
"type": "boolean | undefined",
|
|
171
|
+
"required": false,
|
|
172
|
+
"origin": "own"
|
|
173
|
+
},
|
|
174
|
+
"isDisabled": {
|
|
175
|
+
"type": "boolean | undefined",
|
|
176
|
+
"required": false,
|
|
177
|
+
"origin": "own"
|
|
178
|
+
},
|
|
179
|
+
"isReadOnly": {
|
|
180
|
+
"type": "boolean | undefined",
|
|
181
|
+
"required": false,
|
|
182
|
+
"origin": "own"
|
|
183
|
+
},
|
|
184
|
+
"isRequired": {
|
|
185
|
+
"type": "boolean | undefined",
|
|
186
|
+
"required": false,
|
|
187
|
+
"origin": "own"
|
|
188
|
+
},
|
|
189
|
+
"size": {
|
|
190
|
+
"type": "DatePickerSize | undefined",
|
|
191
|
+
"required": false,
|
|
192
|
+
"origin": "own",
|
|
193
|
+
"description": "Matches Input's `Size` variant: Small, Medium, Large.",
|
|
194
|
+
"values": [
|
|
195
|
+
"sm",
|
|
196
|
+
"md",
|
|
197
|
+
"lg"
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
"value": {
|
|
201
|
+
"type": "string | null | undefined",
|
|
202
|
+
"required": false,
|
|
203
|
+
"origin": "own",
|
|
204
|
+
"description": "The selected date as `YYYY-MM-DD`. `null` means nothing is selected.\n\nNot a `Date` and not a timestamp — a calendar date has no time and no\ntimezone, so it cannot shift across midnight the way `new Date('2026-04-12')`\ndoes for every reader west of Greenwich. A malformed value throws rather\nthan rendering an empty field."
|
|
205
|
+
},
|
|
206
|
+
"defaultValue": {
|
|
207
|
+
"type": "string | undefined",
|
|
208
|
+
"required": false,
|
|
209
|
+
"origin": "own",
|
|
210
|
+
"description": "The initial date as `YYYY-MM-DD`, for an uncontrolled picker."
|
|
211
|
+
},
|
|
212
|
+
"onChange": {
|
|
213
|
+
"type": "((value: IsoDate | null) => void) | undefined",
|
|
214
|
+
"required": false,
|
|
215
|
+
"origin": "own",
|
|
216
|
+
"description": "Fires with `YYYY-MM-DD`, or `null` when the field is cleared."
|
|
217
|
+
},
|
|
218
|
+
"minValue": {
|
|
219
|
+
"type": "string | undefined",
|
|
220
|
+
"required": false,
|
|
221
|
+
"origin": "own",
|
|
222
|
+
"description": "Earliest selectable date, `YYYY-MM-DD`. Earlier dates are unreachable."
|
|
223
|
+
},
|
|
224
|
+
"maxValue": {
|
|
225
|
+
"type": "string | undefined",
|
|
226
|
+
"required": false,
|
|
227
|
+
"origin": "own",
|
|
228
|
+
"description": "Latest selectable date, `YYYY-MM-DD`."
|
|
229
|
+
},
|
|
230
|
+
"isDateUnavailable": {
|
|
231
|
+
"type": "((date: IsoDate) => boolean) | undefined",
|
|
232
|
+
"required": false,
|
|
233
|
+
"origin": "own",
|
|
234
|
+
"description": "Individual dates the calendar refuses — weekends, holidays, booked days.\nReceives `YYYY-MM-DD`. Use `minValue`/`maxValue` for a continuous bound;\nthis is for the holes inside it."
|
|
235
|
+
},
|
|
236
|
+
"name": {
|
|
237
|
+
"type": "string | undefined",
|
|
238
|
+
"required": false,
|
|
239
|
+
"origin": "own",
|
|
240
|
+
"description": "Posts the value under this name, for an uncontrolled form."
|
|
241
|
+
},
|
|
242
|
+
"calendarLabel": {
|
|
243
|
+
"type": "string | undefined",
|
|
244
|
+
"required": false,
|
|
245
|
+
"origin": "own",
|
|
246
|
+
"description": "Accessible label for the button that opens the calendar."
|
|
247
|
+
},
|
|
248
|
+
"className": {
|
|
249
|
+
"type": "string | undefined",
|
|
250
|
+
"required": false,
|
|
251
|
+
"origin": "own"
|
|
252
|
+
},
|
|
253
|
+
"wrapperClassName": {
|
|
254
|
+
"type": "string | undefined",
|
|
255
|
+
"required": false,
|
|
256
|
+
"origin": "own"
|
|
257
|
+
},
|
|
258
|
+
"id": {
|
|
259
|
+
"type": "string | undefined",
|
|
260
|
+
"required": false,
|
|
261
|
+
"origin": "own"
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"propCounts": {
|
|
265
|
+
"own": 19,
|
|
266
|
+
"aria": 0,
|
|
267
|
+
"dom": 0,
|
|
268
|
+
"other": 0
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "DateRangePicker",
|
|
3
|
+
"source": "src/components/DateRangePicker.tsx",
|
|
4
|
+
"propsType": "DateRangePickerProps",
|
|
5
|
+
"description": "DateRangePicker — two segmented date fields with one calendar between them.\n\nNOT TWO `DatePicker`s SIDE BY SIDE, and the difference is the whole reason\nthis exists. Two independent pickers cannot stop the end date being before\nthe start, cannot show the days between them as a band, and give the user two\ncalendars to reconcile by memory. `useDateRangePicker` owns both ends: the\nsecond click completes the range in whichever order the two dates fall, the\nband follows the pointer while it is being dragged out, and a range cannot be\nmade to run backwards.\n\nTHE VALUE COMMITS LIVE. THERE IS NO APPLY BUTTON.\n\n`onChange` fires the moment the second end lands, and the calendar closes.\nThe reference designs this was drawn from put Clear and Apply under the grid,\nwhich is a draft model: the popover holds a pending range and only Apply\npromotes it. That was considered and rejected. Escape and an outside click\nwould then silently discard a selection the user watched themselves make —\nand there is no way to tell those two gestures apart from \"I am done\". A\nbutton labelled Apply beside a value that already applied is worse still.\n\nClear stays, because clearing is a real action with no other affordance.\n\nBOTH ENDS OR NEITHER\n\n`value` has no half-open form. A range with a start and no end is a state the\ncalendar passes THROUGH between the two clicks; it is never a value the\ncaller is handed, because \"everything after March\" and \"March to today\" are\ndifferent questions and a `null` end cannot say which one was meant. A caller\nwho wants an open end passes a sentinel of their own choosing as `maxValue`.",
|
|
6
|
+
"import": "import { DateRangePicker } from 'ionbase-ui';",
|
|
7
|
+
"status": "stable",
|
|
8
|
+
"summary": "Two segmented date fields sharing one calendar, returning an inclusive { start, end } of YYYY-MM-DD strings.",
|
|
9
|
+
"useWhen": [
|
|
10
|
+
"the user picks a period — a report window, a stay, a filter over time",
|
|
11
|
+
"the range commonly crosses a month boundary, so both ends need to be visible at once",
|
|
12
|
+
"there are conventional periods worth offering as shortcuts: last 7 days, month to date, year to date"
|
|
13
|
+
],
|
|
14
|
+
"useInstead": [
|
|
15
|
+
{
|
|
16
|
+
"when": "the user picks one date",
|
|
17
|
+
"use": "DatePicker"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"when": "the choice is really a named period and the exact dates are incidental",
|
|
21
|
+
"use": "Select",
|
|
22
|
+
"why": "if 'Last 30 days' is the answer rather than a shortcut to one, a calendar is scaffolding around a list of five options"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"when": "one end is open — everything before, or everything since",
|
|
26
|
+
"use": "DatePicker",
|
|
27
|
+
"why": "with the open end expressed as minValue or maxValue. This component has no half-open value on purpose; see antiPatterns"
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
"variants": {
|
|
31
|
+
"size": {
|
|
32
|
+
"sm": {
|
|
33
|
+
"use": "dense forms, table filters, dashboard toolbars"
|
|
34
|
+
},
|
|
35
|
+
"md": {
|
|
36
|
+
"use": "the default"
|
|
37
|
+
},
|
|
38
|
+
"lg": {
|
|
39
|
+
"use": "prominent single-field forms"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"a11y": {
|
|
44
|
+
"guarantees": [
|
|
45
|
+
"both fields sit in one labelled group; each announces its own name, so 'Start Date' and 'End Date' are heard without a visible sublabel, and each editable segment is its own tab stop as it is in DatePicker",
|
|
46
|
+
"the dash between them is aria-hidden — the fields have already said what they are, and a spoken dash adds nothing",
|
|
47
|
+
"the calendar is modal: focus enters the grid, the page behind is hidden from assistive tech, Escape closes and focus returns",
|
|
48
|
+
"a range cannot be made to run backwards, in either direction of selection, and cannot be dragged across an unavailable day",
|
|
49
|
+
"preset rows are buttons in a labelled group carrying aria-pressed, so 'which shortcut is active' is answerable without seeing the tint",
|
|
50
|
+
"the selected preset is marked by weight as well as by background, so it does not rely on colour alone",
|
|
51
|
+
"range endpoints and the band between them keep their fill under forced-colors, where background-color is otherwise discarded",
|
|
52
|
+
"the rail stacks above the grids below 32rem rather than being hidden, because shortcuts matter most on the device where dragging across two months is worst"
|
|
53
|
+
],
|
|
54
|
+
"requires": [
|
|
55
|
+
"`label`, or an `aria-label` when no visible label is rendered",
|
|
56
|
+
"`presetsLabel` wording if the default is wrong for the context — it names the whole shortcut group",
|
|
57
|
+
"preset labels that say what period they select, since the label is the button's entire accessible name"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"antiPatterns": [
|
|
61
|
+
{
|
|
62
|
+
"dont": "expecting an Apply button, or adding one",
|
|
63
|
+
"why": "the value commits when the second end lands and the calendar closes. A draft model makes Escape and an outside click silently discard a selection the user watched themselves make, and there is no way to tell those gestures apart from 'I am done'. Clear exists because clearing has no other affordance"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"dont": "passing a range with only one end, or reading one back",
|
|
67
|
+
"why": "a start with no end is a state the calendar passes through between the two clicks, never a value the caller is handed. 'Everything after March' and 'March to today' are different questions and a null end cannot say which was meant"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"dont": "writing a relative preset as a literal object",
|
|
71
|
+
"why": "`value: { start: '…', end: '…' }` is evaluated once, when the module is first imported. 'Last 7 days' is then seven days before whenever the tab was opened. Pass a function; it is re-run each time the calendar opens"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"dont": "composing this out of two DatePickers",
|
|
75
|
+
"why": "two independent pickers cannot stop the end preceding the start, cannot draw the band between the ends, and make the user reconcile two calendars from memory"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"dont": "setting visibleMonths to 1 for a filter that usually spans weeks",
|
|
79
|
+
"why": "the user then pages back and forth to see both ends of their own selection. One month is for ranges that genuinely sit inside one"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"dont": "treating `end` as exclusive",
|
|
83
|
+
"why": "the range is closed. A stay of 3 nights from the 1st ends on the 4th in checkout terms and on the 3rd here; convert at your boundary, not in the picker"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"slots": {
|
|
87
|
+
"label": {
|
|
88
|
+
"expects": "what the period is for — 'Reporting period', not 'Dates'"
|
|
89
|
+
},
|
|
90
|
+
"presets": {
|
|
91
|
+
"expects": "conventional periods for this screen, longest-lived first: today, last 7 days, month to date, year to date"
|
|
92
|
+
},
|
|
93
|
+
"description": {
|
|
94
|
+
"expects": "helper text under the fields; replaced by `errorMessage` when `isInvalid`"
|
|
95
|
+
},
|
|
96
|
+
"errorMessage": {
|
|
97
|
+
"expects": "what is wrong with the range and what would be right, shown only when `isInvalid`"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"stylesheet": "src/styles/date-range-picker.css",
|
|
101
|
+
"tokens": [
|
|
102
|
+
"--border-focus",
|
|
103
|
+
"--border-subtle",
|
|
104
|
+
"--border-width-default",
|
|
105
|
+
"--border-width-thick",
|
|
106
|
+
"--font-family-sans",
|
|
107
|
+
"--font-weight-medium",
|
|
108
|
+
"--font-weight-regular",
|
|
109
|
+
"--icon-disabled",
|
|
110
|
+
"--icon-interactive",
|
|
111
|
+
"--ion-input-icon-size",
|
|
112
|
+
"--radius-2xs",
|
|
113
|
+
"--radius-full",
|
|
114
|
+
"--radius-none",
|
|
115
|
+
"--radius-sm",
|
|
116
|
+
"--spacing-12",
|
|
117
|
+
"--spacing-2",
|
|
118
|
+
"--spacing-4",
|
|
119
|
+
"--spacing-6",
|
|
120
|
+
"--spacing-8",
|
|
121
|
+
"--surface-hover",
|
|
122
|
+
"--surface-primary",
|
|
123
|
+
"--surface-primary-subtle",
|
|
124
|
+
"--surface-primary-subtle-hover",
|
|
125
|
+
"--surface-raised",
|
|
126
|
+
"--text-default",
|
|
127
|
+
"--text-disabled",
|
|
128
|
+
"--text-interactive",
|
|
129
|
+
"--text-interactive-hover",
|
|
130
|
+
"--text-on-color",
|
|
131
|
+
"--text-primary",
|
|
132
|
+
"--text-tertiary",
|
|
133
|
+
"--type-body-sm",
|
|
134
|
+
"--type-body-sm-line-height"
|
|
135
|
+
],
|
|
136
|
+
"props": {
|
|
137
|
+
"label": {
|
|
138
|
+
"type": "React.ReactNode",
|
|
139
|
+
"required": false,
|
|
140
|
+
"origin": "own",
|
|
141
|
+
"description": "Field label. Required for a usable control — see `a11y.requires`."
|
|
142
|
+
},
|
|
143
|
+
"description": {
|
|
144
|
+
"type": "React.ReactNode",
|
|
145
|
+
"required": false,
|
|
146
|
+
"origin": "own",
|
|
147
|
+
"description": "Helper text below the field."
|
|
148
|
+
},
|
|
149
|
+
"errorMessage": {
|
|
150
|
+
"type": "React.ReactNode",
|
|
151
|
+
"required": false,
|
|
152
|
+
"origin": "own",
|
|
153
|
+
"description": "Replaces the helper text when `isInvalid` is set."
|
|
154
|
+
},
|
|
155
|
+
"isInvalid": {
|
|
156
|
+
"type": "boolean | undefined",
|
|
157
|
+
"required": false,
|
|
158
|
+
"origin": "own"
|
|
159
|
+
},
|
|
160
|
+
"isDisabled": {
|
|
161
|
+
"type": "boolean | undefined",
|
|
162
|
+
"required": false,
|
|
163
|
+
"origin": "own"
|
|
164
|
+
},
|
|
165
|
+
"isReadOnly": {
|
|
166
|
+
"type": "boolean | undefined",
|
|
167
|
+
"required": false,
|
|
168
|
+
"origin": "own"
|
|
169
|
+
},
|
|
170
|
+
"isRequired": {
|
|
171
|
+
"type": "boolean | undefined",
|
|
172
|
+
"required": false,
|
|
173
|
+
"origin": "own"
|
|
174
|
+
},
|
|
175
|
+
"size": {
|
|
176
|
+
"type": "DateRangePickerSize | undefined",
|
|
177
|
+
"required": false,
|
|
178
|
+
"origin": "own",
|
|
179
|
+
"description": "Matches Input's `Size` variant: Small, Medium, Large.",
|
|
180
|
+
"values": [
|
|
181
|
+
"sm",
|
|
182
|
+
"md",
|
|
183
|
+
"lg"
|
|
184
|
+
]
|
|
185
|
+
},
|
|
186
|
+
"value": {
|
|
187
|
+
"type": "DateRange | null | undefined",
|
|
188
|
+
"required": false,
|
|
189
|
+
"origin": "own",
|
|
190
|
+
"description": "The selected range, both ends as `YYYY-MM-DD`. `null` means no range.\nA half-open range is not representable on purpose — see `antiPatterns`."
|
|
191
|
+
},
|
|
192
|
+
"defaultValue": {
|
|
193
|
+
"type": "DateRange | undefined",
|
|
194
|
+
"required": false,
|
|
195
|
+
"origin": "own",
|
|
196
|
+
"description": "The initial range, for an uncontrolled picker."
|
|
197
|
+
},
|
|
198
|
+
"onChange": {
|
|
199
|
+
"type": "((value: DateRange | null) => void) | undefined",
|
|
200
|
+
"required": false,
|
|
201
|
+
"origin": "own",
|
|
202
|
+
"description": "Fires with both ends, or `null` when the range is cleared."
|
|
203
|
+
},
|
|
204
|
+
"minValue": {
|
|
205
|
+
"type": "string | undefined",
|
|
206
|
+
"required": false,
|
|
207
|
+
"origin": "own",
|
|
208
|
+
"description": "Earliest selectable date, `YYYY-MM-DD`."
|
|
209
|
+
},
|
|
210
|
+
"maxValue": {
|
|
211
|
+
"type": "string | undefined",
|
|
212
|
+
"required": false,
|
|
213
|
+
"origin": "own",
|
|
214
|
+
"description": "Latest selectable date, `YYYY-MM-DD`."
|
|
215
|
+
},
|
|
216
|
+
"isDateUnavailable": {
|
|
217
|
+
"type": "((date: IsoDate) => boolean) | undefined",
|
|
218
|
+
"required": false,
|
|
219
|
+
"origin": "own",
|
|
220
|
+
"description": "Individual dates the calendar refuses. Receives `YYYY-MM-DD`.\n\nA range may not be dragged ACROSS one of these — react-aria stops the\nselection at the first unavailable day, which is what makes \"book a room\nfor these nights\" correct rather than merely styled."
|
|
221
|
+
},
|
|
222
|
+
"presets": {
|
|
223
|
+
"type": "readonly DateRangePreset[] | undefined",
|
|
224
|
+
"required": false,
|
|
225
|
+
"origin": "own",
|
|
226
|
+
"description": "Shortcut rows beside the calendar. Omitted, no rail is rendered."
|
|
227
|
+
},
|
|
228
|
+
"visibleMonths": {
|
|
229
|
+
"type": "2 | 3 | 1 | undefined",
|
|
230
|
+
"required": false,
|
|
231
|
+
"origin": "own",
|
|
232
|
+
"description": "How many months the calendar shows at once. Two by default: a range that\ncrosses a month boundary is the common case, and a one-month calendar\nmakes the user page back and forth to see both ends of their own selection."
|
|
233
|
+
},
|
|
234
|
+
"isClearable": {
|
|
235
|
+
"type": "boolean | undefined",
|
|
236
|
+
"required": false,
|
|
237
|
+
"origin": "own",
|
|
238
|
+
"description": "Show a Clear button under the calendar. Defaults to `true`."
|
|
239
|
+
},
|
|
240
|
+
"name": {
|
|
241
|
+
"type": "string | undefined",
|
|
242
|
+
"required": false,
|
|
243
|
+
"origin": "own",
|
|
244
|
+
"description": "Posts `<name>-start` and `<name>-end` for an uncontrolled form."
|
|
245
|
+
},
|
|
246
|
+
"calendarLabel": {
|
|
247
|
+
"type": "string | undefined",
|
|
248
|
+
"required": false,
|
|
249
|
+
"origin": "own",
|
|
250
|
+
"description": "Accessible label for the button that opens the calendar."
|
|
251
|
+
},
|
|
252
|
+
"clearLabel": {
|
|
253
|
+
"type": "string | undefined",
|
|
254
|
+
"required": false,
|
|
255
|
+
"origin": "own"
|
|
256
|
+
},
|
|
257
|
+
"presetsLabel": {
|
|
258
|
+
"type": "string | undefined",
|
|
259
|
+
"required": false,
|
|
260
|
+
"origin": "own"
|
|
261
|
+
},
|
|
262
|
+
"className": {
|
|
263
|
+
"type": "string | undefined",
|
|
264
|
+
"required": false,
|
|
265
|
+
"origin": "own"
|
|
266
|
+
},
|
|
267
|
+
"wrapperClassName": {
|
|
268
|
+
"type": "string | undefined",
|
|
269
|
+
"required": false,
|
|
270
|
+
"origin": "own"
|
|
271
|
+
},
|
|
272
|
+
"id": {
|
|
273
|
+
"type": "string | undefined",
|
|
274
|
+
"required": false,
|
|
275
|
+
"origin": "own"
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
"propCounts": {
|
|
279
|
+
"own": 24,
|
|
280
|
+
"aria": 0,
|
|
281
|
+
"dom": 0,
|
|
282
|
+
"other": 0
|
|
283
|
+
}
|
|
284
|
+
}
|
package/dist/meta/Header.json
CHANGED
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"guarantees": [
|
|
41
41
|
"the mobile toggle carries `aria-expanded` and `aria-controls` pointing at the menu container",
|
|
42
42
|
"Escape closes the open mobile menu — and the listener sits on the header, so a header that never opens never listens",
|
|
43
|
-
"the slots are rendered once, so no nav link exists twice in the accessibility tree"
|
|
43
|
+
"the slots are rendered once, so no nav link exists twice in the accessibility tree",
|
|
44
|
+
"with `menuType=\"dialog\"` the toggle carries `aria-haspopup=\"dialog\"` instead of `aria-controls` — the Drawer it opens is not in the DOM while closed — and comes first in DOM order as well as on screen"
|
|
44
45
|
],
|
|
45
46
|
"requires": [
|
|
46
47
|
"`menuLabel` — the mobile toggle is icon-only and has no other name"
|
|
@@ -61,8 +62,27 @@
|
|
|
61
62
|
{
|
|
62
63
|
"dont": "passing `open` without `onOpenChange`",
|
|
63
64
|
"why": "controlled with no handler means the toggle can never change it"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"dont": "a second menu button in `brand` to open a navigation Drawer",
|
|
68
|
+
"do": "<Header menuType=\"dialog\" open={navOpen} onOpenChange={setNavOpen} />",
|
|
69
|
+
"why": "the built-in toggle still renders, so a phone shows two menu buttons that open different things"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"dont": "NavItems in `center` with `menuType=\"dialog\"`",
|
|
73
|
+
"why": "nothing collapses them any more — they overflow a phone, and they duplicate the Sidebar the dialog opens"
|
|
64
74
|
}
|
|
65
75
|
],
|
|
76
|
+
"variants": {
|
|
77
|
+
"menuType": {
|
|
78
|
+
"panel": {
|
|
79
|
+
"use": "the default, Figma's Mobile-Open — `center` and `end` drop into a panel below the bar"
|
|
80
|
+
},
|
|
81
|
+
"dialog": {
|
|
82
|
+
"use": "the app's navigation is a Sidebar. The toggle moves to the start of the bar and only reports `onOpenChange`; open a Drawer holding the same Sidebar with it. `center` and `end` stay in the bar at every width"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
66
86
|
"stylesheet": "src/styles/header.css",
|
|
67
87
|
"tokens": [
|
|
68
88
|
"--border-default",
|
|
@@ -135,6 +155,16 @@
|
|
|
135
155
|
"origin": "own",
|
|
136
156
|
"description": "Accessible name for the mobile menu toggle."
|
|
137
157
|
},
|
|
158
|
+
"menuType": {
|
|
159
|
+
"type": "\"dialog\" | \"panel\" | undefined",
|
|
160
|
+
"required": false,
|
|
161
|
+
"origin": "own",
|
|
162
|
+
"description": "What the mobile toggle opens.\n\n`panel` (default) is Figma's Mobile-Open: `center` and `end` drop below the\nbar. `dialog` is for an app whose navigation lives in a Sidebar: the toggle\nsits at the start of the bar and only reports `onOpenChange`, the caller\nopens a Drawer with it, and `center` and `end` stay in the bar at every\nwidth — so keep `center` empty and `end` short.",
|
|
163
|
+
"values": [
|
|
164
|
+
"dialog",
|
|
165
|
+
"panel"
|
|
166
|
+
]
|
|
167
|
+
},
|
|
138
168
|
"children": {
|
|
139
169
|
"type": "React.ReactNode",
|
|
140
170
|
"required": false,
|
|
@@ -142,7 +172,7 @@
|
|
|
142
172
|
}
|
|
143
173
|
},
|
|
144
174
|
"propCounts": {
|
|
145
|
-
"own":
|
|
175
|
+
"own": 9,
|
|
146
176
|
"aria": 0,
|
|
147
177
|
"dom": 276,
|
|
148
178
|
"other": 0
|