@eifi1/ui-kit 0.8.1 → 0.10.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/README.md +25 -11
- package/dist/components/alert-banner.d.ts +32 -5
- package/dist/components/alert-banner.js +57 -14
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +6 -0
- package/dist/components/breadcrumbs.d.ts +60 -0
- package/dist/components/breadcrumbs.js +88 -0
- package/dist/components/breadcrumbs.js.map +1 -0
- package/dist/components/bulk-action-bar.d.ts +66 -0
- package/dist/components/bulk-action-bar.js +149 -0
- package/dist/components/bulk-action-bar.js.map +1 -0
- package/dist/components/calculator.d.ts +6 -0
- package/dist/components/chip.d.ts +58 -10
- package/dist/components/chip.js +91 -7
- package/dist/components/chip.js.map +1 -1
- package/dist/components/copy-button.d.ts +13 -4
- package/dist/components/copy-button.js +17 -4
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +122 -91
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +89 -3
- package/dist/components/date-picker.js +163 -68
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +43 -6
- package/dist/components/description-list.js +91 -11
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +7 -0
- package/dist/components/dialog-frame.js.map +1 -1
- package/dist/components/disclosure.d.ts +68 -4
- package/dist/components/disclosure.js +33 -15
- package/dist/components/disclosure.js.map +1 -1
- package/dist/components/file-dropzone.d.ts +3 -4
- package/dist/components/file-dropzone.js +2 -1
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/floating-panel.d.ts +29 -2
- package/dist/components/floating-panel.js +16 -2
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/full-bleed-dialog.d.ts +23 -4
- package/dist/components/full-bleed-dialog.js +11 -2
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/list.d.ts +174 -0
- package/dist/components/list.js +215 -0
- package/dist/components/list.js.map +1 -0
- package/dist/components/menu-item.d.ts +99 -0
- package/dist/components/menu-item.js +83 -0
- package/dist/components/menu-item.js.map +1 -0
- package/dist/components/modal.d.ts +23 -1
- package/dist/components/modal.js +36 -10
- package/dist/components/modal.js.map +1 -1
- package/dist/components/number-field.d.ts +6 -0
- package/dist/components/number-input.d.ts +6 -0
- package/dist/components/numpad-sheet.d.ts +6 -0
- package/dist/components/page-contents.js +1 -2
- package/dist/components/page-contents.js.map +1 -1
- package/dist/components/page-header.d.ts +37 -0
- package/dist/components/page-header.js +36 -0
- package/dist/components/page-header.js.map +1 -0
- package/dist/components/progress-bar.d.ts +16 -2
- package/dist/components/progress-bar.js +4 -2
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +3 -0
- package/dist/components/series-chart-labels.js +2 -1
- package/dist/components/series-chart-labels.js.map +1 -1
- package/dist/components/series-chart.d.ts +16 -0
- package/dist/components/series-chart.js +137 -3
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/status-dot.d.ts +49 -0
- package/dist/components/status-dot.js +52 -0
- package/dist/components/status-dot.js.map +1 -0
- package/dist/components/table.d.ts +39 -6
- package/dist/components/table.js +43 -4
- package/dist/components/table.js.map +1 -1
- package/dist/components/text.d.ts +63 -0
- package/dist/components/text.js +23 -0
- package/dist/components/text.js.map +1 -0
- package/dist/components/toast.d.ts +167 -0
- package/dist/components/toast.js +226 -0
- package/dist/components/toast.js.map +1 -0
- package/dist/components/toggle-group.d.ts +29 -1
- package/dist/components/toggle-group.js +52 -3
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/tooltip.d.ts +38 -15
- package/dist/components/tooltip.js +85 -47
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/ui.d.ts +139 -16
- package/dist/components/ui.js +136 -26
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -1
- package/dist/{data-table-filters-CF1PXqjQ.d.ts → data-table-filters-Dh9uF_S-.d.ts} +33 -2
- package/dist/data-table.d.ts +1 -1
- package/dist/hooks/use-close-transition.d.ts +7 -1
- package/dist/hooks/use-close-transition.js +5 -2
- package/dist/hooks/use-close-transition.js.map +1 -1
- package/dist/hooks/use-copy-to-clipboard.js +1 -1
- package/dist/hooks/use-copy-to-clipboard.js.map +1 -1
- package/dist/hooks/use-overlay-history.js +84 -4
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/i18n/defaults.d.ts +6 -0
- package/dist/i18n/defaults.js +11 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +11 -0
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +6 -0
- package/dist/i18n/locales/de-CH.d.ts +6 -0
- package/dist/i18n/locales/de-informal.d.ts +6 -0
- package/dist/i18n/locales/de.d.ts +6 -0
- package/dist/i18n/locales/de.js +31 -1
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +6 -0
- package/dist/i18n/locales/es.js +31 -1
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +6 -0
- package/dist/i18n/locales/fr.js +31 -1
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +6 -0
- package/dist/i18n/locales/hu.js +31 -1
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +6 -0
- package/dist/i18n/locales/it.js +31 -1
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +6 -0
- package/dist/i18n/locales/zh.js +31 -1
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +18 -8
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/clipping.d.ts +9 -0
- package/dist/lib/clipping.js +14 -0
- package/dist/lib/clipping.js.map +1 -0
- package/dist/search/command-palette.d.ts +67 -2
- package/dist/search/command-palette.js +147 -33
- package/dist/search/command-palette.js.map +1 -1
- package/dist/search/global-search.d.ts +166 -0
- package/dist/search/global-search.js +293 -0
- package/dist/search/global-search.js.map +1 -0
- package/dist/search/search-index.d.ts +105 -0
- package/dist/search/search-index.js +142 -0
- package/dist/search/search-index.js.map +1 -0
- package/dist/search.d.ts +3 -1
- package/dist/search.js +2 -0
- package/dist/search.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +10 -1
- package/dist/wizard/stepper-nav.js +3 -2
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +2 -2
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.js +1 -1
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/wizard-summary.js +3 -3
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/package.json +25 -12
- package/src/components/alert-banner.tsx +117 -18
- package/src/components/breadcrumbs.tsx +168 -0
- package/src/components/bulk-action-bar.tsx +256 -0
- package/src/components/chip.tsx +164 -13
- package/src/components/copy-button.tsx +29 -7
- package/src/components/data-table.tsx +81 -5
- package/src/components/date-picker.tsx +377 -118
- package/src/components/description-list.tsx +168 -15
- package/src/components/dialog-frame.tsx +7 -0
- package/src/components/disclosure.tsx +116 -28
- package/src/components/file-dropzone.tsx +9 -10
- package/src/components/floating-panel.tsx +46 -2
- package/src/components/full-bleed-dialog.tsx +42 -5
- package/src/components/list.tsx +417 -0
- package/src/components/menu-item.tsx +214 -0
- package/src/components/modal.tsx +80 -17
- package/src/components/page-contents.tsx +4 -4
- package/src/components/page-header.tsx +68 -0
- package/src/components/progress-bar.tsx +27 -3
- package/src/components/series-chart-labels.ts +4 -0
- package/src/components/series-chart.tsx +253 -3
- package/src/components/status-dot.tsx +99 -0
- package/src/components/table.tsx +91 -6
- package/src/components/text.tsx +89 -0
- package/src/components/toast.tsx +441 -0
- package/src/components/toggle-group.tsx +82 -3
- package/src/components/tooltip.tsx +186 -100
- package/src/components/ui.tsx +321 -41
- package/src/hooks/use-close-transition.ts +14 -5
- package/src/hooks/use-copy-to-clipboard.ts +1 -1
- package/src/hooks/use-overlay-history.ts +181 -4
- package/src/i18n/defaults.ts +10 -0
- package/src/i18n/kit-labels.tsx +10 -0
- package/src/i18n/locales/de.ts +30 -0
- package/src/i18n/locales/es.ts +30 -0
- package/src/i18n/locales/fr.ts +30 -0
- package/src/i18n/locales/hu.ts +30 -0
- package/src/i18n/locales/it.ts +30 -0
- package/src/i18n/locales/zh.ts +30 -0
- package/src/index.ts +30 -0
- package/src/lib/clipping.ts +16 -0
- package/src/search/command-palette.tsx +241 -31
- package/src/search/global-search.tsx +525 -0
- package/src/search/search-index.ts +295 -0
- package/src/search.ts +2 -0
- package/src/wizard/stepper-nav.tsx +13 -2
- package/src/wizard/types.ts +2 -2
- package/src/wizard/use-wizard.ts +3 -3
- package/src/wizard/wizard-summary.tsx +14 -10
- package/tokens.css +97 -0
|
@@ -6,13 +6,16 @@ import { dirOf, type Direction } from "../lib/direction";
|
|
|
6
6
|
import { addDaysIso, parseIsoDate } from "../lib/dates";
|
|
7
7
|
import {
|
|
8
8
|
DEFAULT_DATE_PICKER_LABELS,
|
|
9
|
+
DEFAULT_PICKER_SHEET_LABELS,
|
|
9
10
|
useKitLabels,
|
|
10
11
|
useKitLocale,
|
|
11
12
|
type DatePickerLabels,
|
|
12
13
|
} from "../i18n/kit-labels";
|
|
13
14
|
import { splitTriggerAria } from "./trigger-aria";
|
|
14
15
|
import type { TriggerAria } from "./trigger-aria";
|
|
15
|
-
import { Button, FieldLabel, FIELD_BASE, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from "./ui";
|
|
16
|
+
import { Button, FieldLabel, FIELD_BASE, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID, PHONE_QUERY } from "./ui";
|
|
17
|
+
import { FullBleedDialog } from "./full-bleed-dialog";
|
|
18
|
+
import { useMediaQuery } from "../hooks/use-media-query";
|
|
16
19
|
import { MiniCalendar, type MiniCalendarProps } from "./mini-calendar";
|
|
17
20
|
import { Popover } from "./popover";
|
|
18
21
|
import { Tooltip } from "./tooltip";
|
|
@@ -66,6 +69,51 @@ function formatDate(iso: string, locale: string | undefined, options?: Intl.Date
|
|
|
66
69
|
return parseIsoDate(iso)?.toLocaleDateString(locale, options) ?? "";
|
|
67
70
|
}
|
|
68
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Everything the kit's own trigger button carries, handed to a custom one
|
|
74
|
+
* ({@link DateRangePickerProps.renderTrigger}) to spread onto its `<button>`. Spread
|
|
75
|
+
* it WHOLE: the ref is how focus comes back when the panel closes, the id pair and
|
|
76
|
+
* `aria-labelledby` are the 0.5.1 naming (an external `<label htmlFor>`, a form
|
|
77
|
+
* library's `aria-describedby`), and `role`/`aria-haspopup`/`aria-controls`/
|
|
78
|
+
* `aria-expanded` are what tell a screen reader this opens a calendar and whether it
|
|
79
|
+
* is open. `className` is the kit's field look (42px with a label, `pe-9` for the
|
|
80
|
+
* glyph the field draws at its end) — merge yours after it with `cn`.
|
|
81
|
+
*/
|
|
82
|
+
export interface DateTriggerAttributes {
|
|
83
|
+
ref: RefObject<HTMLButtonElement | null>;
|
|
84
|
+
type: "button";
|
|
85
|
+
id?: string;
|
|
86
|
+
role: "combobox";
|
|
87
|
+
"aria-haspopup": "dialog";
|
|
88
|
+
"aria-controls": string;
|
|
89
|
+
"aria-expanded": boolean;
|
|
90
|
+
"aria-labelledby"?: string;
|
|
91
|
+
"aria-label"?: string;
|
|
92
|
+
"aria-describedby"?: string;
|
|
93
|
+
"aria-invalid"?: true;
|
|
94
|
+
disabled?: boolean;
|
|
95
|
+
onClick: () => void;
|
|
96
|
+
className: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** A custom trigger, as `DateField` calls it; each picker adapts it to its own props. */
|
|
100
|
+
type TriggerRenderer = (attrs: DateTriggerAttributes, valueId: string) => ReactNode;
|
|
101
|
+
|
|
102
|
+
/** A caller's trigger, as an element of its own: the attributes carry the trigger's
|
|
103
|
+
* ref, and a ref is handed to a child as a prop, not passed to a function in the
|
|
104
|
+
* middle of the parent's render. */
|
|
105
|
+
function CustomTrigger({
|
|
106
|
+
render,
|
|
107
|
+
attrs,
|
|
108
|
+
valueId,
|
|
109
|
+
}: {
|
|
110
|
+
render: TriggerRenderer;
|
|
111
|
+
attrs: DateTriggerAttributes;
|
|
112
|
+
valueId: string;
|
|
113
|
+
}) {
|
|
114
|
+
return render(attrs, valueId);
|
|
115
|
+
}
|
|
116
|
+
|
|
69
117
|
/**
|
|
70
118
|
* The field-shaped button that opens the calendar.
|
|
71
119
|
*
|
|
@@ -86,9 +134,12 @@ function DateFieldTrigger({
|
|
|
86
134
|
invalid,
|
|
87
135
|
panelId,
|
|
88
136
|
aria,
|
|
137
|
+
renderTrigger,
|
|
89
138
|
}: {
|
|
90
139
|
/** The caller's naming/description attributes, routed here from the field. */
|
|
91
140
|
aria: TriggerAria;
|
|
141
|
+
/** Draw the button yourself, with these attributes — see {@link DateTriggerAttributes}. */
|
|
142
|
+
renderTrigger?: TriggerRenderer;
|
|
92
143
|
open: boolean;
|
|
93
144
|
toggle: () => void;
|
|
94
145
|
triggerRef: RefObject<HTMLButtonElement | null>;
|
|
@@ -123,47 +174,55 @@ function DateFieldTrigger({
|
|
|
123
174
|
// is this trigger, every time, however the panel was opened.
|
|
124
175
|
}, [open, triggerRef]);
|
|
125
176
|
|
|
177
|
+
// One attribute object, worn either by the kit's own button below or by a caller's
|
|
178
|
+
// (`renderTrigger`) — so a custom trigger cannot quietly fall out of step with the
|
|
179
|
+
// naming and state this one announces.
|
|
180
|
+
const attrs: DateTriggerAttributes = {
|
|
181
|
+
ref: triggerRef,
|
|
182
|
+
type: "button",
|
|
183
|
+
disabled,
|
|
184
|
+
onClick: toggle,
|
|
185
|
+
// The name has to carry the VALUE. A bare `aria-label={label}` — which is what
|
|
186
|
+
// this was — replaces the button's text outright, so the one field in the form
|
|
187
|
+
// whose entire job is to show a date announced "Due date" and stopped there,
|
|
188
|
+
// and a screen-reader user could not read back what they had picked without
|
|
189
|
+
// opening the calendar and hunting for the selected day.
|
|
190
|
+
//
|
|
191
|
+
// Two ids rather than one composed string (`common.fieldValue`): "label: value"
|
|
192
|
+
// is a sentence, and a name reference is spoken as the two texts in order with
|
|
193
|
+
// no punctuation to translate at all. The hidden twin of the FieldLabel lives
|
|
194
|
+
// in DateField, next to the label it copies.
|
|
195
|
+
id: aria.id,
|
|
196
|
+
"aria-labelledby": aria["aria-label"] && !aria["aria-labelledby"] ? undefined : labelledBy,
|
|
197
|
+
"aria-label": aria["aria-label"],
|
|
198
|
+
"aria-describedby": aria["aria-describedby"],
|
|
199
|
+
// `role="combobox"` on a button that opens a calendar is the APG date-picker
|
|
200
|
+
// shape, and it is what makes the next two lines legal: `button` supports
|
|
201
|
+
// neither `aria-expanded` nor `aria-invalid`, so the previous markup set an
|
|
202
|
+
// invalid state that announced nothing (ESLint's `role-supports-aria-props`).
|
|
203
|
+
//
|
|
204
|
+
// `aria-haspopup="dialog"` is now honest — it was not when this comment first
|
|
205
|
+
// said so. `Popover` gained a real `role="dialog"` in the same wave, so the
|
|
206
|
+
// trigger's promise and the panel's role finally agree. The phone sheet is a
|
|
207
|
+
// `role="dialog"` too, and carries the same id.
|
|
208
|
+
role: "combobox",
|
|
209
|
+
"aria-haspopup": "dialog",
|
|
210
|
+
"aria-controls": panelId,
|
|
211
|
+
"aria-expanded": open,
|
|
212
|
+
"aria-invalid":
|
|
213
|
+
invalid || aria["aria-invalid"] === true || aria["aria-invalid"] === "true" || undefined,
|
|
214
|
+
className: cn(
|
|
215
|
+
FIELD_TRIGGER,
|
|
216
|
+
"pe-9",
|
|
217
|
+
padded && FIELD_FLOATING_PAD,
|
|
218
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
219
|
+
invalid && FIELD_INVALID,
|
|
220
|
+
),
|
|
221
|
+
};
|
|
222
|
+
if (renderTrigger) return <CustomTrigger render={renderTrigger} attrs={attrs} valueId={valueId} />;
|
|
223
|
+
|
|
126
224
|
return (
|
|
127
|
-
<button
|
|
128
|
-
ref={triggerRef}
|
|
129
|
-
type="button"
|
|
130
|
-
disabled={disabled}
|
|
131
|
-
onClick={toggle}
|
|
132
|
-
// The name has to carry the VALUE. A bare `aria-label={label}` — which is what
|
|
133
|
-
// this was — replaces the button's text outright, so the one field in the form
|
|
134
|
-
// whose entire job is to show a date announced "Due date" and stopped there,
|
|
135
|
-
// and a screen-reader user could not read back what they had picked without
|
|
136
|
-
// opening the calendar and hunting for the selected day.
|
|
137
|
-
//
|
|
138
|
-
// Two ids rather than one composed string (`common.fieldValue`): "label: value"
|
|
139
|
-
// is a sentence, and a name reference is spoken as the two texts in order with
|
|
140
|
-
// no punctuation to translate at all. The hidden twin of the FieldLabel lives
|
|
141
|
-
// in DateField, next to the label it copies.
|
|
142
|
-
id={aria.id}
|
|
143
|
-
aria-labelledby={aria["aria-label"] && !aria["aria-labelledby"] ? undefined : labelledBy}
|
|
144
|
-
aria-label={aria["aria-label"]}
|
|
145
|
-
aria-describedby={aria["aria-describedby"]}
|
|
146
|
-
// `role="combobox"` on a button that opens a calendar is the APG date-picker
|
|
147
|
-
// shape, and it is what makes the next two lines legal: `button` supports
|
|
148
|
-
// neither `aria-expanded` nor `aria-invalid`, so the previous markup set an
|
|
149
|
-
// invalid state that announced nothing (ESLint's `role-supports-aria-props`).
|
|
150
|
-
//
|
|
151
|
-
// `aria-haspopup="dialog"` is now honest — it was not when this comment first
|
|
152
|
-
// said so. `Popover` gained a real `role="dialog"` in the same wave, so the
|
|
153
|
-
// trigger's promise and the panel's role finally agree.
|
|
154
|
-
role="combobox"
|
|
155
|
-
aria-haspopup="dialog"
|
|
156
|
-
aria-controls={panelId}
|
|
157
|
-
aria-expanded={open}
|
|
158
|
-
aria-invalid={invalid || aria["aria-invalid"] === true || aria["aria-invalid"] === "true" || undefined}
|
|
159
|
-
className={cn(
|
|
160
|
-
FIELD_TRIGGER,
|
|
161
|
-
"pe-9",
|
|
162
|
-
padded && FIELD_FLOATING_PAD,
|
|
163
|
-
disabled && "cursor-not-allowed opacity-50",
|
|
164
|
-
invalid && FIELD_INVALID,
|
|
165
|
-
)}
|
|
166
|
-
>
|
|
225
|
+
<button {...attrs}>
|
|
167
226
|
<span id={valueId} className={cn("truncate", !hasValue && "text-[var(--text-placeholder)]")}>
|
|
168
227
|
{/* `|| " "` (a NON-BREAKING space) — triggerText is "" when there is no value and no
|
|
169
228
|
placeholder was passed. An empty span has no line box, so the
|
|
@@ -184,6 +243,24 @@ function DateFieldTrigger({
|
|
|
184
243
|
);
|
|
185
244
|
}
|
|
186
245
|
|
|
246
|
+
/**
|
|
247
|
+
* How a panel's body and its action row are put on screen — the popover stacks them,
|
|
248
|
+
* the phone sheet pins the actions in its footer. Handed to the panel rather than
|
|
249
|
+
* applied around it because the actions belong to the panel's own draft state
|
|
250
|
+
* (`RangePanel`), while the frame they sit in belongs to the field.
|
|
251
|
+
*/
|
|
252
|
+
type PanelFrame = (body: ReactNode, actions?: ReactNode) => ReactNode;
|
|
253
|
+
|
|
254
|
+
const popoverFrame: PanelFrame = (body, actions) =>
|
|
255
|
+
actions ? (
|
|
256
|
+
<div className="flex flex-col gap-2">
|
|
257
|
+
{body}
|
|
258
|
+
<div className="flex items-center justify-end gap-2 border-t border-[var(--border)] pt-2">{actions}</div>
|
|
259
|
+
</div>
|
|
260
|
+
) : (
|
|
261
|
+
body
|
|
262
|
+
);
|
|
263
|
+
|
|
187
264
|
/** A field-styled trigger that opens a portalled MiniCalendar. Shared by the
|
|
188
265
|
* single- and range-date pickers below. */
|
|
189
266
|
function DateField({
|
|
@@ -198,6 +275,9 @@ function DateField({
|
|
|
198
275
|
width,
|
|
199
276
|
onClear,
|
|
200
277
|
invalid,
|
|
278
|
+
sheet = false,
|
|
279
|
+
sheetBackCloses = true,
|
|
280
|
+
renderTrigger,
|
|
201
281
|
children,
|
|
202
282
|
...rest
|
|
203
283
|
}: Omit<ComponentPropsWithoutRef<"div">, "children"> & {
|
|
@@ -215,7 +295,13 @@ function DateField({
|
|
|
215
295
|
/** Popover panel width; omit for the default (a bare calendar). */
|
|
216
296
|
width?: number;
|
|
217
297
|
onClear: () => void;
|
|
218
|
-
|
|
298
|
+
/** Open as a full-screen sheet instead of the popover — the picker decides when
|
|
299
|
+
* (below {@link PHONE_QUERY}). */
|
|
300
|
+
sheet?: boolean;
|
|
301
|
+
/** The sheet's `FullBleedDialog backCloses`. */
|
|
302
|
+
sheetBackCloses?: boolean;
|
|
303
|
+
renderTrigger?: TriggerRenderer;
|
|
304
|
+
children: (close: () => void, frame: PanelFrame) => ReactNode;
|
|
219
305
|
}) {
|
|
220
306
|
const showClear = Boolean(clearable && hasValue && !disabled);
|
|
221
307
|
const [aria, wrapperRest] = splitTriggerAria(rest);
|
|
@@ -233,6 +319,83 @@ function DateField({
|
|
|
233
319
|
// its own interactive "?" hint in it, and naming a button with that reads the hint
|
|
234
320
|
// out as part of the field's name.
|
|
235
321
|
const named = typeof label === "string";
|
|
322
|
+
// The sheet's open flag. Only the phone branch owns one: on desktop `Popover` owns
|
|
323
|
+
// it, so the two can never disagree about what is on screen.
|
|
324
|
+
const [sheetOpen, setSheetOpen] = useState(false);
|
|
325
|
+
const sheetTriggerRef = useRef<HTMLButtonElement>(null);
|
|
326
|
+
const closeSheet = () => setSheetOpen(false);
|
|
327
|
+
const sheetLabels = useKitLabels("pickerSheet", DEFAULT_PICKER_SHEET_LABELS);
|
|
328
|
+
const sheetFrame: PanelFrame = (body, actions) => (
|
|
329
|
+
<FullBleedDialog
|
|
330
|
+
open
|
|
331
|
+
onClose={closeSheet}
|
|
332
|
+
// The same id the popover panel wears, so the trigger's `aria-controls` holds in
|
|
333
|
+
// both presentations; named the way the popover is.
|
|
334
|
+
id={panelId}
|
|
335
|
+
aria-label={panelLabel}
|
|
336
|
+
header={panelLabel}
|
|
337
|
+
// `pickerSheet.close`: the one "close this full-screen picker" string the kit
|
|
338
|
+
// already translates, rather than a second key saying the same thing.
|
|
339
|
+
closeLabel={sheetLabels.close}
|
|
340
|
+
backCloses={sheetBackCloses}
|
|
341
|
+
dir={dir}
|
|
342
|
+
// Portalled to <body>, the sheet is not inside the field's wrapper, so a
|
|
343
|
+
// document-level "outside click" listener — a Popover or dropdown this field
|
|
344
|
+
// sits in — would read a tap on a day as outside and unmount the cell before
|
|
345
|
+
// its click (Keksdose dev#477, the fix `PickerSheet` carries).
|
|
346
|
+
onMouseDown={(e) => e.stopPropagation()}
|
|
347
|
+
footer={actions}
|
|
348
|
+
>
|
|
349
|
+
{body}
|
|
350
|
+
</FullBleedDialog>
|
|
351
|
+
);
|
|
352
|
+
const fieldTrigger = ({
|
|
353
|
+
open,
|
|
354
|
+
toggle,
|
|
355
|
+
ref,
|
|
356
|
+
}: {
|
|
357
|
+
open: boolean;
|
|
358
|
+
toggle: () => void;
|
|
359
|
+
ref: RefObject<HTMLButtonElement | null>;
|
|
360
|
+
}) => (
|
|
361
|
+
<DateFieldTrigger
|
|
362
|
+
open={open}
|
|
363
|
+
toggle={() => {
|
|
364
|
+
setDir(dirOf(rootRef.current));
|
|
365
|
+
toggle();
|
|
366
|
+
}}
|
|
367
|
+
triggerRef={ref}
|
|
368
|
+
triggerText={triggerText}
|
|
369
|
+
hasValue={hasValue}
|
|
370
|
+
// ALWAYS a name reference, never `undefined`. A `<button>` takes its
|
|
371
|
+
// accessible name from its contents, so an unlabelled trigger used to
|
|
372
|
+
// announce its own date text for free. `role="combobox"` does not —
|
|
373
|
+
// content is excluded from name computation for that role — so leaving
|
|
374
|
+
// this undefined made an unlabelled date field announce nothing at all.
|
|
375
|
+
// Named: "label, value". Unnamed: the value alone, which is what the
|
|
376
|
+
// button was saying before.
|
|
377
|
+
//
|
|
378
|
+
// A caller's own reference comes first. And when the caller gives the field
|
|
379
|
+
// an `id` (so an external `<label htmlFor>` can point at it), the trigger
|
|
380
|
+
// lists ITSELF first: a self-reference in `aria-labelledby` is resolved
|
|
381
|
+
// from the element's native label (accname 2B → 2D), so "Due date" from
|
|
382
|
+
// that <label> is spoken before the value, instead of being overridden.
|
|
383
|
+
labelledBy={[
|
|
384
|
+
aria["aria-labelledby"],
|
|
385
|
+
named ? labelId : !aria["aria-labelledby"] && aria.id ? aria.id : undefined,
|
|
386
|
+
valueId,
|
|
387
|
+
]
|
|
388
|
+
.filter(Boolean)
|
|
389
|
+
.join(" ")}
|
|
390
|
+
aria={aria}
|
|
391
|
+
panelId={panelId}
|
|
392
|
+
valueId={valueId}
|
|
393
|
+
padded={label !== undefined}
|
|
394
|
+
disabled={disabled}
|
|
395
|
+
invalid={invalid}
|
|
396
|
+
renderTrigger={renderTrigger}
|
|
397
|
+
/>
|
|
398
|
+
);
|
|
236
399
|
return (
|
|
237
400
|
// The caller's attributes land here, on the field's own box — the trigger inside is
|
|
238
401
|
// named by `aria-labelledby` and must keep the id pair it is given.
|
|
@@ -250,54 +413,26 @@ function DateField({
|
|
|
250
413
|
{label}
|
|
251
414
|
</span>
|
|
252
415
|
)}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
// content is excluded from name computation for that role — so leaving
|
|
274
|
-
// this undefined made an unlabelled date field announce nothing at all.
|
|
275
|
-
// Named: "label, value". Unnamed: the value alone, which is what the
|
|
276
|
-
// button was saying before.
|
|
277
|
-
//
|
|
278
|
-
// A caller's own reference comes first. And when the caller gives the field
|
|
279
|
-
// an `id` (so an external `<label htmlFor>` can point at it), the trigger
|
|
280
|
-
// lists ITSELF first: a self-reference in `aria-labelledby` is resolved
|
|
281
|
-
// from the element's native label (accname 2B → 2D), so "Due date" from
|
|
282
|
-
// that <label> is spoken before the value, instead of being overridden.
|
|
283
|
-
labelledBy={[
|
|
284
|
-
aria["aria-labelledby"],
|
|
285
|
-
named ? labelId : !aria["aria-labelledby"] && aria.id ? aria.id : undefined,
|
|
286
|
-
valueId,
|
|
287
|
-
]
|
|
288
|
-
.filter(Boolean)
|
|
289
|
-
.join(" ")}
|
|
290
|
-
aria={aria}
|
|
291
|
-
panelId={panelId}
|
|
292
|
-
valueId={valueId}
|
|
293
|
-
padded={label !== undefined}
|
|
294
|
-
disabled={disabled}
|
|
295
|
-
invalid={invalid}
|
|
296
|
-
/>
|
|
297
|
-
)}
|
|
298
|
-
>
|
|
299
|
-
{(close) => children(close)}
|
|
300
|
-
</Popover>
|
|
416
|
+
{sheet ? (
|
|
417
|
+
<>
|
|
418
|
+
{fieldTrigger({ open: sheetOpen, toggle: () => setSheetOpen((v) => !v), ref: sheetTriggerRef })}
|
|
419
|
+
{/* Mounted only while open, like the popover's children: the panel's draft is
|
|
420
|
+
born with it, so every open starts again from the committed value. */}
|
|
421
|
+
{sheetOpen && children(closeSheet, sheetFrame)}
|
|
422
|
+
</>
|
|
423
|
+
) : (
|
|
424
|
+
<Popover
|
|
425
|
+
width={width}
|
|
426
|
+
panelId={panelId}
|
|
427
|
+
// Named for what it is. Unnamed, it fell back to `popover.panel`, and a date
|
|
428
|
+
// field announced its calendar as "Popover" — in English, in every language.
|
|
429
|
+
labels={{ panel: panelLabel }}
|
|
430
|
+
dir={dir}
|
|
431
|
+
trigger={fieldTrigger}
|
|
432
|
+
>
|
|
433
|
+
{(close) => children(close, popoverFrame)}
|
|
434
|
+
</Popover>
|
|
435
|
+
)}
|
|
301
436
|
{showClear ? (
|
|
302
437
|
<button
|
|
303
438
|
type="button"
|
|
@@ -612,6 +747,66 @@ export interface DateRangePickerProps extends DatePickerBaseProps {
|
|
|
612
747
|
preset?: string | null;
|
|
613
748
|
/** See {@link DateRangeCommit}. Default `"immediate"`. */
|
|
614
749
|
commit?: DateRangeCommit;
|
|
750
|
+
/**
|
|
751
|
+
* Draw the trigger yourself. keksdose's report range field
|
|
752
|
+
* (reports/report-range-field.tsx, "Why this is app-level") is why: its trigger
|
|
753
|
+
* NAMES the active preset ("Last 3 months", the window as a muted suffix) where the
|
|
754
|
+
* kit's shows two dates, sits inside a Tooltip, and is squared off on one side so the
|
|
755
|
+
* granularity control can join it flush at the field's 42px.
|
|
756
|
+
*
|
|
757
|
+
* Spread `props.triggerProps` onto a `<button>` whole and put `props.valueProps` on
|
|
758
|
+
* the element that shows the value — see {@link DateTriggerAttributes} for what each
|
|
759
|
+
* part is for. The field around it (label, hidden name twin, clear/calendar glyph,
|
|
760
|
+
* popover or phone sheet) is unchanged.
|
|
761
|
+
*/
|
|
762
|
+
renderTrigger?: (props: DateRangeTriggerRenderProps) => ReactNode;
|
|
763
|
+
/**
|
|
764
|
+
* Below {@link PHONE_QUERY} the panel opens as a full-screen sheet (`FullBleedDialog`)
|
|
765
|
+
* with presets in a grid above the calendar and Apply pinned in the footer, instead
|
|
766
|
+
* of the 440px popover that hung off a 360px screen (keksdose's report range field,
|
|
767
|
+
* which hand-rolled exactly this). This is its `backCloses`: on by default, so Back
|
|
768
|
+
* dismisses the sheet; off for a caller whose commit rewrites the URL with
|
|
769
|
+
* `replaceState` in the same tick — keksdose's `?preset/from/to` — where the router
|
|
770
|
+
* would overwrite the sheet's history marker.
|
|
771
|
+
*/
|
|
772
|
+
sheetBackCloses?: boolean;
|
|
773
|
+
/**
|
|
774
|
+
* With `commit="apply"`: a line above the calendar saying what Apply would commit —
|
|
775
|
+
* keksdose's report range writes "Custom · 1 Mar 2026 – …" there
|
|
776
|
+
* (report-range-field.tsx), the one place a preset armed and then nudged by a day is
|
|
777
|
+
* seen to have become "Custom", and a half-made range to still lack its end. Called
|
|
778
|
+
* with the DRAFT on every change, in the popover and the phone sheet alike; `preset`
|
|
779
|
+
* is the preset the column marks for it (none once a day was picked by hand), `to` is
|
|
780
|
+
* `""` until the second click. The line is a polite live region, so a screen reader
|
|
781
|
+
* hears the draft change as the calendar is used.
|
|
782
|
+
*
|
|
783
|
+
* Ignored in `"immediate"` mode, where there is no draft: every click is the value.
|
|
784
|
+
*/
|
|
785
|
+
renderDraftSummary?: (draft: DateRangeDraftSummary) => ReactNode;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
/** What {@link DateRangePickerProps.renderDraftSummary} is called with. */
|
|
789
|
+
export interface DateRangeDraftSummary {
|
|
790
|
+
from: string;
|
|
791
|
+
to: string;
|
|
792
|
+
/** The preset the column marks for the draft, if any. */
|
|
793
|
+
preset: DateRangePickerPreset | undefined;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/** What {@link DateRangePickerProps.renderTrigger} is called with. */
|
|
797
|
+
export interface DateRangeTriggerRenderProps {
|
|
798
|
+
/** Spread onto the `<button>`, whole. Merge your class after `triggerProps.className`. */
|
|
799
|
+
triggerProps: DateTriggerAttributes;
|
|
800
|
+
/** Put on the element showing the value: the trigger is named "label, value" by
|
|
801
|
+
* reference to this id. Without it the name is the label alone. */
|
|
802
|
+
valueProps: { id: string };
|
|
803
|
+
open: boolean;
|
|
804
|
+
from: string;
|
|
805
|
+
to: string;
|
|
806
|
+
/** The preset the column marks for the committed range, if any — the one to name. */
|
|
807
|
+
preset: DateRangePickerPreset | undefined;
|
|
808
|
+
/** What the kit's own trigger would show: the formatted range, or the placeholder. */
|
|
809
|
+
text: string;
|
|
615
810
|
}
|
|
616
811
|
|
|
617
812
|
interface RangeDraft {
|
|
@@ -648,11 +843,15 @@ function PresetColumn({
|
|
|
648
843
|
marked,
|
|
649
844
|
label,
|
|
650
845
|
onPick,
|
|
846
|
+
sheet,
|
|
651
847
|
}: {
|
|
652
848
|
presets: readonly DateRangePickerPreset[];
|
|
653
849
|
marked: number;
|
|
654
850
|
label: string;
|
|
655
851
|
onPick: (p: DateRangePickerPreset) => void;
|
|
852
|
+
/** The phone sheet's shape: a two-column grid ABOVE the calendar with 44px rows —
|
|
853
|
+
* a 128px column beside a month grid leaves the grid ~200px on a 360px screen. */
|
|
854
|
+
sheet?: boolean;
|
|
656
855
|
}) {
|
|
657
856
|
return (
|
|
658
857
|
// `border-e`/`pe`, not `-r`: the preset column is on the START side, and the rule
|
|
@@ -660,7 +859,11 @@ function PresetColumn({
|
|
|
660
859
|
<div
|
|
661
860
|
role="group"
|
|
662
861
|
aria-label={label}
|
|
663
|
-
className=
|
|
862
|
+
className={
|
|
863
|
+
sheet
|
|
864
|
+
? "grid grid-cols-2 gap-0.5"
|
|
865
|
+
: "flex w-32 shrink-0 flex-col gap-0.5 border-e border-[var(--border)] pe-2"
|
|
866
|
+
}
|
|
664
867
|
>
|
|
665
868
|
{presets.map((p, i) => {
|
|
666
869
|
const selected = i === marked;
|
|
@@ -672,7 +875,9 @@ function PresetColumn({
|
|
|
672
875
|
data-preset={p.id}
|
|
673
876
|
onClick={() => onPick(p)}
|
|
674
877
|
className={cn(
|
|
675
|
-
"rounded px-2
|
|
878
|
+
"rounded px-2 text-start",
|
|
879
|
+
// 44px on a phone: the kit's touch-target size (`SHEET_ROW_CLASS`).
|
|
880
|
+
sheet ? "min-h-11 py-2 text-sm" : "py-1.5 text-xs",
|
|
676
881
|
selected
|
|
677
882
|
? "bg-[var(--bg-active)] font-medium text-[var(--text-primary)]"
|
|
678
883
|
: "text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]",
|
|
@@ -700,9 +905,12 @@ function RangePanel({
|
|
|
700
905
|
controlled,
|
|
701
906
|
commit,
|
|
702
907
|
close,
|
|
908
|
+
frame,
|
|
909
|
+
sheet,
|
|
703
910
|
commitRange,
|
|
704
911
|
calendarProps,
|
|
705
912
|
labels,
|
|
913
|
+
renderDraftSummary,
|
|
706
914
|
}: {
|
|
707
915
|
from: string;
|
|
708
916
|
to: string;
|
|
@@ -711,9 +919,13 @@ function RangePanel({
|
|
|
711
919
|
controlled: boolean;
|
|
712
920
|
commit: DateRangeCommit;
|
|
713
921
|
close: () => void;
|
|
922
|
+
/** Where the body and the Apply row go — see `PanelFrame`. */
|
|
923
|
+
frame: PanelFrame;
|
|
924
|
+
sheet: boolean;
|
|
714
925
|
commitRange: (from: string, to: string, presetId: string | undefined) => void;
|
|
715
926
|
calendarProps: Pick<MiniCalendarProps, "locale" | "min" | "max" | "labels">;
|
|
716
927
|
labels: DatePickerLabels;
|
|
928
|
+
renderDraftSummary?: DateRangePickerProps["renderDraftSummary"];
|
|
717
929
|
}) {
|
|
718
930
|
const drafting = commit === "apply";
|
|
719
931
|
const [draft, setDraft] = useState<RangeDraft>({
|
|
@@ -728,7 +940,12 @@ function RangePanel({
|
|
|
728
940
|
: -1;
|
|
729
941
|
const complete = Boolean(draft.from && draft.to);
|
|
730
942
|
|
|
731
|
-
const
|
|
943
|
+
const summary =
|
|
944
|
+
drafting && renderDraftSummary
|
|
945
|
+
? renderDraftSummary({ from: draft.from, to: draft.to, preset: presets?.[marked] })
|
|
946
|
+
: null;
|
|
947
|
+
|
|
948
|
+
const picker = (
|
|
732
949
|
<MiniCalendar
|
|
733
950
|
{...calendarProps}
|
|
734
951
|
focusOnOpen
|
|
@@ -745,11 +962,30 @@ function RangePanel({
|
|
|
745
962
|
}}
|
|
746
963
|
/>
|
|
747
964
|
);
|
|
965
|
+
// The summary heads the CALENDAR's column, not the panel: beside a preset column it
|
|
966
|
+
// reads as the calendar's caption, and in the sheet it sits between the presets and
|
|
967
|
+
// the month it describes. `null` renders no line — a caller may opt out per draft —
|
|
968
|
+
// but keeps the wrapper, so the calendar is not remounted (and its month and focus
|
|
969
|
+
// lost) when a line comes or goes.
|
|
970
|
+
const calendar =
|
|
971
|
+
drafting && renderDraftSummary ? (
|
|
972
|
+
<div className="flex flex-col gap-2">
|
|
973
|
+
{summary != null && (
|
|
974
|
+
<div aria-live="polite" data-draft-summary="" className="text-xs text-[var(--text-muted)]">
|
|
975
|
+
{summary}
|
|
976
|
+
</div>
|
|
977
|
+
)}
|
|
978
|
+
{picker}
|
|
979
|
+
</div>
|
|
980
|
+
) : (
|
|
981
|
+
picker
|
|
982
|
+
);
|
|
748
983
|
|
|
749
984
|
const body =
|
|
750
985
|
presets && presets.length > 0 ? (
|
|
751
|
-
<div className="flex gap-3">
|
|
986
|
+
<div className={sheet ? "flex flex-col gap-3" : "flex gap-3"}>
|
|
752
987
|
<PresetColumn
|
|
988
|
+
sheet={sheet}
|
|
753
989
|
presets={presets}
|
|
754
990
|
marked={marked}
|
|
755
991
|
label={labels.presets}
|
|
@@ -770,29 +1006,30 @@ function RangePanel({
|
|
|
770
1006
|
calendar
|
|
771
1007
|
);
|
|
772
1008
|
|
|
773
|
-
if (!drafting) return body;
|
|
774
|
-
return (
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
1009
|
+
if (!drafting) return frame(body);
|
|
1010
|
+
return frame(
|
|
1011
|
+
body,
|
|
1012
|
+
<>
|
|
1013
|
+
{/* `flex-1` in the sheet: two thumb-wide halves of the footer, not two small
|
|
1014
|
+
buttons in its corner. */}
|
|
1015
|
+
<Button type="button" variant="ghost" className={sheet ? "flex-1" : undefined} onClick={close}>
|
|
1016
|
+
{labels.cancel}
|
|
1017
|
+
</Button>
|
|
1018
|
+
<Button
|
|
1019
|
+
type="button"
|
|
1020
|
+
className={sheet ? "flex-1" : undefined}
|
|
1021
|
+
// A half-made `(from, "")` would commit a window with no end — a blank
|
|
1022
|
+
// report, one click into a two-click gesture.
|
|
1023
|
+
disabled={!complete}
|
|
1024
|
+
onClick={() => {
|
|
1025
|
+
if (!complete) return;
|
|
1026
|
+
commitRange(draft.from, draft.to, draft.presetId);
|
|
1027
|
+
close();
|
|
1028
|
+
}}
|
|
1029
|
+
>
|
|
1030
|
+
{labels.apply}
|
|
1031
|
+
</Button>
|
|
1032
|
+
</>,
|
|
796
1033
|
);
|
|
797
1034
|
}
|
|
798
1035
|
|
|
@@ -813,6 +1050,9 @@ export function DateRangePicker({
|
|
|
813
1050
|
presets,
|
|
814
1051
|
preset,
|
|
815
1052
|
commit = "immediate",
|
|
1053
|
+
renderTrigger,
|
|
1054
|
+
sheetBackCloses,
|
|
1055
|
+
renderDraftSummary,
|
|
816
1056
|
calendarLabels,
|
|
817
1057
|
label,
|
|
818
1058
|
clearable,
|
|
@@ -837,6 +1077,7 @@ export function DateRangePicker({
|
|
|
837
1077
|
: `${a}${separator}…`
|
|
838
1078
|
: (placeholder ?? "");
|
|
839
1079
|
const hasPresets = Boolean(presets && presets.length > 0);
|
|
1080
|
+
const sheet = useMediaQuery(PHONE_QUERY, false);
|
|
840
1081
|
const commitRange = (f: string, t: string, presetId: string | undefined) => {
|
|
841
1082
|
setOwnPreset(presetId);
|
|
842
1083
|
// Two arguments when no preset is involved — exactly the 0.7 call, so a caller's
|
|
@@ -858,8 +1099,23 @@ export function DateRangePicker({
|
|
|
858
1099
|
hasValue={Boolean(from || to)}
|
|
859
1100
|
triggerText={triggerText}
|
|
860
1101
|
onClear={() => commitRange("", "", undefined)}
|
|
1102
|
+
sheet={sheet}
|
|
1103
|
+
sheetBackCloses={sheetBackCloses}
|
|
1104
|
+
renderTrigger={
|
|
1105
|
+
renderTrigger &&
|
|
1106
|
+
((triggerProps, valueId) =>
|
|
1107
|
+
renderTrigger({
|
|
1108
|
+
triggerProps,
|
|
1109
|
+
valueProps: { id: valueId },
|
|
1110
|
+
open: triggerProps["aria-expanded"],
|
|
1111
|
+
from,
|
|
1112
|
+
to,
|
|
1113
|
+
preset: presets?.[markedPreset(presets, from, to, activeId, controlled)],
|
|
1114
|
+
text: triggerText,
|
|
1115
|
+
}))
|
|
1116
|
+
}
|
|
861
1117
|
>
|
|
862
|
-
{(close) => (
|
|
1118
|
+
{(close, frame) => (
|
|
863
1119
|
<RangePanel
|
|
864
1120
|
from={from}
|
|
865
1121
|
to={to}
|
|
@@ -868,9 +1124,12 @@ export function DateRangePicker({
|
|
|
868
1124
|
controlled={controlled}
|
|
869
1125
|
commit={commit}
|
|
870
1126
|
close={close}
|
|
1127
|
+
frame={frame}
|
|
1128
|
+
sheet={sheet}
|
|
871
1129
|
commitRange={commitRange}
|
|
872
1130
|
calendarProps={{ locale, min, max, labels: calendarLabels }}
|
|
873
1131
|
labels={text}
|
|
1132
|
+
renderDraftSummary={renderDraftSummary}
|
|
874
1133
|
/>
|
|
875
1134
|
)}
|
|
876
1135
|
</DateField>
|