ionbase-ui 0.51.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 (174) hide show
  1. package/dist/components/Accordion.d.ts +54 -0
  2. package/dist/components/Accordion.d.ts.map +1 -0
  3. package/dist/components/Accordion.js +68 -0
  4. package/dist/components/Accordion.js.map +1 -0
  5. package/dist/components/AgentActivity.d.ts +2 -1
  6. package/dist/components/AgentActivity.d.ts.map +1 -1
  7. package/dist/components/AgentActivity.js +4 -17
  8. package/dist/components/AgentActivity.js.map +1 -1
  9. package/dist/components/Breadcrumb.d.ts +45 -0
  10. package/dist/components/Breadcrumb.d.ts.map +1 -0
  11. package/dist/components/Breadcrumb.js +31 -0
  12. package/dist/components/Breadcrumb.js.map +1 -0
  13. package/dist/components/Calendar.d.ts +20 -0
  14. package/dist/components/Calendar.d.ts.map +1 -0
  15. package/dist/components/Calendar.js +151 -0
  16. package/dist/components/Calendar.js.map +1 -0
  17. package/dist/components/CalendarPopover.d.ts +26 -0
  18. package/dist/components/CalendarPopover.d.ts.map +1 -0
  19. package/dist/components/CalendarPopover.js +45 -0
  20. package/dist/components/CalendarPopover.js.map +1 -0
  21. package/dist/components/Checkbox.d.ts +2 -1
  22. package/dist/components/Checkbox.d.ts.map +1 -1
  23. package/dist/components/Checkbox.js +4 -2
  24. package/dist/components/Checkbox.js.map +1 -1
  25. package/dist/components/Combobox.d.ts +86 -0
  26. package/dist/components/Combobox.d.ts.map +1 -0
  27. package/dist/components/Combobox.js +261 -0
  28. package/dist/components/Combobox.js.map +1 -0
  29. package/dist/components/DateField.d.ts +15 -0
  30. package/dist/components/DateField.d.ts.map +1 -0
  31. package/dist/components/DateField.js +74 -0
  32. package/dist/components/DateField.js.map +1 -0
  33. package/dist/components/DatePicker.d.ts +81 -0
  34. package/dist/components/DatePicker.d.ts.map +1 -0
  35. package/dist/components/DatePicker.js +102 -0
  36. package/dist/components/DatePicker.js.map +1 -0
  37. package/dist/components/DateRangePicker.d.ts +117 -0
  38. package/dist/components/DateRangePicker.d.ts.map +1 -0
  39. package/dist/components/DateRangePicker.js +152 -0
  40. package/dist/components/DateRangePicker.js.map +1 -0
  41. package/dist/components/Drawer.d.ts +52 -0
  42. package/dist/components/Drawer.d.ts.map +1 -0
  43. package/dist/components/Drawer.js +66 -0
  44. package/dist/components/Drawer.js.map +1 -0
  45. package/dist/components/FileUpload.d.ts +79 -0
  46. package/dist/components/FileUpload.d.ts.map +1 -0
  47. package/dist/components/FileUpload.js +218 -0
  48. package/dist/components/FileUpload.js.map +1 -0
  49. package/dist/components/Header.d.ts +10 -0
  50. package/dist/components/Header.d.ts.map +1 -1
  51. package/dist/components/Header.js +18 -3
  52. package/dist/components/Header.js.map +1 -1
  53. package/dist/components/NumberInput.d.ts +63 -0
  54. package/dist/components/NumberInput.d.ts.map +1 -0
  55. package/dist/components/NumberInput.js +102 -0
  56. package/dist/components/NumberInput.js.map +1 -0
  57. package/dist/components/ProgressBar.d.ts +46 -0
  58. package/dist/components/ProgressBar.d.ts.map +1 -0
  59. package/dist/components/ProgressBar.js +52 -0
  60. package/dist/components/ProgressBar.js.map +1 -0
  61. package/dist/components/PromptInput.d.ts +89 -0
  62. package/dist/components/PromptInput.d.ts.map +1 -0
  63. package/dist/components/PromptInput.js +130 -0
  64. package/dist/components/PromptInput.js.map +1 -0
  65. package/dist/components/SegmentedControl.d.ts +63 -0
  66. package/dist/components/SegmentedControl.d.ts.map +1 -0
  67. package/dist/components/SegmentedControl.js +79 -0
  68. package/dist/components/SegmentedControl.js.map +1 -0
  69. package/dist/components/Select.d.ts +9 -2
  70. package/dist/components/Select.d.ts.map +1 -1
  71. package/dist/components/Select.js.map +1 -1
  72. package/dist/components/Sidebar.d.ts +109 -0
  73. package/dist/components/Sidebar.d.ts.map +1 -0
  74. package/dist/components/Sidebar.js +106 -0
  75. package/dist/components/Sidebar.js.map +1 -0
  76. package/dist/components/Skeleton.d.ts +39 -0
  77. package/dist/components/Skeleton.d.ts.map +1 -0
  78. package/dist/components/Skeleton.js +50 -0
  79. package/dist/components/Skeleton.js.map +1 -0
  80. package/dist/components/Spinner.d.ts +45 -0
  81. package/dist/components/Spinner.d.ts.map +1 -0
  82. package/dist/components/Spinner.js +44 -0
  83. package/dist/components/Spinner.js.map +1 -0
  84. package/dist/components/Stepper.d.ts +73 -0
  85. package/dist/components/Stepper.d.ts.map +1 -0
  86. package/dist/components/Stepper.js +82 -0
  87. package/dist/components/Stepper.js.map +1 -0
  88. package/dist/components/Toggle.d.ts +2 -1
  89. package/dist/components/Toggle.d.ts.map +1 -1
  90. package/dist/components/Toggle.js +4 -2
  91. package/dist/components/Toggle.js.map +1 -1
  92. package/dist/components/ToolCall.d.ts +66 -0
  93. package/dist/components/ToolCall.d.ts.map +1 -0
  94. package/dist/components/ToolCall.js +78 -0
  95. package/dist/components/ToolCall.js.map +1 -0
  96. package/dist/components/agent-status.d.ts +14 -0
  97. package/dist/components/agent-status.d.ts.map +1 -0
  98. package/dist/components/agent-status.js +16 -0
  99. package/dist/components/agent-status.js.map +1 -0
  100. package/dist/components/index.d.ts +33 -0
  101. package/dist/components/index.d.ts.map +1 -1
  102. package/dist/components/index.js +16 -0
  103. package/dist/components/index.js.map +1 -1
  104. package/dist/components/iso-date.d.ts +53 -0
  105. package/dist/components/iso-date.d.ts.map +1 -0
  106. package/dist/components/iso-date.js +102 -0
  107. package/dist/components/iso-date.js.map +1 -0
  108. package/dist/components/resolve-selection.d.ts +36 -0
  109. package/dist/components/resolve-selection.d.ts.map +1 -0
  110. package/dist/components/resolve-selection.js +14 -0
  111. package/dist/components/resolve-selection.js.map +1 -0
  112. package/dist/figma-descriptions.json +255 -145
  113. package/dist/figma-map.json +3205 -1860
  114. package/dist/meta/Accordion.json +123 -0
  115. package/dist/meta/AccordionItem.json +90 -0
  116. package/dist/meta/AgentActivityStep.json +2 -2
  117. package/dist/meta/Breadcrumb.json +87 -0
  118. package/dist/meta/BreadcrumbItem.json +78 -0
  119. package/dist/meta/Checkbox.json +18 -1
  120. package/dist/meta/Combobox.json +265 -0
  121. package/dist/meta/DatePicker.json +270 -0
  122. package/dist/meta/DateRangePicker.json +284 -0
  123. package/dist/meta/Drawer.json +234 -0
  124. package/dist/meta/EmptyState.json +1 -1
  125. package/dist/meta/FileUpload.json +246 -0
  126. package/dist/meta/Header.json +32 -2
  127. package/dist/meta/NumberInput.json +407 -0
  128. package/dist/meta/PhoneInput.json +39 -39
  129. package/dist/meta/Popover.json +3 -3
  130. package/dist/meta/ProgressBar.json +166 -0
  131. package/dist/meta/PromptInput.json +212 -0
  132. package/dist/meta/SegmentedControl.json +217 -0
  133. package/dist/meta/SegmentedControlItem.json +122 -0
  134. package/dist/meta/Select.json +4 -3
  135. package/dist/meta/Sidebar.json +150 -0
  136. package/dist/meta/SidebarItem.json +184 -0
  137. package/dist/meta/SidebarSection.json +131 -0
  138. package/dist/meta/Skeleton.json +120 -0
  139. package/dist/meta/Spinner.json +123 -0
  140. package/dist/meta/Stepper.json +135 -0
  141. package/dist/meta/StepperStep.json +148 -0
  142. package/dist/meta/Tabs.json +5 -0
  143. package/dist/meta/Toggle.json +18 -1
  144. package/dist/meta/ToolCall.json +192 -0
  145. package/dist/meta/Tooltip.json +3 -3
  146. package/dist/meta/components.json +6759 -2705
  147. package/dist/meta/contrast.json +11075 -3098
  148. package/dist/meta/index.json +266 -8
  149. package/dist/meta/patterns/AgentRun.json +27 -0
  150. package/dist/meta/patterns/Form.json +9 -0
  151. package/dist/meta/patterns/PageShell.json +43 -3
  152. package/dist/meta/patterns/Wizard.json +20 -1
  153. package/dist/meta/patterns/index.json +10 -1
  154. package/dist/styles/accordion.css +102 -0
  155. package/dist/styles/breadcrumb.css +72 -0
  156. package/dist/styles/combobox.css +154 -0
  157. package/dist/styles/date-picker.css +420 -0
  158. package/dist/styles/date-range-picker.css +280 -0
  159. package/dist/styles/drawer.css +181 -0
  160. package/dist/styles/empty-state.css +16 -4
  161. package/dist/styles/file-upload.css +236 -0
  162. package/dist/styles/header.css +26 -0
  163. package/dist/styles/index.css +23 -0
  164. package/dist/styles/number-input.css +83 -0
  165. package/dist/styles/progress-bar.css +107 -0
  166. package/dist/styles/prompt-input.css +127 -0
  167. package/dist/styles/segmented-control.css +182 -0
  168. package/dist/styles/sidebar.css +307 -0
  169. package/dist/styles/skeleton.css +76 -0
  170. package/dist/styles/spinner.css +70 -0
  171. package/dist/styles/stepper.css +250 -0
  172. package/dist/styles/tool-call.css +202 -0
  173. package/llms.txt +2 -2
  174. package/package.json +2 -1
@@ -0,0 +1,218 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useId, useRef, useState } from 'react';
4
+ const UploadIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M12 16V4m0 0L8 8m4-4 4 4M4 16v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
5
+ const RemoveIcon = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M18 6 6 18M6 6l12 12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }));
6
+ /**
7
+ * Bytes as a person would say them.
8
+ *
9
+ * Decimal units, not binary: a disk sold as 500 GB and a browser reporting a
10
+ * file size both mean powers of 1000, and showing "476 MiB" for a 500 MB file
11
+ * is correct arithmetic and a confusing answer.
12
+ */
13
+ const formatBytes = (bytes) => {
14
+ if (bytes < 1000)
15
+ return `${bytes} B`;
16
+ const units = ['kB', 'MB', 'GB', 'TB'];
17
+ let value = bytes / 1000;
18
+ let unit = 0;
19
+ while (value >= 1000 && unit < units.length - 1) {
20
+ value /= 1000;
21
+ unit += 1;
22
+ }
23
+ return `${value < 10 ? value.toFixed(1) : Math.round(value)} ${units[unit]}`;
24
+ };
25
+ /**
26
+ * Does a file match an `accept` list?
27
+ *
28
+ * The browser enforces `accept` in its own picker but NOT on drop, and not at
29
+ * all if the user switches the picker's filter to "All files" — which every
30
+ * platform picker offers. So the check is repeated here. Treating the native
31
+ * attribute as a guarantee is the standard way a drop zone ends up holding a
32
+ * .exe someone dragged into it.
33
+ */
34
+ const matchesAccept = (file, accept) => {
35
+ if (!accept)
36
+ return true;
37
+ const name = file.name.toLowerCase();
38
+ const type = file.type.toLowerCase();
39
+ return accept.split(',').some((raw) => {
40
+ const token = raw.trim().toLowerCase();
41
+ if (!token)
42
+ return false;
43
+ if (token.startsWith('.'))
44
+ return name.endsWith(token);
45
+ if (token.endsWith('/*'))
46
+ return type.startsWith(token.slice(0, -1));
47
+ return type === token;
48
+ });
49
+ };
50
+ /**
51
+ * FileUpload — a drop target wrapped around a real `<input type="file">`.
52
+ *
53
+ * Drawn in Figma as `File Upload` (1367:2333) — two sizes by five states. The
54
+ * measurements came from `Input` and `EmptyState` rather than being invented:
55
+ * the border, radius and disabled treatment are Input's; the centred
56
+ * icon-over-text stack is EmptyState's. Figma draws the drop zone alone, the
57
+ * same split `Input` makes against `Form Field`.
58
+ *
59
+ * THE INPUT IS THE CONTROL. THE DROP ZONE IS DECORATION.
60
+ *
61
+ * The usual build of this component is a `<div>` with drag handlers and a
62
+ * click that calls `input.click()`. That version cannot be reached by keyboard,
63
+ * has no accessible name, does not participate in a form, and does not work in
64
+ * any environment without a pointer — which includes switch access, voice
65
+ * control and most screen-reader browse modes.
66
+ *
67
+ * Here the file input is a real, focusable, labelled control that is visually
68
+ * hidden but NOT `display: none` — it keeps its place in the tab order and its
69
+ * label. Drag-and-drop is layered on top as an enhancement, and every path it
70
+ * offers is also reachable without it. That ordering is the whole component.
71
+ *
72
+ * VALIDATION IS ADVISORY, NOT SECURITY. `accept` and `maxSize` are checked here
73
+ * so the user finds out immediately instead of after an upload. A server that
74
+ * trusts either one is trusting a value the client chose.
75
+ */
76
+ export function FileUpload({ label, description, errorMessage, isInvalid, isDisabled: isDisabledProp, size = 'md', accept, multiple, maxSize, maxFiles, files: controlledFiles, onChange, onReject, prompt, hint, removeLabel = (name) => `Remove ${name}`, className, wrapperClassName, id: providedId, name: inputName, }) {
77
+ /* No `disabled` alias to resolve: FileUpload is new, so it never had one. */
78
+ const isDisabled = isDisabledProp ?? false;
79
+ const generatedId = useId();
80
+ const id = providedId ?? generatedId;
81
+ const helperId = `${id}-helper`;
82
+ const hintId = `${id}-hint`;
83
+ const inputRef = useRef(null);
84
+ const [uncontrolled, setUncontrolled] = useState([]);
85
+ const [isDragging, setIsDragging] = useState(false);
86
+ /*
87
+ * A depth counter, not a boolean. `dragleave` fires every time the pointer
88
+ * crosses into a CHILD element, so a boolean flickers off whenever the
89
+ * cursor passes over the icon or the prompt text. Counting enter/leave pairs
90
+ * is the only version that survives having children.
91
+ */
92
+ const dragDepth = useRef(0);
93
+ const files = controlledFiles ? [...controlledFiles] : uncontrolled;
94
+ const commit = useCallback((next) => {
95
+ if (!controlledFiles)
96
+ setUncontrolled(next);
97
+ onChange?.(next);
98
+ }, [controlledFiles, onChange]);
99
+ const add = useCallback((incoming) => {
100
+ if (isDisabled || incoming.length === 0)
101
+ return;
102
+ const accepted = [];
103
+ const rejected = [];
104
+ /*
105
+ * Room is counted against what is already held, so dropping four files
106
+ * onto a control holding two with maxFiles=3 accepts one and reports
107
+ * three — rather than accepting all four or refusing the lot.
108
+ */
109
+ let room = multiple ? (maxFiles ?? Infinity) - files.length : 1;
110
+ for (const file of incoming) {
111
+ if (!matchesAccept(file, accept)) {
112
+ rejected.push({
113
+ file,
114
+ reason: 'type',
115
+ message: `${file.name} is not an accepted file type.`,
116
+ });
117
+ }
118
+ else if (maxSize !== undefined && file.size > maxSize) {
119
+ rejected.push({
120
+ file,
121
+ reason: 'size',
122
+ message: `${file.name} is ${formatBytes(file.size)}, over the ${formatBytes(maxSize)} limit.`,
123
+ });
124
+ }
125
+ else if (room <= 0) {
126
+ rejected.push({
127
+ file,
128
+ reason: 'count',
129
+ message: multiple
130
+ ? `${file.name} was not added — at most ${maxFiles} files.`
131
+ : `${file.name} was not added — only one file is allowed.`,
132
+ });
133
+ }
134
+ else {
135
+ accepted.push(file);
136
+ room -= 1;
137
+ }
138
+ }
139
+ if (accepted.length)
140
+ commit(multiple ? [...files, ...accepted] : accepted);
141
+ if (rejected.length)
142
+ onReject?.(rejected);
143
+ }, [accept, commit, files, isDisabled, maxFiles, maxSize, multiple, onReject]);
144
+ const remove = (index) => {
145
+ commit(files.filter((_, i) => i !== index));
146
+ /*
147
+ * Clearing the input's own value matters: a browser fires no `change` when
148
+ * the same file is picked twice in a row, so removing a file and picking it
149
+ * again would silently do nothing.
150
+ */
151
+ if (inputRef.current)
152
+ inputRef.current.value = '';
153
+ };
154
+ const helper = isInvalid && errorMessage ? errorMessage : description;
155
+ const zoneClassNames = [
156
+ 'ion-file-upload',
157
+ size !== 'md' ? `ion-file-upload--${size}` : '',
158
+ isDragging ? 'ion-file-upload--dragging' : '',
159
+ isInvalid ? 'ion-file-upload--invalid' : '',
160
+ isDisabled ? 'ion-file-upload--disabled' : '',
161
+ className || '',
162
+ ]
163
+ .filter(Boolean)
164
+ .join(' ');
165
+ const zone = (_jsxs("div", { className: zoneClassNames, "data-dragging": isDragging || undefined, "data-invalid": isInvalid || undefined, "data-disabled": isDisabled || undefined, onDragEnter: (e) => {
166
+ if (isDisabled)
167
+ return;
168
+ e.preventDefault();
169
+ dragDepth.current += 1;
170
+ setIsDragging(true);
171
+ }, onDragOver: (e) => {
172
+ if (isDisabled)
173
+ return;
174
+ // Without this the browser navigates to the dropped file. There is no
175
+ // other reason for a dragover handler that only calls preventDefault.
176
+ e.preventDefault();
177
+ }, onDragLeave: () => {
178
+ dragDepth.current = Math.max(0, dragDepth.current - 1);
179
+ if (dragDepth.current === 0)
180
+ setIsDragging(false);
181
+ }, onDrop: (e) => {
182
+ if (isDisabled)
183
+ return;
184
+ e.preventDefault();
185
+ dragDepth.current = 0;
186
+ setIsDragging(false);
187
+ add(Array.from(e.dataTransfer.files));
188
+ }, children: [_jsx("input", { ref: inputRef, type: "file", id: id, name: inputName, className: "ion-file-upload__input", accept: accept, multiple: multiple, disabled: isDisabled, "aria-describedby": [hint ? hintId : null, helper ? helperId : null]
189
+ .filter(Boolean)
190
+ .join(' ') || undefined, "aria-invalid": isInvalid || undefined, onChange: (e) => {
191
+ add(Array.from(e.target.files ?? []));
192
+ // Same reason as remove(): re-picking an identical file must fire.
193
+ e.target.value = '';
194
+ } }), _jsxs("label", { htmlFor: id, className: "ion-file-upload__target", children: [_jsx("span", { className: "ion-file-upload__icon", "aria-hidden": "true", children: _jsx(UploadIcon, {}) }), _jsx("span", { className: "ion-file-upload__prompt", children: prompt ??
195
+ (multiple
196
+ ? 'Choose files or drag them here'
197
+ : 'Choose a file or drag it here') }), hint && (_jsx("span", { id: hintId, className: "ion-file-upload__hint", children: hint }))] })] }));
198
+ const list = files.length > 0 && (_jsx("ul", { className: "ion-file-upload__list", children: files.map((file, index) => (_jsxs("li", { className: "ion-file-upload__file", children: [_jsx("span", { className: "ion-file-upload__name", children: file.name }), _jsx("span", { className: "ion-file-upload__size", children: formatBytes(file.size) }), _jsx("button", { type: "button", className: "ion-file-upload__remove", "aria-label": removeLabel(file.name), disabled: isDisabled, onClick: () => remove(index), children: _jsx(RemoveIcon, {}) })] }, `${file.name}-${file.size}-${index}`))) }));
199
+ /*
200
+ * The count, announced. A file added by drop produces no focus change and no
201
+ * visible change anywhere near the user's attention, so without this a screen
202
+ * reader user gets no confirmation that the drop did anything at all. Polite,
203
+ * and the count rather than the names: reading six filenames over an
204
+ * assertive interruption is worse than saying how many there now are.
205
+ */
206
+ const status = (_jsx("span", { className: "ion-visually-hidden", role: "status", "aria-live": "polite", children: files.length === 0
207
+ ? ''
208
+ : `${files.length} file${files.length === 1 ? '' : 's'} selected` }));
209
+ return (_jsxs("div", { className: [
210
+ 'ion-field',
211
+ isInvalid ? 'ion-field--error' : '',
212
+ wrapperClassName || '',
213
+ ]
214
+ .filter(Boolean)
215
+ .join(' '), children: [label && (_jsx("label", { htmlFor: id, className: "ion-field__label", children: label })), zone, list, status, helper && (_jsx("span", { id: helperId, className: "ion-field__helper", children: helper }))] }));
216
+ }
217
+ FileUpload.displayName = 'FileUpload';
218
+ //# sourceMappingURL=FileUpload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FileUpload.js","sourceRoot":"","sources":["../../src/components/FileUpload.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"}
@@ -0,0 +1,102 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { forwardRef, useImperativeHandle, useRef } from 'react';
4
+ import { mergeProps, useButton, useFocusRing, useHover, useLocale, useNumberField, } from 'react-aria';
5
+ import { useNumberFieldState } from 'react-stately';
6
+ import { ARIA_TEXT_FIELD_NON_DOM_PROPS, omitProps } from './dom-props.js';
7
+ /* Props this component or the number-field hook consume, on top of a text field's. */
8
+ const NUMBER_FIELD_NON_DOM_PROPS = [
9
+ ...ARIA_TEXT_FIELD_NON_DOM_PROPS,
10
+ 'minValue',
11
+ 'maxValue',
12
+ 'step',
13
+ 'formatOptions',
14
+ 'commitBehavior',
15
+ 'isWheelDisabled',
16
+ 'incrementAriaLabel',
17
+ 'decrementAriaLabel',
18
+ ];
19
+ const Minus = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M6 12h12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
20
+ const Plus = () => (_jsx("svg", { viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: "M12 6v12M6 12h12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
21
+ function StepButton({ children, ...props }) {
22
+ const ref = useRef(null);
23
+ const { buttonProps } = useButton(props, ref);
24
+ return (_jsx("button", { ...buttonProps, ref: ref, className: "ion-number-input__step", children: children }));
25
+ }
26
+ const toHook = (v) => (v === null ? NaN : v);
27
+ /**
28
+ * NumberInput — a quantity, with formatting, bounds and steps.
29
+ *
30
+ * NOT `<input type="number">`, and the list of reasons is the component:
31
+ *
32
+ * It scrolls. A focused `type="number"` changes value under the mouse wheel,
33
+ * so a user scrolling the page past a price field edits the price. The wheel
34
+ * is OFF here by default (`isWheelDisabled`), and a caller has to ask for it.
35
+ *
36
+ * It cannot format. "1,234.50", "€12", "15%" are text to the browser's number
37
+ * input, which rejects them. `formatOptions` takes `Intl.NumberFormatOptions`,
38
+ * so currency, percent and units display and parse in the user's locale —
39
+ * including "1.234,50" for a German user.
40
+ *
41
+ * It is not a number to the browser's validation either. `type="text"` with
42
+ * the right `inputMode` gets the numeric keyboard on a phone without
43
+ * Firefox letting letters in and Chrome silently reporting an empty value.
44
+ *
45
+ * EMPTY IS `null`, NOT `NaN`. React Aria reports an empty field as `NaN`, and
46
+ * `NaN === NaN` is false — so every "is it empty" check a caller writes is
47
+ * wrong. This converts at the boundary, both ways.
48
+ *
49
+ * − AND + SIT SIDE BY SIDE, NOT STACKED. Stacked chevrons split the field's
50
+ * height in two, which puts a Small field's targets at 16px — under the 24px
51
+ * WCAG 2.5.8 asks. Side by side, every size clears it. They are out of the tab
52
+ * order, as React Aria sets them: the arrow keys do the same job from the field,
53
+ * and two extra tab stops per number on a form is a tax on every keyboard user.
54
+ *
55
+ * The box is Input's, class for class, so every state — hover, focus, invalid,
56
+ * read-only, disabled — is Input's and cannot drift from it.
57
+ */
58
+ export const NumberInput = forwardRef((props, forwardedRef) => {
59
+ const { size = 'md', showStepper = true, isWheelDisabled = true, value, defaultValue, onChange, label, description, errorMessage, isDisabled, isReadOnly, className, wrapperClassName, ...rest } = props;
60
+ const { locale } = useLocale();
61
+ const hookProps = {
62
+ ...props,
63
+ isWheelDisabled,
64
+ value: value === undefined ? undefined : toHook(value),
65
+ defaultValue: defaultValue === undefined ? undefined : toHook(defaultValue),
66
+ onChange: onChange
67
+ ? (n) => onChange(Number.isNaN(n) ? null : n)
68
+ : undefined,
69
+ };
70
+ const state = useNumberFieldState({ ...hookProps, locale });
71
+ const ref = useRef(null);
72
+ useImperativeHandle(forwardedRef, () => ref.current);
73
+ const { labelProps, groupProps, inputProps, incrementButtonProps, decrementButtonProps, descriptionProps, errorMessageProps, isInvalid, } = useNumberField(hookProps, state, ref);
74
+ const { hoverProps, isHovered } = useHover({ isDisabled });
75
+ const { focusProps, isFocusVisible } = useFocusRing({ isTextInput: true });
76
+ const domProps = omitProps(rest, NUMBER_FIELD_NON_DOM_PROPS);
77
+ const box = (_jsxs("div", { ...mergeProps(groupProps, hoverProps), "data-hovered": isHovered || undefined, "data-focused": isFocusVisible || undefined, "data-invalid": isInvalid || undefined, "data-readonly": isReadOnly || undefined, "data-disabled": isDisabled || undefined, className: [
78
+ 'ion-input',
79
+ 'ion-number-input',
80
+ size !== 'md' ? `ion-input--${size}` : '',
81
+ showStepper ? 'ion-number-input--stepper' : '',
82
+ isInvalid ? 'ion-input--invalid' : '',
83
+ isReadOnly ? 'ion-input--readonly' : '',
84
+ isDisabled ? 'ion-input--disabled' : '',
85
+ className || '',
86
+ ]
87
+ .filter(Boolean)
88
+ .join(' '), children: [_jsx("input", { ...domProps, ...mergeProps(inputProps, focusProps), ref: ref, className: "ion-input__field ion-number-input__field" }), showStepper && (_jsxs("span", { className: "ion-number-input__steps", children: [_jsx(StepButton, { ...decrementButtonProps, children: _jsx(Minus, {}) }), _jsx(StepButton, { ...incrementButtonProps, children: _jsx(Plus, {}) })] }))] }));
89
+ const helper = isInvalid && errorMessage ? errorMessage : description;
90
+ const helperProps = isInvalid && errorMessage ? errorMessageProps : descriptionProps;
91
+ if (!label && !helper)
92
+ return box;
93
+ return (_jsxs("div", { className: [
94
+ 'ion-field',
95
+ isInvalid ? 'ion-field--error' : '',
96
+ wrapperClassName || '',
97
+ ]
98
+ .filter(Boolean)
99
+ .join(' '), children: [label && (_jsx("label", { ...labelProps, className: "ion-field__label", children: label })), box, helper && (_jsx("span", { ...helperProps, className: "ion-field__helper", children: helper }))] }));
100
+ });
101
+ NumberInput.displayName = 'NumberInput';
102
+ //# sourceMappingURL=NumberInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NumberInput.js","sourceRoot":"","sources":["../../src/components/NumberInput.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ export type ProgressBarIntent = 'primary' | 'success' | 'warning' | 'error';
3
+ export type ProgressBarSize = 'sm' | 'md';
4
+ export interface ProgressBarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
5
+ /** What is progressing. Required — a bare bar announces a number and no noun. */
6
+ label: string;
7
+ /** 0 to `max`. Omit for an indeterminate bar. */
8
+ value?: number;
9
+ /** Defaults to 100. */
10
+ max?: number;
11
+ intent?: ProgressBarIntent;
12
+ size?: ProgressBarSize;
13
+ /** Show the label as text above the track. */
14
+ isLabelVisible?: boolean;
15
+ /** Show the percentage beside the label. Determinate bars only. */
16
+ isValueVisible?: boolean;
17
+ /**
18
+ * Spoken instead of the percentage — "3 of 12 files". A percentage is rarely
19
+ * the thing a person wants read aloud.
20
+ */
21
+ valueText?: string;
22
+ }
23
+ /**
24
+ * ProgressBar — a determinate or indeterminate measure of work.
25
+ *
26
+ * DETERMINATE AND INDETERMINATE ARE THE SAME COMPONENT ON PURPOSE
27
+ *
28
+ * Work that starts unmeasurable and becomes measurable is the common case — a
29
+ * upload that does not know its size until the first chunk lands. Splitting
30
+ * them into two components would make that transition a swap, which remounts
31
+ * the node and loses the live region with it.
32
+ *
33
+ * Omitting `value` is what makes it indeterminate. `aria-valuenow` is then
34
+ * omitted too, which is exactly what the ARIA spec asks for and is the detail
35
+ * hand-rolled progress bars get wrong most often — a bar reporting
36
+ * `aria-valuenow="0"` forever tells a screen reader the work is stuck at zero,
37
+ * not that it is unmeasured.
38
+ *
39
+ * WHY `label` IS REQUIRED
40
+ *
41
+ * `role="progressbar"` announces a number. Without a name the user hears "42
42
+ * percent" with no indication of what is at 42 percent, which is worse than
43
+ * silence because it sounds like information.
44
+ */
45
+ export declare const ProgressBar: React.ForwardRefExoticComponent<ProgressBarProps & React.RefAttributes<HTMLDivElement>>;
46
+ //# sourceMappingURL=ProgressBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBar.d.ts","sourceRoot":"","sources":["../../src/components/ProgressBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAEjD,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAC5E,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;AAE1C,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAC5C,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EACpC,UAAU,CACX;IACC,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,WAAW,yFA6EvB,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useId } from 'react';
3
+ const clamp = (n, max) => Math.min(Math.max(n, 0), max);
4
+ /**
5
+ * ProgressBar — a determinate or indeterminate measure of work.
6
+ *
7
+ * DETERMINATE AND INDETERMINATE ARE THE SAME COMPONENT ON PURPOSE
8
+ *
9
+ * Work that starts unmeasurable and becomes measurable is the common case — a
10
+ * upload that does not know its size until the first chunk lands. Splitting
11
+ * them into two components would make that transition a swap, which remounts
12
+ * the node and loses the live region with it.
13
+ *
14
+ * Omitting `value` is what makes it indeterminate. `aria-valuenow` is then
15
+ * omitted too, which is exactly what the ARIA spec asks for and is the detail
16
+ * hand-rolled progress bars get wrong most often — a bar reporting
17
+ * `aria-valuenow="0"` forever tells a screen reader the work is stuck at zero,
18
+ * not that it is unmeasured.
19
+ *
20
+ * WHY `label` IS REQUIRED
21
+ *
22
+ * `role="progressbar"` announces a number. Without a name the user hears "42
23
+ * percent" with no indication of what is at 42 percent, which is worse than
24
+ * silence because it sounds like information.
25
+ */
26
+ export const ProgressBar = forwardRef(({ label, value, max = 100, intent = 'primary', size = 'md', isLabelVisible = false, isValueVisible = false, valueText, className, ...rest }, ref) => {
27
+ const labelId = useId();
28
+ const isIndeterminate = value === undefined;
29
+ const resolved = isIndeterminate ? 0 : clamp(value, max);
30
+ const pct = max > 0 ? (resolved / max) * 100 : 0;
31
+ const classNames = [
32
+ 'ion-progress-bar',
33
+ intent !== 'primary' ? `ion-progress-bar--${intent}` : '',
34
+ size !== 'md' ? `ion-progress-bar--${size}` : '',
35
+ isIndeterminate ? 'ion-progress-bar--indeterminate' : '',
36
+ className || '',
37
+ ]
38
+ .filter(Boolean)
39
+ .join(' ');
40
+ return (_jsxs("div", { ...rest, ref: ref, className: classNames, children: [_jsxs("div", { className: isLabelVisible ? 'ion-progress-bar__header' : 'ion-visually-hidden', children: [_jsx("span", { id: labelId, className: "ion-progress-bar__label", children: label }), isLabelVisible && isValueVisible && !isIndeterminate && (_jsx("span", { className: "ion-progress-bar__value", children: valueText ?? `${Math.round(pct)}%` }))] }), _jsx("div", { className: "ion-progress-bar__track", role: "progressbar", "aria-labelledby": labelId, "aria-valuemin": 0, "aria-valuemax": max, ...(isIndeterminate
41
+ ? {}
42
+ : {
43
+ 'aria-valuenow': resolved,
44
+ ...(valueText ? { 'aria-valuetext': valueText } : {}),
45
+ }), children: _jsx("div", { className: "ion-progress-bar__fill", style: isIndeterminate
46
+ ? undefined
47
+ : {
48
+ '--ion-progress-bar-pct': `${pct}%`,
49
+ } }) })] }));
50
+ });
51
+ ProgressBar.displayName = 'ProgressBar';
52
+ //# sourceMappingURL=ProgressBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProgressBar.js","sourceRoot":"","sources":["../../src/components/ProgressBar.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AA4BjD,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CACnC,CACE,EACE,KAAK,EACL,KAAK,EACL,GAAG,GAAG,GAAG,EACT,MAAM,GAAG,SAAS,EAClB,IAAI,GAAG,IAAI,EACX,cAAc,GAAG,KAAK,EACtB,cAAc,GAAG,KAAK,EACtB,SAAS,EACT,SAAS,EACT,GAAG,IAAI,EACR,EACD,GAAG,EACH,EAAE;IACF,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IACxB,MAAM,eAAe,GAAG,KAAK,KAAK,SAAS,CAAC;IAC5C,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjD,MAAM,UAAU,GAAG;QACjB,kBAAkB;QAClB,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,qBAAqB,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE;QACzD,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;QAChD,eAAe,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,EAAE;QACxD,SAAS,IAAI,EAAE;KAChB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,OAAO,CACL,kBAAS,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,UAAU,aAC5C,eACE,SAAS,EACP,cAAc,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,qBAAqB,aAGrE,eAAM,EAAE,EAAE,OAAO,EAAE,SAAS,EAAC,yBAAyB,YACnD,KAAK,GACD,EACN,cAAc,IAAI,cAAc,IAAI,CAAC,eAAe,IAAI,CACvD,eAAM,SAAS,EAAC,yBAAyB,YACtC,SAAS,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,GAC9B,CACR,IACG,EAEN,cACE,SAAS,EAAC,yBAAyB,EACnC,IAAI,EAAC,aAAa,qBACD,OAAO,mBACT,CAAC,mBACD,GAAG,KAGd,CAAC,eAAe;oBAClB,CAAC,CAAC,EAAE;oBACJ,CAAC,CAAC;wBACE,eAAe,EAAE,QAAQ;wBACzB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;qBACtD,CAAC,YAEN,cACE,SAAS,EAAC,wBAAwB,EAClC,KAAK,EACH,eAAe;wBACb,CAAC,CAAC,SAAS;wBACX,CAAC,CAAE;4BACC,wBAAwB,EAAE,GAAG,GAAG,GAAG;yBACZ,GAE/B,GACE,IACF,CACP,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,WAAW,CAAC,WAAW,GAAG,aAAa,CAAC"}