@eifi1/ui-kit 0.8.0 → 0.9.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.
Files changed (107) hide show
  1. package/README.md +4 -0
  2. package/dist/components/amount-input.d.ts +2 -0
  3. package/dist/components/calculator.d.ts +2 -0
  4. package/dist/components/chip.d.ts +27 -5
  5. package/dist/components/chip.js +6 -2
  6. package/dist/components/chip.js.map +1 -1
  7. package/dist/components/data-table-filter-popover.d.ts +1 -1
  8. package/dist/components/data-table-filters.d.ts +1 -1
  9. package/dist/components/data-table.d.ts +1 -1
  10. package/dist/components/data-table.js +122 -91
  11. package/dist/components/data-table.js.map +1 -1
  12. package/dist/components/date-picker.d.ts +69 -3
  13. package/dist/components/date-picker.js +152 -65
  14. package/dist/components/date-picker.js.map +1 -1
  15. package/dist/components/disclosure.d.ts +11 -2
  16. package/dist/components/disclosure.js +10 -4
  17. package/dist/components/disclosure.js.map +1 -1
  18. package/dist/components/floating-panel.d.ts +29 -2
  19. package/dist/components/floating-panel.js +16 -2
  20. package/dist/components/floating-panel.js.map +1 -1
  21. package/dist/components/full-bleed-dialog.js +3 -1
  22. package/dist/components/full-bleed-dialog.js.map +1 -1
  23. package/dist/components/number-field.d.ts +2 -0
  24. package/dist/components/number-input.d.ts +2 -0
  25. package/dist/components/numpad-sheet.d.ts +2 -0
  26. package/dist/components/progress-bar.d.ts +16 -2
  27. package/dist/components/progress-bar.js +4 -2
  28. package/dist/components/progress-bar.js.map +1 -1
  29. package/dist/components/treemap.js +4 -1
  30. package/dist/components/treemap.js.map +1 -1
  31. package/dist/components/ui.d.ts +44 -14
  32. package/dist/components/ui.js +28 -22
  33. package/dist/components/ui.js.map +1 -1
  34. package/dist/components/use-table-state.d.ts +1 -1
  35. package/dist/{data-table-filters-CF1PXqjQ.d.ts → data-table-filters-Dh9uF_S-.d.ts} +33 -2
  36. package/dist/data-table.d.ts +1 -1
  37. package/dist/hooks/use-overlay-history.js +84 -4
  38. package/dist/hooks/use-overlay-history.js.map +1 -1
  39. package/dist/i18n/defaults.d.ts +2 -0
  40. package/dist/i18n/defaults.js +2 -0
  41. package/dist/i18n/defaults.js.map +1 -1
  42. package/dist/i18n/kit-labels.d.ts +3 -0
  43. package/dist/i18n/kit-labels.js.map +1 -1
  44. package/dist/i18n/locales/de-CH-informal.d.ts +2 -0
  45. package/dist/i18n/locales/de-CH.d.ts +2 -0
  46. package/dist/i18n/locales/de-informal.d.ts +2 -0
  47. package/dist/i18n/locales/de.d.ts +2 -0
  48. package/dist/i18n/locales/de.js +10 -0
  49. package/dist/i18n/locales/de.js.map +1 -1
  50. package/dist/i18n/locales/es.d.ts +2 -0
  51. package/dist/i18n/locales/es.js +10 -0
  52. package/dist/i18n/locales/es.js.map +1 -1
  53. package/dist/i18n/locales/fr.d.ts +2 -0
  54. package/dist/i18n/locales/fr.js +10 -0
  55. package/dist/i18n/locales/fr.js.map +1 -1
  56. package/dist/i18n/locales/hu.d.ts +2 -0
  57. package/dist/i18n/locales/hu.js +10 -0
  58. package/dist/i18n/locales/hu.js.map +1 -1
  59. package/dist/i18n/locales/it.d.ts +2 -0
  60. package/dist/i18n/locales/it.js +10 -0
  61. package/dist/i18n/locales/it.js.map +1 -1
  62. package/dist/i18n/locales/zh.d.ts +2 -0
  63. package/dist/i18n/locales/zh.js +10 -0
  64. package/dist/i18n/locales/zh.js.map +1 -1
  65. package/dist/index.d.ts +5 -3
  66. package/dist/index.js +2 -0
  67. package/dist/index.js.map +1 -1
  68. package/dist/search/command-palette.d.ts +49 -1
  69. package/dist/search/command-palette.js +132 -29
  70. package/dist/search/command-palette.js.map +1 -1
  71. package/dist/search/global-search.d.ts +141 -0
  72. package/dist/search/global-search.js +277 -0
  73. package/dist/search/global-search.js.map +1 -0
  74. package/dist/search/search-index.d.ts +105 -0
  75. package/dist/search/search-index.js +142 -0
  76. package/dist/search/search-index.js.map +1 -0
  77. package/dist/search.d.ts +2 -0
  78. package/dist/search.js +2 -0
  79. package/dist/search.js.map +1 -1
  80. package/dist/wizard/stepper-nav.d.ts +10 -1
  81. package/dist/wizard/stepper-nav.js +2 -1
  82. package/dist/wizard/stepper-nav.js.map +1 -1
  83. package/package.json +12 -3
  84. package/src/components/chip.tsx +36 -6
  85. package/src/components/data-table.tsx +81 -5
  86. package/src/components/date-picker.tsx +328 -117
  87. package/src/components/disclosure.tsx +24 -8
  88. package/src/components/floating-panel.tsx +46 -2
  89. package/src/components/full-bleed-dialog.tsx +7 -2
  90. package/src/components/progress-bar.tsx +27 -3
  91. package/src/components/treemap.tsx +3 -0
  92. package/src/components/ui.tsx +95 -37
  93. package/src/hooks/use-overlay-history.ts +181 -4
  94. package/src/i18n/defaults.ts +2 -0
  95. package/src/i18n/kit-labels.tsx +2 -0
  96. package/src/i18n/locales/de.ts +10 -0
  97. package/src/i18n/locales/es.ts +10 -0
  98. package/src/i18n/locales/fr.ts +10 -0
  99. package/src/i18n/locales/hu.ts +10 -0
  100. package/src/i18n/locales/it.ts +10 -0
  101. package/src/i18n/locales/zh.ts +10 -0
  102. package/src/index.ts +4 -0
  103. package/src/search/command-palette.tsx +200 -27
  104. package/src/search/global-search.tsx +484 -0
  105. package/src/search/search-index.ts +295 -0
  106. package/src/search.ts +2 -0
  107. package/src/wizard/stepper-nav.tsx +11 -1
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { ComponentPropsWithoutRef, ReactNode } from 'react';
2
+ import { ComponentPropsWithoutRef, ReactNode, RefObject } from 'react';
3
3
  import { MiniCalendarProps } from './mini-calendar.js';
4
4
 
5
5
  /**
@@ -43,6 +43,32 @@ interface DatePickerBaseProps extends Omit<ComponentPropsWithoutRef<"div">, "onC
43
43
  * Usually unnecessary now: the calendar reads `miniCalendar` from the provider. */
44
44
  calendarLabels?: MiniCalendarProps["labels"];
45
45
  }
46
+ /**
47
+ * Everything the kit's own trigger button carries, handed to a custom one
48
+ * ({@link DateRangePickerProps.renderTrigger}) to spread onto its `<button>`. Spread
49
+ * it WHOLE: the ref is how focus comes back when the panel closes, the id pair and
50
+ * `aria-labelledby` are the 0.5.1 naming (an external `<label htmlFor>`, a form
51
+ * library's `aria-describedby`), and `role`/`aria-haspopup`/`aria-controls`/
52
+ * `aria-expanded` are what tell a screen reader this opens a calendar and whether it
53
+ * is open. `className` is the kit's field look (42px with a label, `pe-9` for the
54
+ * glyph the field draws at its end) — merge yours after it with `cn`.
55
+ */
56
+ interface DateTriggerAttributes {
57
+ ref: RefObject<HTMLButtonElement | null>;
58
+ type: "button";
59
+ id?: string;
60
+ role: "combobox";
61
+ "aria-haspopup": "dialog";
62
+ "aria-controls": string;
63
+ "aria-expanded": boolean;
64
+ "aria-labelledby"?: string;
65
+ "aria-label"?: string;
66
+ "aria-describedby"?: string;
67
+ "aria-invalid"?: true;
68
+ disabled?: boolean;
69
+ onClick: () => void;
70
+ className: string;
71
+ }
46
72
  interface DatePickerProps extends DatePickerBaseProps {
47
73
  /** ISO "YYYY-MM-DD", or "" for empty. */
48
74
  value: string;
@@ -138,10 +164,50 @@ interface DateRangePickerProps extends DatePickerBaseProps {
138
164
  preset?: string | null;
139
165
  /** See {@link DateRangeCommit}. Default `"immediate"`. */
140
166
  commit?: DateRangeCommit;
167
+ /**
168
+ * Draw the trigger yourself. keksdose's report range field
169
+ * (reports/report-range-field.tsx, "Why this is app-level") is why: its trigger
170
+ * NAMES the active preset ("Last 3 months", the window as a muted suffix) where the
171
+ * kit's shows two dates, sits inside a Tooltip, and is squared off on one side so the
172
+ * granularity control can join it flush at the field's 42px.
173
+ *
174
+ * Spread `props.triggerProps` onto a `<button>` whole and put `props.valueProps` on
175
+ * the element that shows the value — see {@link DateTriggerAttributes} for what each
176
+ * part is for. The field around it (label, hidden name twin, clear/calendar glyph,
177
+ * popover or phone sheet) is unchanged.
178
+ */
179
+ renderTrigger?: (props: DateRangeTriggerRenderProps) => ReactNode;
180
+ /**
181
+ * Below {@link PHONE_QUERY} the panel opens as a full-screen sheet (`FullBleedDialog`)
182
+ * with presets in a grid above the calendar and Apply pinned in the footer, instead
183
+ * of the 440px popover that hung off a 360px screen (keksdose's report range field,
184
+ * which hand-rolled exactly this). This is its `backCloses`: on by default, so Back
185
+ * dismisses the sheet; off for a caller whose commit rewrites the URL with
186
+ * `replaceState` in the same tick — keksdose's `?preset/from/to` — where the router
187
+ * would overwrite the sheet's history marker.
188
+ */
189
+ sheetBackCloses?: boolean;
190
+ }
191
+ /** What {@link DateRangePickerProps.renderTrigger} is called with. */
192
+ interface DateRangeTriggerRenderProps {
193
+ /** Spread onto the `<button>`, whole. Merge your class after `triggerProps.className`. */
194
+ triggerProps: DateTriggerAttributes;
195
+ /** Put on the element showing the value: the trigger is named "label, value" by
196
+ * reference to this id. Without it the name is the label alone. */
197
+ valueProps: {
198
+ id: string;
199
+ };
200
+ open: boolean;
201
+ from: string;
202
+ to: string;
203
+ /** The preset the column marks for the committed range, if any — the one to name. */
204
+ preset: DateRangePickerPreset | undefined;
205
+ /** What the kit's own trigger would show: the formatted range, or the placeholder. */
206
+ text: string;
141
207
  }
142
208
  /** Two-date range picker: click a start then an end; closes once both are set.
143
209
  * With `presets`, a column of named ranges is shown beside the calendar; with
144
210
  * `commit="apply"` the panel drafts and commits on Apply (see {@link DateRangeCommit}). */
145
- declare function DateRangePicker({ from, to, onChange, locale: localeProp, placeholder, min, max, formatOptions, formatValue, separator, presets, preset, commit, calendarLabels, label, clearable, clearLabel, disabled, invalid, ...rest }: DateRangePickerProps): react.JSX.Element;
211
+ declare function DateRangePicker({ from, to, onChange, locale: localeProp, placeholder, min, max, formatOptions, formatValue, separator, presets, preset, commit, renderTrigger, sheetBackCloses, calendarLabels, label, clearable, clearLabel, disabled, invalid, ...rest }: DateRangePickerProps): react.JSX.Element;
146
212
 
147
- export { DatePicker, type DatePickerProps, type DateRangeCommit, DateRangePicker, type DateRangePickerPreset, type DateRangePickerProps };
213
+ export { DatePicker, type DatePickerProps, type DateRangeCommit, DateRangePicker, type DateRangePickerPreset, type DateRangePickerProps, type DateRangeTriggerRenderProps, type DateTriggerAttributes };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useId, useMemo, useRef, useState } from "react";
4
4
  import { Calendar, CalendarClock, ChevronLeft, ChevronRight, X } from "lucide-react";
5
5
  import { cn } from "../lib/cn.js";
@@ -7,17 +7,27 @@ import { dirOf } from "../lib/direction.js";
7
7
  import { addDaysIso, parseIsoDate } from "../lib/dates.js";
8
8
  import {
9
9
  DEFAULT_DATE_PICKER_LABELS,
10
+ DEFAULT_PICKER_SHEET_LABELS,
10
11
  useKitLabels,
11
12
  useKitLocale
12
13
  } from "../i18n/kit-labels.js";
13
14
  import { splitTriggerAria } from "./trigger-aria.js";
14
- import { Button, FieldLabel, FIELD_BASE, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID } from "./ui.js";
15
+ import { Button, FieldLabel, FIELD_BASE, FIELD_TRIGGER, FIELD_FLOATING_PAD, FIELD_INVALID, PHONE_QUERY } from "./ui.js";
16
+ import { FullBleedDialog } from "./full-bleed-dialog.js";
17
+ import { useMediaQuery } from "../hooks/use-media-query.js";
15
18
  import { MiniCalendar } from "./mini-calendar.js";
16
19
  import { Popover } from "./popover.js";
17
20
  import { Tooltip } from "./tooltip.js";
18
21
  function formatDate(iso, locale, options) {
19
22
  return parseIsoDate(iso)?.toLocaleDateString(locale, options) ?? "";
20
23
  }
24
+ function CustomTrigger({
25
+ render,
26
+ attrs,
27
+ valueId
28
+ }) {
29
+ return render(attrs, valueId);
30
+ }
21
31
  function DateFieldTrigger({
22
32
  open,
23
33
  toggle,
@@ -30,7 +40,8 @@ function DateFieldTrigger({
30
40
  disabled,
31
41
  invalid,
32
42
  panelId,
33
- aria
43
+ aria,
44
+ renderTrigger
34
45
  }) {
35
46
  const wasOpen = useRef(false);
36
47
  useEffect(() => {
@@ -40,33 +51,54 @@ function DateFieldTrigger({
40
51
  const active = document.activeElement;
41
52
  if (!active || active === document.body) triggerRef.current?.focus();
42
53
  }, [open, triggerRef]);
43
- return /* @__PURE__ */ jsx(
44
- "button",
45
- {
46
- ref: triggerRef,
47
- type: "button",
48
- disabled,
49
- onClick: toggle,
50
- id: aria.id,
51
- "aria-labelledby": aria["aria-label"] && !aria["aria-labelledby"] ? void 0 : labelledBy,
52
- "aria-label": aria["aria-label"],
53
- "aria-describedby": aria["aria-describedby"],
54
- role: "combobox",
55
- "aria-haspopup": "dialog",
56
- "aria-controls": panelId,
57
- "aria-expanded": open,
58
- "aria-invalid": invalid || aria["aria-invalid"] === true || aria["aria-invalid"] === "true" || void 0,
59
- className: cn(
60
- FIELD_TRIGGER,
61
- "pe-9",
62
- padded && FIELD_FLOATING_PAD,
63
- disabled && "cursor-not-allowed opacity-50",
64
- invalid && FIELD_INVALID
65
- ),
66
- children: /* @__PURE__ */ jsx("span", { id: valueId, className: cn("truncate", !hasValue && "text-[var(--text-placeholder)]"), children: triggerText || "\xA0" })
67
- }
68
- );
54
+ const attrs = {
55
+ ref: triggerRef,
56
+ type: "button",
57
+ disabled,
58
+ onClick: toggle,
59
+ // The name has to carry the VALUE. A bare `aria-label={label}` — which is what
60
+ // this was — replaces the button's text outright, so the one field in the form
61
+ // whose entire job is to show a date announced "Due date" and stopped there,
62
+ // and a screen-reader user could not read back what they had picked without
63
+ // opening the calendar and hunting for the selected day.
64
+ //
65
+ // Two ids rather than one composed string (`common.fieldValue`): "label: value"
66
+ // is a sentence, and a name reference is spoken as the two texts in order with
67
+ // no punctuation to translate at all. The hidden twin of the FieldLabel lives
68
+ // in DateField, next to the label it copies.
69
+ id: aria.id,
70
+ "aria-labelledby": aria["aria-label"] && !aria["aria-labelledby"] ? void 0 : labelledBy,
71
+ "aria-label": aria["aria-label"],
72
+ "aria-describedby": aria["aria-describedby"],
73
+ // `role="combobox"` on a button that opens a calendar is the APG date-picker
74
+ // shape, and it is what makes the next two lines legal: `button` supports
75
+ // neither `aria-expanded` nor `aria-invalid`, so the previous markup set an
76
+ // invalid state that announced nothing (ESLint's `role-supports-aria-props`).
77
+ //
78
+ // `aria-haspopup="dialog"` is now honest — it was not when this comment first
79
+ // said so. `Popover` gained a real `role="dialog"` in the same wave, so the
80
+ // trigger's promise and the panel's role finally agree. The phone sheet is a
81
+ // `role="dialog"` too, and carries the same id.
82
+ role: "combobox",
83
+ "aria-haspopup": "dialog",
84
+ "aria-controls": panelId,
85
+ "aria-expanded": open,
86
+ "aria-invalid": invalid || aria["aria-invalid"] === true || aria["aria-invalid"] === "true" || void 0,
87
+ className: cn(
88
+ FIELD_TRIGGER,
89
+ "pe-9",
90
+ padded && FIELD_FLOATING_PAD,
91
+ disabled && "cursor-not-allowed opacity-50",
92
+ invalid && FIELD_INVALID
93
+ )
94
+ };
95
+ if (renderTrigger) return /* @__PURE__ */ jsx(CustomTrigger, { render: renderTrigger, attrs, valueId });
96
+ return /* @__PURE__ */ jsx("button", { ...attrs, children: /* @__PURE__ */ jsx("span", { id: valueId, className: cn("truncate", !hasValue && "text-[var(--text-placeholder)]"), children: triggerText || "\xA0" }) });
69
97
  }
98
+ const popoverFrame = (body, actions) => actions ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
99
+ body,
100
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-2 border-t border-[var(--border)] pt-2", children: actions })
101
+ ] }) : body;
70
102
  function DateField({
71
103
  triggerText,
72
104
  hasValue,
@@ -79,6 +111,9 @@ function DateField({
79
111
  width,
80
112
  onClear,
81
113
  invalid,
114
+ sheet = false,
115
+ sheetBackCloses = true,
116
+ renderTrigger,
82
117
  children,
83
118
  ...rest
84
119
  }) {
@@ -91,44 +126,73 @@ function DateField({
91
126
  const valueId = `${id}-value`;
92
127
  const panelId = `${id}-panel`;
93
128
  const named = typeof label === "string";
129
+ const [sheetOpen, setSheetOpen] = useState(false);
130
+ const sheetTriggerRef = useRef(null);
131
+ const closeSheet = () => setSheetOpen(false);
132
+ const sheetLabels = useKitLabels("pickerSheet", DEFAULT_PICKER_SHEET_LABELS);
133
+ const sheetFrame = (body, actions) => /* @__PURE__ */ jsx(
134
+ FullBleedDialog,
135
+ {
136
+ open: true,
137
+ onClose: closeSheet,
138
+ id: panelId,
139
+ "aria-label": panelLabel,
140
+ header: panelLabel,
141
+ closeLabel: sheetLabels.close,
142
+ backCloses: sheetBackCloses,
143
+ dir,
144
+ onMouseDown: (e) => e.stopPropagation(),
145
+ footer: actions,
146
+ children: body
147
+ }
148
+ );
149
+ const fieldTrigger = ({
150
+ open,
151
+ toggle,
152
+ ref
153
+ }) => /* @__PURE__ */ jsx(
154
+ DateFieldTrigger,
155
+ {
156
+ open,
157
+ toggle: () => {
158
+ setDir(dirOf(rootRef.current));
159
+ toggle();
160
+ },
161
+ triggerRef: ref,
162
+ triggerText,
163
+ hasValue,
164
+ labelledBy: [
165
+ aria["aria-labelledby"],
166
+ named ? labelId : !aria["aria-labelledby"] && aria.id ? aria.id : void 0,
167
+ valueId
168
+ ].filter(Boolean).join(" "),
169
+ aria,
170
+ panelId,
171
+ valueId,
172
+ padded: label !== void 0,
173
+ disabled,
174
+ invalid,
175
+ renderTrigger
176
+ }
177
+ );
94
178
  return (
95
179
  // The caller's attributes land here, on the field's own box — the trigger inside is
96
180
  // named by `aria-labelledby` and must keep the id pair it is given.
97
181
  /* @__PURE__ */ jsxs("div", { ...wrapperRest, ref: rootRef, className: cn("relative", className), children: [
98
182
  label !== void 0 && /* @__PURE__ */ jsx(FieldLabel, { children: label }),
99
183
  named && /* @__PURE__ */ jsx("span", { id: labelId, "aria-hidden": true, className: "sr-only-fixed", children: label }),
100
- /* @__PURE__ */ jsx(
184
+ sheet ? /* @__PURE__ */ jsxs(Fragment, { children: [
185
+ fieldTrigger({ open: sheetOpen, toggle: () => setSheetOpen((v) => !v), ref: sheetTriggerRef }),
186
+ sheetOpen && children(closeSheet, sheetFrame)
187
+ ] }) : /* @__PURE__ */ jsx(
101
188
  Popover,
102
189
  {
103
190
  width,
104
191
  panelId,
105
192
  labels: { panel: panelLabel },
106
193
  dir,
107
- trigger: ({ open, toggle, ref }) => /* @__PURE__ */ jsx(
108
- DateFieldTrigger,
109
- {
110
- open,
111
- toggle: () => {
112
- setDir(dirOf(rootRef.current));
113
- toggle();
114
- },
115
- triggerRef: ref,
116
- triggerText,
117
- hasValue,
118
- labelledBy: [
119
- aria["aria-labelledby"],
120
- named ? labelId : !aria["aria-labelledby"] && aria.id ? aria.id : void 0,
121
- valueId
122
- ].filter(Boolean).join(" "),
123
- aria,
124
- panelId,
125
- valueId,
126
- padded: label !== void 0,
127
- disabled,
128
- invalid
129
- }
130
- ),
131
- children: (close) => children(close)
194
+ trigger: fieldTrigger,
195
+ children: (close) => children(close, popoverFrame)
132
196
  }
133
197
  ),
134
198
  showClear ? /* @__PURE__ */ jsx(
@@ -338,7 +402,8 @@ function PresetColumn({
338
402
  presets,
339
403
  marked,
340
404
  label,
341
- onPick
405
+ onPick,
406
+ sheet
342
407
  }) {
343
408
  return (
344
409
  // `border-e`/`pe`, not `-r`: the preset column is on the START side, and the rule
@@ -348,7 +413,7 @@ function PresetColumn({
348
413
  {
349
414
  role: "group",
350
415
  "aria-label": label,
351
- className: "flex w-32 shrink-0 flex-col gap-0.5 border-e border-[var(--border)] pe-2",
416
+ className: sheet ? "grid grid-cols-2 gap-0.5" : "flex w-32 shrink-0 flex-col gap-0.5 border-e border-[var(--border)] pe-2",
352
417
  children: presets.map((p, i) => {
353
418
  const selected = i === marked;
354
419
  return /* @__PURE__ */ jsx(
@@ -359,7 +424,9 @@ function PresetColumn({
359
424
  "data-preset": p.id,
360
425
  onClick: () => onPick(p),
361
426
  className: cn(
362
- "rounded px-2 py-1.5 text-start text-xs",
427
+ "rounded px-2 text-start",
428
+ // 44px on a phone: the kit's touch-target size (`SHEET_ROW_CLASS`).
429
+ sheet ? "min-h-11 py-2 text-sm" : "py-1.5 text-xs",
363
430
  selected ? "bg-[var(--bg-active)] font-medium text-[var(--text-primary)]" : "text-[var(--text-secondary)] hover:bg-[var(--bg-hover)]"
364
431
  ),
365
432
  children: p.label
@@ -379,6 +446,8 @@ function RangePanel({
379
446
  controlled,
380
447
  commit,
381
448
  close,
449
+ frame,
450
+ sheet,
382
451
  commitRange,
383
452
  calendarProps,
384
453
  labels
@@ -409,10 +478,11 @@ function RangePanel({
409
478
  }
410
479
  }
411
480
  );
412
- const body = presets && presets.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
481
+ const body = presets && presets.length > 0 ? /* @__PURE__ */ jsxs("div", { className: sheet ? "flex flex-col gap-3" : "flex gap-3", children: [
413
482
  /* @__PURE__ */ jsx(
414
483
  PresetColumn,
415
484
  {
485
+ sheet,
416
486
  presets,
417
487
  marked,
418
488
  label: labels.presets,
@@ -428,15 +498,16 @@ function RangePanel({
428
498
  ),
429
499
  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: calendar })
430
500
  ] }) : calendar;
431
- if (!drafting) return body;
432
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
501
+ if (!drafting) return frame(body);
502
+ return frame(
433
503
  body,
434
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 border-t border-[var(--border)] pt-2", children: [
435
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", onClick: close, children: labels.cancel }),
504
+ /* @__PURE__ */ jsxs(Fragment, { children: [
505
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "ghost", className: sheet ? "flex-1" : void 0, onClick: close, children: labels.cancel }),
436
506
  /* @__PURE__ */ jsx(
437
507
  Button,
438
508
  {
439
509
  type: "button",
510
+ className: sheet ? "flex-1" : void 0,
440
511
  disabled: !complete,
441
512
  onClick: () => {
442
513
  if (!complete) return;
@@ -447,7 +518,7 @@ function RangePanel({
447
518
  }
448
519
  )
449
520
  ] })
450
- ] });
521
+ );
451
522
  }
452
523
  function DateRangePicker({
453
524
  from,
@@ -463,6 +534,8 @@ function DateRangePicker({
463
534
  presets,
464
535
  preset,
465
536
  commit = "immediate",
537
+ renderTrigger,
538
+ sheetBackCloses,
466
539
  calendarLabels,
467
540
  label,
468
541
  clearable,
@@ -481,6 +554,7 @@ function DateRangePicker({
481
554
  const b = to ? render(to) : "";
482
555
  const triggerText = from ? to ? `${a}${separator}${b}` : `${a}${separator}\u2026` : placeholder ?? "";
483
556
  const hasPresets = Boolean(presets && presets.length > 0);
557
+ const sheet = useMediaQuery(PHONE_QUERY, false);
484
558
  const commitRange = (f, t, presetId) => {
485
559
  setOwnPreset(presetId);
486
560
  if (presetId === void 0) onChange(f, t);
@@ -500,7 +574,18 @@ function DateRangePicker({
500
574
  hasValue: Boolean(from || to),
501
575
  triggerText,
502
576
  onClear: () => commitRange("", "", void 0),
503
- children: (close) => /* @__PURE__ */ jsx(
577
+ sheet,
578
+ sheetBackCloses,
579
+ renderTrigger: renderTrigger && ((triggerProps, valueId) => renderTrigger({
580
+ triggerProps,
581
+ valueProps: { id: valueId },
582
+ open: triggerProps["aria-expanded"],
583
+ from,
584
+ to,
585
+ preset: presets?.[markedPreset(presets, from, to, activeId, controlled)],
586
+ text: triggerText
587
+ })),
588
+ children: (close, frame) => /* @__PURE__ */ jsx(
504
589
  RangePanel,
505
590
  {
506
591
  from,
@@ -510,6 +595,8 @@ function DateRangePicker({
510
595
  controlled,
511
596
  commit,
512
597
  close,
598
+ frame,
599
+ sheet,
513
600
  commitRange,
514
601
  calendarProps: { locale, min, max, labels: calendarLabels },
515
602
  labels: text