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.
Files changed (102) hide show
  1. package/dist/components/AgentActivity.d.ts +2 -1
  2. package/dist/components/AgentActivity.d.ts.map +1 -1
  3. package/dist/components/AgentActivity.js +4 -17
  4. package/dist/components/AgentActivity.js.map +1 -1
  5. package/dist/components/Calendar.d.ts +20 -0
  6. package/dist/components/Calendar.d.ts.map +1 -0
  7. package/dist/components/Calendar.js +151 -0
  8. package/dist/components/Calendar.js.map +1 -0
  9. package/dist/components/CalendarPopover.d.ts +26 -0
  10. package/dist/components/CalendarPopover.d.ts.map +1 -0
  11. package/dist/components/CalendarPopover.js +45 -0
  12. package/dist/components/CalendarPopover.js.map +1 -0
  13. package/dist/components/DateField.d.ts +15 -0
  14. package/dist/components/DateField.d.ts.map +1 -0
  15. package/dist/components/DateField.js +74 -0
  16. package/dist/components/DateField.js.map +1 -0
  17. package/dist/components/DatePicker.d.ts +81 -0
  18. package/dist/components/DatePicker.d.ts.map +1 -0
  19. package/dist/components/DatePicker.js +102 -0
  20. package/dist/components/DatePicker.js.map +1 -0
  21. package/dist/components/DateRangePicker.d.ts +117 -0
  22. package/dist/components/DateRangePicker.d.ts.map +1 -0
  23. package/dist/components/DateRangePicker.js +152 -0
  24. package/dist/components/DateRangePicker.js.map +1 -0
  25. package/dist/components/Header.d.ts +10 -0
  26. package/dist/components/Header.d.ts.map +1 -1
  27. package/dist/components/Header.js +18 -3
  28. package/dist/components/Header.js.map +1 -1
  29. package/dist/components/NumberInput.d.ts +63 -0
  30. package/dist/components/NumberInput.d.ts.map +1 -0
  31. package/dist/components/NumberInput.js +102 -0
  32. package/dist/components/NumberInput.js.map +1 -0
  33. package/dist/components/PromptInput.d.ts +89 -0
  34. package/dist/components/PromptInput.d.ts.map +1 -0
  35. package/dist/components/PromptInput.js +130 -0
  36. package/dist/components/PromptInput.js.map +1 -0
  37. package/dist/components/SegmentedControl.d.ts +63 -0
  38. package/dist/components/SegmentedControl.d.ts.map +1 -0
  39. package/dist/components/SegmentedControl.js +79 -0
  40. package/dist/components/SegmentedControl.js.map +1 -0
  41. package/dist/components/Sidebar.d.ts +109 -0
  42. package/dist/components/Sidebar.d.ts.map +1 -0
  43. package/dist/components/Sidebar.js +106 -0
  44. package/dist/components/Sidebar.js.map +1 -0
  45. package/dist/components/Stepper.d.ts +73 -0
  46. package/dist/components/Stepper.d.ts.map +1 -0
  47. package/dist/components/Stepper.js +82 -0
  48. package/dist/components/Stepper.js.map +1 -0
  49. package/dist/components/ToolCall.d.ts +66 -0
  50. package/dist/components/ToolCall.d.ts.map +1 -0
  51. package/dist/components/ToolCall.js +78 -0
  52. package/dist/components/ToolCall.js.map +1 -0
  53. package/dist/components/agent-status.d.ts +14 -0
  54. package/dist/components/agent-status.d.ts.map +1 -0
  55. package/dist/components/agent-status.js +16 -0
  56. package/dist/components/agent-status.js.map +1 -0
  57. package/dist/components/index.d.ts +17 -0
  58. package/dist/components/index.d.ts.map +1 -1
  59. package/dist/components/index.js +8 -0
  60. package/dist/components/index.js.map +1 -1
  61. package/dist/components/iso-date.d.ts +53 -0
  62. package/dist/components/iso-date.d.ts.map +1 -0
  63. package/dist/components/iso-date.js +102 -0
  64. package/dist/components/iso-date.js.map +1 -0
  65. package/dist/figma-descriptions.json +107 -52
  66. package/dist/figma-map.json +735 -2
  67. package/dist/meta/AgentActivityStep.json +2 -2
  68. package/dist/meta/DatePicker.json +270 -0
  69. package/dist/meta/DateRangePicker.json +284 -0
  70. package/dist/meta/Header.json +32 -2
  71. package/dist/meta/NumberInput.json +407 -0
  72. package/dist/meta/PromptInput.json +212 -0
  73. package/dist/meta/SegmentedControl.json +217 -0
  74. package/dist/meta/SegmentedControlItem.json +122 -0
  75. package/dist/meta/Sidebar.json +150 -0
  76. package/dist/meta/SidebarItem.json +184 -0
  77. package/dist/meta/SidebarSection.json +131 -0
  78. package/dist/meta/Stepper.json +135 -0
  79. package/dist/meta/StepperStep.json +148 -0
  80. package/dist/meta/Tabs.json +5 -0
  81. package/dist/meta/ToolCall.json +192 -0
  82. package/dist/meta/components.json +5784 -3297
  83. package/dist/meta/contrast.json +7776 -2478
  84. package/dist/meta/index.json +139 -2
  85. package/dist/meta/patterns/AgentRun.json +27 -0
  86. package/dist/meta/patterns/Form.json +9 -0
  87. package/dist/meta/patterns/PageShell.json +43 -3
  88. package/dist/meta/patterns/Wizard.json +20 -1
  89. package/dist/meta/patterns/index.json +10 -1
  90. package/dist/styles/date-picker.css +420 -0
  91. package/dist/styles/date-range-picker.css +280 -0
  92. package/dist/styles/header.css +26 -0
  93. package/dist/styles/index.css +15 -0
  94. package/dist/styles/number-input.css +83 -0
  95. package/dist/styles/prompt-input.css +127 -0
  96. package/dist/styles/segmented-control.css +182 -0
  97. package/dist/styles/sidebar.css +307 -0
  98. package/dist/styles/stepper.css +250 -0
  99. package/dist/styles/tool-call.css +202 -0
  100. package/llms.txt +2 -2
  101. package/package.json +20 -19
  102. package/LICENSE +0 -21
@@ -0,0 +1,102 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useRef } from 'react';
4
+ import { useDatePicker, useButton } from 'react-aria';
5
+ import { useDatePickerState } from 'react-stately';
6
+ import { DateField } from './DateField.js';
7
+ import { SingleCalendar } from './Calendar.js';
8
+ import { CalendarPopover } from './CalendarPopover.js';
9
+ import { toCalendarDate, toIso, wrapUnavailable } from './iso-date.js';
10
+ const CalendarIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M8 2v4m8-4v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Z", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
11
+ /**
12
+ * DatePicker — a segmented date field with a calendar attached.
13
+ *
14
+ * WHY NOT `<input type="date">`
15
+ *
16
+ * The native control is genuinely good on mobile and genuinely unusable as a
17
+ * design system component on desktop: its calendar cannot be styled at all, it
18
+ * cannot express an unavailable date that is not part of a continuous min/max
19
+ * range, and Safari on macOS renders no calendar button whatsoever. A system
20
+ * whose date field looks like a different control in every browser is not a
21
+ * design system, so this rebuilds it — and pays for that by having to rebuild
22
+ * the keyboard handling and the screen-reader semantics the native control gave
23
+ * away for free. React Aria's `useDatePicker` is what builds them back.
24
+ *
25
+ * THE VALUE IS A STRING, THE DISPLAY IS NOT
26
+ *
27
+ * `value` is always `YYYY-MM-DD` in the Gregorian calendar. What the user SEES
28
+ * is their own locale's field order and their own calendar system, resolved
29
+ * from `Intl` — so a German reader edits DD.MM.YYYY and the value still comes
30
+ * back as `2026-04-12`. See `iso-date.ts` for why the public type is not
31
+ * react-aria's `CalendarDate`.
32
+ *
33
+ * THE FIELD IS EDITABLE WITHOUT THE CALENDAR, AND THAT IS THE POINT
34
+ *
35
+ * Typing a date is faster than clicking one for anybody who knows the date they
36
+ * want, and paging a calendar back to a birth year is miserable. The segments
37
+ * take digits and arrow keys directly; the calendar is for the cases where the
38
+ * date is being chosen rather than recalled.
39
+ */
40
+ export function DatePicker({ label, description, errorMessage, isInvalid, isDisabled, isReadOnly, isRequired, size = 'md', value, defaultValue, onChange, minValue, maxValue, isDateUnavailable, name, calendarLabel = 'Open calendar', className, wrapperClassName, id, }) {
41
+ /*
42
+ * The ISO boundary, crossed once on the way in and once on the way out.
43
+ *
44
+ * `value === undefined` has to survive the conversion as `undefined`, not
45
+ * become `null`. react-aria reads the two differently: `undefined` means
46
+ * uncontrolled and `null` means controlled-and-empty, so collapsing them
47
+ * would make an uncontrolled picker refuse to hold the date it was given.
48
+ */
49
+ const ariaProps = {
50
+ label: typeof label === 'string' ? label : undefined,
51
+ value: value === undefined ? undefined : toCalendarDate(value, 'value'),
52
+ defaultValue: toCalendarDate(defaultValue, 'defaultValue') ?? undefined,
53
+ minValue: toCalendarDate(minValue, 'minValue') ?? undefined,
54
+ maxValue: toCalendarDate(maxValue, 'maxValue') ?? undefined,
55
+ isDateUnavailable: wrapUnavailable(isDateUnavailable),
56
+ isDisabled,
57
+ isReadOnly,
58
+ isRequired,
59
+ isInvalid,
60
+ /*
61
+ * `granularity: 'day'` is what keeps this a DATE picker. Left unset,
62
+ * react-aria infers granularity from the value's type, and a value of
63
+ * `undefined` infers 'minute' — so an empty picker renders hour and minute
64
+ * segments that disappear the moment a date-only value arrives.
65
+ */
66
+ granularity: 'day',
67
+ onChange: onChange
68
+ ? (date) => onChange(date ? toIso(date) : null)
69
+ : undefined,
70
+ };
71
+ const state = useDatePickerState(ariaProps);
72
+ const groupRef = useRef(null);
73
+ const buttonRef = useRef(null);
74
+ const { groupProps, labelProps, fieldProps, buttonProps: triggerProps, dialogProps, calendarProps, descriptionProps, errorMessageProps, } = useDatePicker({ ...ariaProps, id }, state, groupRef);
75
+ const { buttonProps } = useButton(triggerProps, buttonRef);
76
+ const helper = isInvalid && errorMessage ? errorMessage : description;
77
+ return (_jsxs("div", { className: [
78
+ 'ion-field',
79
+ isInvalid ? 'ion-field--error' : '',
80
+ wrapperClassName || '',
81
+ ]
82
+ .filter(Boolean)
83
+ .join(' '), children: [label && (
84
+ // A <span>, not a <label>. The group is a set of spinbuttons rather
85
+ // than one form control, so `htmlFor` has nothing to point at —
86
+ // `useDatePicker` wires the name through `aria-labelledby` instead.
87
+ _jsx("span", { ...labelProps, className: "ion-field__label", children: label })), _jsxs("div", { ...groupProps, ref: groupRef, className: [
88
+ 'ion-input',
89
+ 'ion-date-picker',
90
+ size !== 'md' ? `ion-input--${size}` : '',
91
+ isInvalid ? 'ion-input--invalid' : '',
92
+ isDisabled ? 'ion-input--disabled' : '',
93
+ isReadOnly ? 'ion-input--readonly' : '',
94
+ className || '',
95
+ ]
96
+ .filter(Boolean)
97
+ .join(' '), "data-open": state.isOpen || undefined, "data-invalid": isInvalid || undefined, "data-disabled": isDisabled || undefined, children: [_jsx(DateField, { ...fieldProps }), name && (_jsx("input", { type: "hidden", name: name, value: state.value ? toIso(state.value) : '' })), _jsx("button", { ...buttonProps, ref: buttonRef, type: "button", "aria-labelledby": undefined, "aria-label": calendarLabel, className: "ion-date-picker__button", children: _jsx(CalendarIcon, {}) })] }), state.isOpen && !isDisabled && !isReadOnly && (_jsx(CalendarPopover, { state: state, triggerRef: groupRef, dialogProps: dialogProps, children: _jsx(SingleCalendar, { ...calendarProps }) })), helper && (_jsx("span", { ...(isInvalid && errorMessage
98
+ ? errorMessageProps
99
+ : descriptionProps), className: "ion-field__helper", children: helper }))] }));
100
+ }
101
+ DatePicker.displayName = 'DatePicker';
102
+ //# sourceMappingURL=DatePicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DatePicker.js","sourceRoot":"","sources":["../../src/components/DatePicker.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ import React from 'react';
2
+ import type { IsoDate } from './iso-date.js';
3
+ export type DateRangePickerSize = 'sm' | 'md' | 'lg';
4
+ /** A closed interval of calendar dates. `end` is included in the range. */
5
+ export interface DateRange {
6
+ /** `YYYY-MM-DD`. */
7
+ start: IsoDate;
8
+ /** `YYYY-MM-DD`, inclusive. */
9
+ end: IsoDate;
10
+ }
11
+ /**
12
+ * A shortcut in the rail beside the calendar — "Last 7 days", "Year to date".
13
+ */
14
+ export interface DateRangePreset {
15
+ /** What the row reads. Also its accessible name. */
16
+ label: string;
17
+ /**
18
+ * The range it selects.
19
+ *
20
+ * A FUNCTION for anything relative to today, which is most of them. A literal
21
+ * object is evaluated once, when the caller's module is first imported, so
22
+ * "Last 7 days" built as a literal is seven days before whenever the tab was
23
+ * opened — correct on load and increasingly wrong for a session left open
24
+ * overnight. The function is re-run every time the calendar opens.
25
+ */
26
+ value: DateRange | (() => DateRange);
27
+ }
28
+ export interface DateRangePickerProps {
29
+ /** Field label. Required for a usable control — see `a11y.requires`. */
30
+ label?: React.ReactNode;
31
+ /** Helper text below the field. */
32
+ description?: React.ReactNode;
33
+ /** Replaces the helper text when `isInvalid` is set. */
34
+ errorMessage?: React.ReactNode;
35
+ isInvalid?: boolean;
36
+ isDisabled?: boolean;
37
+ isReadOnly?: boolean;
38
+ isRequired?: boolean;
39
+ /** Matches Input's `Size` variant: Small, Medium, Large. */
40
+ size?: DateRangePickerSize;
41
+ /**
42
+ * The selected range, both ends as `YYYY-MM-DD`. `null` means no range.
43
+ * A half-open range is not representable on purpose — see `antiPatterns`.
44
+ */
45
+ value?: DateRange | null;
46
+ /** The initial range, for an uncontrolled picker. */
47
+ defaultValue?: DateRange;
48
+ /** Fires with both ends, or `null` when the range is cleared. */
49
+ onChange?: (value: DateRange | null) => void;
50
+ /** Earliest selectable date, `YYYY-MM-DD`. */
51
+ minValue?: IsoDate;
52
+ /** Latest selectable date, `YYYY-MM-DD`. */
53
+ maxValue?: IsoDate;
54
+ /**
55
+ * Individual dates the calendar refuses. Receives `YYYY-MM-DD`.
56
+ *
57
+ * A range may not be dragged ACROSS one of these — react-aria stops the
58
+ * selection at the first unavailable day, which is what makes "book a room
59
+ * for these nights" correct rather than merely styled.
60
+ */
61
+ isDateUnavailable?: (date: IsoDate) => boolean;
62
+ /** Shortcut rows beside the calendar. Omitted, no rail is rendered. */
63
+ presets?: readonly DateRangePreset[];
64
+ /**
65
+ * How many months the calendar shows at once. Two by default: a range that
66
+ * crosses a month boundary is the common case, and a one-month calendar
67
+ * makes the user page back and forth to see both ends of their own selection.
68
+ */
69
+ visibleMonths?: 1 | 2 | 3;
70
+ /** Show a Clear button under the calendar. Defaults to `true`. */
71
+ isClearable?: boolean;
72
+ /** Posts `<name>-start` and `<name>-end` for an uncontrolled form. */
73
+ name?: string;
74
+ /** Accessible label for the button that opens the calendar. */
75
+ calendarLabel?: string;
76
+ clearLabel?: string;
77
+ presetsLabel?: string;
78
+ className?: string;
79
+ wrapperClassName?: string;
80
+ id?: string;
81
+ }
82
+ /**
83
+ * DateRangePicker — two segmented date fields with one calendar between them.
84
+ *
85
+ * NOT TWO `DatePicker`s SIDE BY SIDE, and the difference is the whole reason
86
+ * this exists. Two independent pickers cannot stop the end date being before
87
+ * the start, cannot show the days between them as a band, and give the user two
88
+ * calendars to reconcile by memory. `useDateRangePicker` owns both ends: the
89
+ * second click completes the range in whichever order the two dates fall, the
90
+ * band follows the pointer while it is being dragged out, and a range cannot be
91
+ * made to run backwards.
92
+ *
93
+ * THE VALUE COMMITS LIVE. THERE IS NO APPLY BUTTON.
94
+ *
95
+ * `onChange` fires the moment the second end lands, and the calendar closes.
96
+ * The reference designs this was drawn from put Clear and Apply under the grid,
97
+ * which is a draft model: the popover holds a pending range and only Apply
98
+ * promotes it. That was considered and rejected. Escape and an outside click
99
+ * would then silently discard a selection the user watched themselves make —
100
+ * and there is no way to tell those two gestures apart from "I am done". A
101
+ * button labelled Apply beside a value that already applied is worse still.
102
+ *
103
+ * Clear stays, because clearing is a real action with no other affordance.
104
+ *
105
+ * BOTH ENDS OR NEITHER
106
+ *
107
+ * `value` has no half-open form. A range with a start and no end is a state the
108
+ * calendar passes THROUGH between the two clicks; it is never a value the
109
+ * caller is handed, because "everything after March" and "March to today" are
110
+ * different questions and a `null` end cannot say which one was meant. A caller
111
+ * who wants an open end passes a sentinel of their own choosing as `maxValue`.
112
+ */
113
+ export declare function DateRangePicker({ label, description, errorMessage, isInvalid, isDisabled, isReadOnly, isRequired, size, value, defaultValue, onChange, minValue, maxValue, isDateUnavailable, presets, visibleMonths, isClearable, name, calendarLabel, clearLabel, presetsLabel, className, wrapperClassName, id, }: DateRangePickerProps): React.JSX.Element;
114
+ export declare namespace DateRangePicker {
115
+ var displayName: string;
116
+ }
117
+ //# sourceMappingURL=DateRangePicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateRangePicker.d.ts","sourceRoot":"","sources":["../../src/components/DateRangePicker.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA0B,MAAM,OAAO,CAAC;AAO/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAErD,2EAA2E;AAC3E,MAAM,WAAW,SAAS;IACxB,oBAAoB;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,+BAA+B;IAC/B,GAAG,EAAE,OAAO,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,KAAK,EAAE,SAAS,GAAG,CAAC,MAAM,SAAS,CAAC,CAAC;CACtC;AAcD,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,mCAAmC;IACnC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,wDAAwD;IACxD,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,qDAAqD;IACrD,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7C,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;IAC/C,uEAAuE;IACvE,OAAO,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACrC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,UAAU,EACV,UAAU,EACV,IAAW,EACX,KAAK,EACL,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,iBAAiB,EACjB,OAAO,EACP,aAAiB,EACjB,WAAkB,EAClB,IAAI,EACJ,aAA+B,EAC/B,UAAoB,EACpB,YAAqC,EACrC,SAAS,EACT,gBAAgB,EAChB,EAAE,GACH,EAAE,oBAAoB,qBAuPtB;yBAhRe,eAAe"}
@@ -0,0 +1,152 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useMemo, useRef } from 'react';
4
+ import { useDateRangePicker, useButton } from 'react-aria';
5
+ import { useDateRangePickerState } from 'react-stately';
6
+ import { DateField } from './DateField.js';
7
+ import { RangeCalendar } from './Calendar.js';
8
+ import { CalendarPopover } from './CalendarPopover.js';
9
+ import { toCalendarDate, toIso, wrapUnavailable } from './iso-date.js';
10
+ const CalendarIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M8 2v4m8-4v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2Z", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
11
+ /** Resolves a preset's `value`, which may be a literal or a function. */
12
+ const resolvePreset = (p) => typeof p.value === 'function' ? p.value() : p.value;
13
+ /**
14
+ * DateRangePicker — two segmented date fields with one calendar between them.
15
+ *
16
+ * NOT TWO `DatePicker`s SIDE BY SIDE, and the difference is the whole reason
17
+ * this exists. Two independent pickers cannot stop the end date being before
18
+ * the start, cannot show the days between them as a band, and give the user two
19
+ * calendars to reconcile by memory. `useDateRangePicker` owns both ends: the
20
+ * second click completes the range in whichever order the two dates fall, the
21
+ * band follows the pointer while it is being dragged out, and a range cannot be
22
+ * made to run backwards.
23
+ *
24
+ * THE VALUE COMMITS LIVE. THERE IS NO APPLY BUTTON.
25
+ *
26
+ * `onChange` fires the moment the second end lands, and the calendar closes.
27
+ * The reference designs this was drawn from put Clear and Apply under the grid,
28
+ * which is a draft model: the popover holds a pending range and only Apply
29
+ * promotes it. That was considered and rejected. Escape and an outside click
30
+ * would then silently discard a selection the user watched themselves make —
31
+ * and there is no way to tell those two gestures apart from "I am done". A
32
+ * button labelled Apply beside a value that already applied is worse still.
33
+ *
34
+ * Clear stays, because clearing is a real action with no other affordance.
35
+ *
36
+ * BOTH ENDS OR NEITHER
37
+ *
38
+ * `value` has no half-open form. A range with a start and no end is a state the
39
+ * calendar passes THROUGH between the two clicks; it is never a value the
40
+ * caller is handed, because "everything after March" and "March to today" are
41
+ * different questions and a `null` end cannot say which one was meant. A caller
42
+ * who wants an open end passes a sentinel of their own choosing as `maxValue`.
43
+ */
44
+ export function DateRangePicker({ label, description, errorMessage, isInvalid, isDisabled, isReadOnly, isRequired, size = 'md', value, defaultValue, onChange, minValue, maxValue, isDateUnavailable, presets, visibleMonths = 2, isClearable = true, name, calendarLabel = 'Open calendar', clearLabel = 'Clear', presetsLabel = 'Date range shortcuts', className, wrapperClassName, id, }) {
45
+ /*
46
+ * The ISO boundary. `undefined` has to stay `undefined` — react-aria reads it
47
+ * as "uncontrolled" where `null` means "controlled and empty", so collapsing
48
+ * the two makes an uncontrolled picker refuse to hold its own value.
49
+ */
50
+ const toRange = (r, prop) => r == null
51
+ ? null
52
+ : {
53
+ start: toCalendarDate(r.start, `${prop}.start`),
54
+ end: toCalendarDate(r.end, `${prop}.end`),
55
+ };
56
+ const ariaProps = {
57
+ label: typeof label === 'string' ? label : undefined,
58
+ value: value === undefined ? undefined : toRange(value, 'value'),
59
+ defaultValue: toRange(defaultValue, 'defaultValue') ?? undefined,
60
+ minValue: toCalendarDate(minValue, 'minValue') ?? undefined,
61
+ maxValue: toCalendarDate(maxValue, 'maxValue') ?? undefined,
62
+ isDateUnavailable: wrapUnavailable(isDateUnavailable),
63
+ isDisabled,
64
+ isReadOnly,
65
+ isRequired,
66
+ isInvalid,
67
+ /*
68
+ * Same reason as DatePicker: left unset, react-aria infers granularity from
69
+ * the value, and an empty picker infers 'minute' and grows time segments
70
+ * that vanish the moment a date arrives.
71
+ */
72
+ granularity: 'day',
73
+ onChange: onChange
74
+ ? (r) => onChange(r ? { start: toIso(r.start), end: toIso(r.end) } : null)
75
+ : undefined,
76
+ };
77
+ const state = useDateRangePickerState(ariaProps);
78
+ const groupRef = useRef(null);
79
+ const buttonRef = useRef(null);
80
+ const { groupProps, labelProps, startFieldProps, endFieldProps, buttonProps: triggerProps, dialogProps, calendarProps, descriptionProps, errorMessageProps, } = useDateRangePicker({ ...ariaProps, id }, state, groupRef);
81
+ const { buttonProps } = useButton(triggerProps, buttonRef);
82
+ /*
83
+ * Resolved once per open, not once per render.
84
+ *
85
+ * `state.isOpen` is the dependency on purpose. A relative preset is a
86
+ * function of today, so re-resolving it on every render would be correct and
87
+ * wasteful; resolving it once when the module loads would be cheap and wrong
88
+ * by morning. Re-resolving each time the calendar opens is the only cadence
89
+ * at which "Last 7 days" is both stable while the user reads it and accurate
90
+ * when they come back to it.
91
+ */
92
+ const resolvedPresets = useMemo(() => (presets ?? []).map((p) => ({ label: p.label, ...resolvePreset(p) })),
93
+ // `state.isOpen` is in here as a CADENCE, not as a value this reads —
94
+ // see above. An exhaustive-deps rule would call it extraneous and be
95
+ // wrong: dropping it is what makes a relative preset go stale.
96
+ [presets, state.isOpen]);
97
+ const selectedIso = state.value?.start &&
98
+ state.value?.end && {
99
+ start: toIso(state.value.start),
100
+ end: toIso(state.value.end),
101
+ };
102
+ const helper = isInvalid && errorMessage ? errorMessage : description;
103
+ const rail = resolvedPresets.length ? (_jsx("div", { className: "ion-range-presets", role: "group", "aria-label": presetsLabel, children: resolvedPresets.map((p) => {
104
+ const isSelected = selectedIso?.start === p.start && selectedIso?.end === p.end;
105
+ return (_jsx("button", { type: "button", className: "ion-range-presets__item", "aria-pressed": isSelected, "data-selected": isSelected || undefined, onClick: () => {
106
+ state.setValue({
107
+ start: toCalendarDate(p.start, `preset "${p.label}"`),
108
+ end: toCalendarDate(p.end, `preset "${p.label}"`),
109
+ });
110
+ /*
111
+ * Closed explicitly. A complete range from the GRID closes the
112
+ * calendar on its own, and a preset produces the same complete
113
+ * range — leaving it open after a shortcut was pressed would make
114
+ * the two paths behave differently for no reason the user could
115
+ * see.
116
+ */
117
+ state.setOpen(false);
118
+ }, children: p.label }, p.label));
119
+ }) })) : null;
120
+ const footer = isClearable && state.value ? (_jsx("div", { className: "ion-range-footer", children: _jsx("button", { type: "button", className: "ion-range-footer__clear", onClick: () => {
121
+ state.setValue(null);
122
+ /*
123
+ * Deliberately left OPEN. Clearing is nearly always the first half
124
+ * of choosing something else; closing the calendar would make the
125
+ * user reopen it to do the thing they cleared it for.
126
+ */
127
+ }, children: clearLabel }) })) : null;
128
+ return (_jsxs("div", { className: [
129
+ 'ion-field',
130
+ isInvalid ? 'ion-field--error' : '',
131
+ wrapperClassName || '',
132
+ ]
133
+ .filter(Boolean)
134
+ .join(' '), children: [label && (
135
+ // A <span>, not a <label> — the group holds two fields of spinbuttons
136
+ // rather than one form control, so `htmlFor` has nothing to point at.
137
+ _jsx("span", { ...labelProps, className: "ion-field__label", children: label })), _jsxs("div", { ...groupProps, ref: groupRef, className: [
138
+ 'ion-input',
139
+ 'ion-date-range-picker',
140
+ size !== 'md' ? `ion-input--${size}` : '',
141
+ isInvalid ? 'ion-input--invalid' : '',
142
+ isDisabled ? 'ion-input--disabled' : '',
143
+ isReadOnly ? 'ion-input--readonly' : '',
144
+ className || '',
145
+ ]
146
+ .filter(Boolean)
147
+ .join(' '), "data-open": state.isOpen || undefined, "data-invalid": isInvalid || undefined, "data-disabled": isDisabled || undefined, children: [_jsx(DateField, { ...startFieldProps }), _jsx("span", { className: "ion-date-range-picker__dash", "aria-hidden": "true", children: "\u2013" }), _jsx(DateField, { ...endFieldProps }), name && (_jsxs(_Fragment, { children: [_jsx("input", { type: "hidden", name: `${name}-start`, value: state.value?.start ? toIso(state.value.start) : '' }), _jsx("input", { type: "hidden", name: `${name}-end`, value: state.value?.end ? toIso(state.value.end) : '' })] })), _jsx("button", { ...buttonProps, ref: buttonRef, type: "button", "aria-labelledby": undefined, "aria-label": calendarLabel, className: "ion-date-range-picker__button", children: _jsx(CalendarIcon, {}) })] }), state.isOpen && !isDisabled && !isReadOnly && (_jsx(CalendarPopover, { state: state, triggerRef: groupRef, dialogProps: dialogProps, className: "ion-calendar-popover--range", children: _jsx(RangeCalendar, { ...calendarProps, visibleMonths: visibleMonths, aside: rail, footer: footer }) })), helper && (_jsx("span", { ...(isInvalid && errorMessage
148
+ ? errorMessageProps
149
+ : descriptionProps), className: "ion-field__helper", children: helper }))] }));
150
+ }
151
+ DateRangePicker.displayName = 'DateRangePicker';
152
+ //# sourceMappingURL=DateRangePicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DateRangePicker.js","sourceRoot":"","sources":["../../src/components/DateRangePicker.tsx"],"names":[],"mappings":"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"}
@@ -15,6 +15,16 @@ export interface HeaderProps extends Omit<React.HTMLAttributes<HTMLElement>, 'on
15
15
  onOpenChange?: (open: boolean) => void;
16
16
  /** Accessible name for the mobile menu toggle. */
17
17
  menuLabel?: string;
18
+ /**
19
+ * What the mobile toggle opens.
20
+ *
21
+ * `panel` (default) is Figma's Mobile-Open: `center` and `end` drop below the
22
+ * bar. `dialog` is for an app whose navigation lives in a Sidebar: the toggle
23
+ * sits at the start of the bar and only reports `onOpenChange`, the caller
24
+ * opens a Drawer with it, and `center` and `end` stay in the bar at every
25
+ * width — so keep `center` empty and `end` short.
26
+ */
27
+ menuType?: 'panel' | 'dialog';
18
28
  children?: React.ReactNode;
19
29
  }
20
30
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/components/Header.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AA2BxE,MAAM,WAAW,WAAY,SAAQ,IAAI,CACvC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EACjC,UAAU,CACX;IACC,+DAA+D;IAC/D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB;iEAC6D;IAC7D,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,kFAAkF;IAClF,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,MAAM,iFAwElB,CAAC"}
1
+ {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../src/components/Header.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AA2BxE,MAAM,WAAW,WAAY,SAAQ,IAAI,CACvC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EACjC,UAAU,CACX;IACC,+DAA+D;IAC/D,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB;iEAC6D;IAC7D,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,kFAAkF;IAClF,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,mDAAmD;IACnD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC9B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,MAAM,iFAgGlB,CAAC"}
@@ -42,7 +42,7 @@ const CloseGlyph = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "ari
42
42
  * A `<header>` element with no explicit role: it is a landmark already when it
43
43
  * is a direct child of body, which is where a page header sits.
44
44
  */
45
- export const Header = forwardRef(({ brand, center, end, open: openProp, defaultOpen = false, onOpenChange, menuLabel = 'Menu', className, children, ...rest }, ref) => {
45
+ export const Header = forwardRef(({ brand, center, end, open: openProp, defaultOpen = false, onOpenChange, menuLabel = 'Menu', menuType = 'panel', className, children, ...rest }, ref) => {
46
46
  const menuId = useId();
47
47
  const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
48
48
  const isControlled = openProp !== undefined;
@@ -59,12 +59,27 @@ export const Header = forwardRef(({ brand, center, end, open: openProp, defaultO
59
59
  * and it is handled on the header rather than the document so a header that
60
60
  * is never open never listens.
61
61
  */
62
+ const isDialog = menuType === 'dialog';
62
63
  const handleKeyDown = (event) => {
63
- if (event.key === 'Escape' && isOpen)
64
+ // A dialog owns its own Escape; the header only closes its own panel.
65
+ if (event.key === 'Escape' && isOpen && !isDialog)
64
66
  toggle();
65
67
  rest.onKeyDown?.(event);
66
68
  };
67
- return (_jsxs("header", { ...rest, onKeyDown: handleKeyDown, ref: ref, "data-open": isOpen || undefined, className: ['ion-header', className].filter(Boolean).join(' '), children: [brand && _jsx("div", { className: "ion-header__brand", children: brand }), _jsxs("div", { className: "ion-header__menu", id: menuId, children: [_jsx("div", { className: "ion-header__center", children: center }), _jsx("div", { className: "ion-header__end", children: end })] }), children, _jsx("button", { type: "button", className: "ion-header__toggle", "aria-expanded": isOpen, "aria-controls": menuId, "aria-label": menuLabel, onClick: toggle, children: isOpen ? _jsx(CloseGlyph, {}) : _jsx(MenuGlyph, {}) })] }));
69
+ /*
70
+ * As a panel the toggle discloses the menu wrapper, which is always in the
71
+ * DOM, so aria-controls can point at it. As a dialog it opens something the
72
+ * caller mounts only while open — an aria-controls pointing at a missing id
73
+ * is an error — so it says what it opens with aria-haspopup instead.
74
+ */
75
+ const toggleButton = (_jsx("button", { type: "button", className: "ion-header__toggle", "aria-expanded": isOpen, "aria-controls": isDialog ? undefined : menuId, "aria-haspopup": isDialog ? 'dialog' : undefined, "aria-label": menuLabel, onClick: toggle, children: isOpen && !isDialog ? _jsx(CloseGlyph, {}) : _jsx(MenuGlyph, {}) }));
76
+ return (_jsxs("header", { ...rest, onKeyDown: handleKeyDown, ref: ref, "data-open": (isOpen && !isDialog) || undefined, className: [
77
+ 'ion-header',
78
+ isDialog ? 'ion-header--dialog-menu' : '',
79
+ className,
80
+ ]
81
+ .filter(Boolean)
82
+ .join(' '), children: [isDialog && toggleButton, brand && _jsx("div", { className: "ion-header__brand", children: brand }), _jsxs("div", { className: "ion-header__menu", id: menuId, children: [_jsx("div", { className: "ion-header__center", children: center }), _jsx("div", { className: "ion-header__end", children: end })] }), children, !isDialog && toggleButton] }));
68
83
  });
69
84
  Header.displayName = 'Header';
70
85
  //# sourceMappingURL=Header.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/components/Header.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Header.js","sourceRoot":"","sources":["../../src/components/Header.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import type { AriaNumberFieldProps } from 'react-aria';
3
+ export type NumberInputSize = 'sm' | 'md' | 'lg';
4
+ type NumberInputDOMProps = Omit<React.InputHTMLAttributes<HTMLInputElement>, keyof AriaNumberFieldProps | 'size' | 'type' | 'min' | 'max' | 'step' | 'disabled' | 'value' | 'defaultValue' | 'onChange'>;
5
+ export interface NumberInputProps extends Omit<AriaNumberFieldProps, 'value' | 'defaultValue' | 'onChange'>, NumberInputDOMProps {
6
+ /**
7
+ * Controlled value. `null` is empty — never `NaN`, which is what the
8
+ * underlying hook uses and which fails every `===` check a caller writes.
9
+ */
10
+ value?: number | null;
11
+ /** Uncontrolled starting value. `null` for empty. */
12
+ defaultValue?: number | null;
13
+ /**
14
+ * Fires when the value is committed — on blur, Enter, a step button or an
15
+ * arrow key — not on every keystroke. `null` when the field was cleared.
16
+ */
17
+ onChange?: (value: number | null) => void;
18
+ /** Matches Input's `size`: Small, Medium, Large. */
19
+ size?: NumberInputSize;
20
+ /**
21
+ * The − and + buttons. On by default; turn off for a dense table cell where
22
+ * the arrow keys are enough.
23
+ */
24
+ showStepper?: boolean;
25
+ /** Class names for the control box (`.ion-input`). */
26
+ className?: string;
27
+ /** Class names for the `.ion-field` wrapper when a label or helper is shown. */
28
+ wrapperClassName?: string;
29
+ }
30
+ /**
31
+ * NumberInput — a quantity, with formatting, bounds and steps.
32
+ *
33
+ * NOT `<input type="number">`, and the list of reasons is the component:
34
+ *
35
+ * It scrolls. A focused `type="number"` changes value under the mouse wheel,
36
+ * so a user scrolling the page past a price field edits the price. The wheel
37
+ * is OFF here by default (`isWheelDisabled`), and a caller has to ask for it.
38
+ *
39
+ * It cannot format. "1,234.50", "€12", "15%" are text to the browser's number
40
+ * input, which rejects them. `formatOptions` takes `Intl.NumberFormatOptions`,
41
+ * so currency, percent and units display and parse in the user's locale —
42
+ * including "1.234,50" for a German user.
43
+ *
44
+ * It is not a number to the browser's validation either. `type="text"` with
45
+ * the right `inputMode` gets the numeric keyboard on a phone without
46
+ * Firefox letting letters in and Chrome silently reporting an empty value.
47
+ *
48
+ * EMPTY IS `null`, NOT `NaN`. React Aria reports an empty field as `NaN`, and
49
+ * `NaN === NaN` is false — so every "is it empty" check a caller writes is
50
+ * wrong. This converts at the boundary, both ways.
51
+ *
52
+ * − AND + SIT SIDE BY SIDE, NOT STACKED. Stacked chevrons split the field's
53
+ * height in two, which puts a Small field's targets at 16px — under the 24px
54
+ * WCAG 2.5.8 asks. Side by side, every size clears it. They are out of the tab
55
+ * order, as React Aria sets them: the arrow keys do the same job from the field,
56
+ * and two extra tab stops per number on a form is a tax on every keyboard user.
57
+ *
58
+ * The box is Input's, class for class, so every state — hover, focus, invalid,
59
+ * read-only, disabled — is Input's and cannot drift from it.
60
+ */
61
+ export declare const NumberInput: React.ForwardRefExoticComponent<NumberInputProps & React.RefAttributes<HTMLInputElement>>;
62
+ export {};
63
+ //# sourceMappingURL=NumberInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NumberInput.d.ts","sourceRoot":"","sources":["../../src/components/NumberInput.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAkD,MAAM,OAAO,CAAC;AASvE,OAAO,KAAK,EAAmB,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAIxE,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjD,KAAK,mBAAmB,GAAG,IAAI,CAC7B,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EACzC,MAAM,oBAAoB,GAC1B,MAAM,GACN,MAAM,GACN,KAAK,GACL,KAAK,GACL,MAAM,GACN,UAAU,GACV,OAAO,GACP,cAAc,GACd,UAAU,CACb,CAAC;AAEF,MAAM,WAAW,gBACf,SACE,IAAI,CAAC,oBAAoB,EAAE,OAAO,GAAG,cAAc,GAAG,UAAU,CAAC,EACjE,mBAAmB;IACrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1C,oDAAoD;IACpD,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAoDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,WAAW,2FA4HvB,CAAC"}