@ntmats/hc-ui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  // src/index.tsx
2
- import { forwardRef, useId, useRef } from "react";
3
- import { jsx, jsxs } from "react/jsx-runtime";
4
- function Surface({ tone = "content", className, ...props }) {
5
- return /* @__PURE__ */ jsx("div", { ...props, className: ["hc-ui-surface", className].filter(Boolean).join(" "), "data-tone": tone });
2
+ import { cloneElement, createContext, forwardRef, Fragment, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
3
+ import { createPortal } from "react-dom";
4
+ import { Fragment as Fragment2, jsx, jsxs } from "react/jsx-runtime";
5
+ function Surface({ tone = "content", radius, className, ...props }) {
6
+ return /* @__PURE__ */ jsx("div", { ...props, className: ["hc-ui-surface", className].filter(Boolean).join(" "), "data-tone": tone, "data-radius": radius });
6
7
  }
7
8
  function SegmentedControl({
8
9
  label,
@@ -12,12 +13,24 @@ function SegmentedControl({
12
13
  density = "comfortable",
13
14
  orientation = "horizontal",
14
15
  hideLabels = false,
16
+ indicator = "static",
17
+ equalWidth = false,
18
+ optionWidth,
15
19
  className,
20
+ style,
16
21
  ...props
17
22
  }) {
18
23
  const buttons = useRef([]);
19
24
  const selectedIndex = options.findIndex((option) => option.value === value && !option.disabled);
20
25
  const tabStop = selectedIndex >= 0 ? selectedIndex : options.findIndex((option) => !option.disabled);
26
+ const slide = indicator === "slide";
27
+ const equal = slide || equalWidth || optionWidth !== void 0;
28
+ const knobIndex = options.findIndex((option) => option.value === value);
29
+ const layout = {
30
+ ...equal ? { "--hc-segmented-count": options.length } : {},
31
+ ...slide ? { "--hc-segmented-index": Math.max(knobIndex, 0) } : {},
32
+ ...optionWidth !== void 0 ? { "--hc-segmented-option-width": `${optionWidth}px` } : {}
33
+ };
21
34
  const move = (index, key) => {
22
35
  if (!["ArrowRight", "ArrowLeft", "ArrowDown", "ArrowUp", "Home", "End"].includes(key)) return false;
23
36
  const direction = key === "ArrowRight" || key === "ArrowDown" ? 1 : -1;
@@ -36,7 +49,7 @@ function SegmentedControl({
36
49
  buttons.current[next]?.focus();
37
50
  return true;
38
51
  };
39
- return /* @__PURE__ */ jsx(
52
+ return /* @__PURE__ */ jsxs(
40
53
  "div",
41
54
  {
42
55
  ...props,
@@ -47,35 +60,41 @@ function SegmentedControl({
47
60
  "data-density": density,
48
61
  "data-orientation": orientation,
49
62
  "data-labels": hideLabels ? "hidden" : void 0,
50
- children: options.map((option, index) => {
51
- const selected = option.value === value;
52
- return /* @__PURE__ */ jsxs(
53
- "button",
54
- {
55
- ref: (element) => {
56
- buttons.current[index] = element;
57
- },
58
- type: "button",
59
- role: "radio",
60
- "aria-checked": selected,
61
- "aria-label": option.label,
62
- title: hideLabels ? option.label : void 0,
63
- disabled: option.disabled,
64
- tabIndex: !option.disabled && index === tabStop ? 0 : -1,
65
- className: "hc-ui-segmented__option",
66
- "data-selected": selected || void 0,
67
- onClick: () => !option.disabled && onChange(option.value),
68
- onKeyDown: (event) => {
69
- if (move(index, event.key)) event.preventDefault();
63
+ "data-indicator": slide ? "slide" : void 0,
64
+ "data-equal-width": equal || void 0,
65
+ style: { ...layout, ...style },
66
+ children: [
67
+ slide && knobIndex >= 0 && /* @__PURE__ */ jsx("span", { className: "hc-ui-segmented__indicator", "aria-hidden": "true" }),
68
+ options.map((option, index) => {
69
+ const selected = option.value === value;
70
+ return /* @__PURE__ */ jsxs(
71
+ "button",
72
+ {
73
+ ref: (element) => {
74
+ buttons.current[index] = element;
75
+ },
76
+ type: "button",
77
+ role: "radio",
78
+ "aria-checked": selected,
79
+ "aria-label": option.label,
80
+ title: hideLabels ? option.label : void 0,
81
+ disabled: option.disabled,
82
+ tabIndex: !option.disabled && index === tabStop ? 0 : -1,
83
+ className: "hc-ui-segmented__option",
84
+ "data-selected": selected || void 0,
85
+ onClick: () => !option.disabled && onChange(option.value),
86
+ onKeyDown: (event) => {
87
+ if (move(index, event.key)) event.preventDefault();
88
+ },
89
+ children: [
90
+ option.icon && /* @__PURE__ */ jsx("span", { className: "hc-ui-segmented__icon", "aria-hidden": "true", children: option.icon }),
91
+ !hideLabels && /* @__PURE__ */ jsx("span", { className: "hc-ui-segmented__label", children: option.label })
92
+ ]
70
93
  },
71
- children: [
72
- option.icon && /* @__PURE__ */ jsx("span", { className: "hc-ui-segmented__icon", "aria-hidden": "true", children: option.icon }),
73
- !hideLabels && /* @__PURE__ */ jsx("span", { className: "hc-ui-segmented__label", children: option.label })
74
- ]
75
- },
76
- option.value
77
- );
78
- })
94
+ option.value
95
+ );
96
+ })
97
+ ]
79
98
  }
80
99
  );
81
100
  }
@@ -106,7 +125,7 @@ var Button = forwardRef(function Button2({ variant = "secondary", size = "md", i
106
125
  }
107
126
  );
108
127
  });
109
- var IconButton = forwardRef(function IconButton2({ label, icon, size = "md", tone = "primary", selected, type = "button", title, className, ...props }, ref) {
128
+ var IconButton = forwardRef(function IconButton2({ label, icon, size = "md", tone = "primary", variant = "muted", shape = "circle", selected, iconKey, type = "button", title, className, ...props }, ref) {
110
129
  return /* @__PURE__ */ jsx(
111
130
  "button",
112
131
  {
@@ -119,16 +138,63 @@ var IconButton = forwardRef(function IconButton2({ label, icon, size = "md", ton
119
138
  className: classes("hc-ui-icon-button", className),
120
139
  "data-size": size,
121
140
  "data-tone": tone,
122
- children: /* @__PURE__ */ jsx("span", { className: "hc-ui-icon-button__icon", "aria-hidden": "true", children: icon })
141
+ "data-variant": variant === "muted" ? void 0 : variant,
142
+ "data-shape": shape === "circle" ? void 0 : shape,
143
+ children: /* @__PURE__ */ jsx("span", { className: "hc-ui-icon-button__icon", "aria-hidden": "true", "data-swap": iconKey === void 0 ? void 0 : "", children: icon }, iconKey)
123
144
  }
124
145
  );
125
146
  });
126
- var Chip = forwardRef(function Chip2({ selected, icon, type = "button", className, children, ...props }, ref) {
127
- return /* @__PURE__ */ jsxs("button", { ...props, ref, type, "aria-pressed": selected, className: classes("hc-ui-chip", className), children: [
147
+ var glyph = (size, d) => /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", strokeWidth: 1.8, "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d, stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" }) });
148
+ var CHEVRON_DOWN = "M6 9L12 15L18 9";
149
+ var XMARK = "M6.75827 17.2426L12.0009 12M17.2435 6.75736L12.0009 12M12.0009 12L6.75827 6.75736M12.0009 12L17.2435 17.2426";
150
+ var visible = (node) => node !== void 0 && node !== null && node !== false && node !== "";
151
+ var Chip = forwardRef(function Chip2({ selected, icon, size = "md", variant = "outline", applied = false, count, badge, chevron, onClear, clearLabel, type = "button", className, children, ...props }, ref) {
152
+ const popup = props["aria-haspopup"];
153
+ const withChevron = chevron ?? (popup !== void 0 && popup !== false && popup !== "false");
154
+ const look = {
155
+ "data-size": size === "md" ? void 0 : size,
156
+ "data-variant": variant === "outline" ? void 0 : variant,
157
+ "data-applied": applied || void 0
158
+ };
159
+ const content = /* @__PURE__ */ jsxs(Fragment2, { children: [
128
160
  icon && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__icon", "aria-hidden": "true", children: icon }),
129
- children
161
+ children,
162
+ visible(count) && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__count", children: count }),
163
+ visible(badge) && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__badge", children: badge }),
164
+ withChevron && /* @__PURE__ */ jsx("span", { className: "hc-ui-chip__chevron", "aria-hidden": "true", children: glyph(size === "xs" ? 12 : 14, CHEVRON_DOWN) })
165
+ ] });
166
+ if (!onClear) {
167
+ return /* @__PURE__ */ jsx("button", { ...props, ref, type, "aria-pressed": selected, className: classes("hc-ui-chip", className), ...look, children: content });
168
+ }
169
+ const { style, id, onClick, disabled, ...rest } = props;
170
+ return /* @__PURE__ */ jsxs("span", { className: classes("hc-ui-chip", className), style, ...look, "data-clearable": "", "data-selected": selected || void 0, "data-disabled": disabled || void 0, children: [
171
+ onClick ? /* @__PURE__ */ jsx("button", { ...rest, id, ref, type, disabled, "aria-pressed": selected, className: "hc-ui-chip__main", onClick, children: content }) : /* @__PURE__ */ jsx("span", { id, className: "hc-ui-chip__main", children: content }),
172
+ /* @__PURE__ */ jsx("button", { type: "button", className: "hc-ui-chip__clear", "aria-label": clearLabel, title: clearLabel, disabled, onClick: onClear, children: glyph(12, XMARK) })
130
173
  ] });
131
174
  });
175
+ var FilterBar = forwardRef(function FilterBar2({ label, start, end, footer, layout = "auto", density = "comfortable", sticky = false, className, children, ...props }, ref) {
176
+ return /* @__PURE__ */ jsxs(
177
+ "div",
178
+ {
179
+ ...props,
180
+ ref,
181
+ role: "group",
182
+ "aria-label": label,
183
+ className: classes("hc-ui-filter-bar", className),
184
+ "data-layout": layout,
185
+ "data-density": density === "comfortable" ? void 0 : density,
186
+ "data-sticky": sticky || void 0,
187
+ children: [
188
+ /* @__PURE__ */ jsxs("div", { className: "hc-ui-filter-bar__line", children: [
189
+ start && /* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__start", children: start }),
190
+ /* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__row", children }),
191
+ end && /* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__end", children: end })
192
+ ] }),
193
+ footer && /* @__PURE__ */ jsx("div", { className: "hc-ui-filter-bar__footer", children: footer })
194
+ ]
195
+ }
196
+ );
197
+ });
132
198
  var Field = forwardRef(function Field2({ label, hideLabel = false, density = "comfortable", icon, end, hint, error, id, className, disabled, "aria-describedby": describedBy, ...props }, ref) {
133
199
  const generated = useId();
134
200
  const inputId = id ?? generated;
@@ -169,12 +235,1233 @@ function Skeleton({ width, height, circle = false, className, style, ...props })
169
235
  }
170
236
  );
171
237
  }
238
+ var finite = (number) => Number.isFinite(number) ? number : 0;
239
+ var Meter = forwardRef(function Meter2({ value, max, label, valueText, decorative = false, thickness = 4, track = "muted", cap = "round", overflow = "clamp", tone = "auto", animated = false, className, ...props }, ref) {
240
+ const amount = Math.max(0, finite(value));
241
+ const limit = Math.max(0, finite(max));
242
+ const over = tone === "over" || tone === "auto" && amount > limit;
243
+ const scale = overflow === "mark" ? Math.max(limit, amount, 1) : limit;
244
+ const share = scale > 0 ? Math.min(100, amount / scale * 100) : amount > 0 ? 100 : 0;
245
+ const marker = overflow === "mark" && amount > limit ? limit / scale * 100 : null;
246
+ const semantics = decorative ? { "aria-hidden": true } : {
247
+ role: "meter",
248
+ "aria-label": label,
249
+ "aria-valuemin": 0,
250
+ "aria-valuemax": limit,
251
+ // ARIA keeps aria-valuenow inside the range; the text carries the real amount.
252
+ "aria-valuenow": Math.min(amount, limit),
253
+ "aria-valuetext": valueText ?? `${finite(value)} / ${finite(max)}`
254
+ };
255
+ return /* @__PURE__ */ jsxs(
256
+ "span",
257
+ {
258
+ ...props,
259
+ ...semantics,
260
+ ref,
261
+ className: classes("hc-ui-meter", className),
262
+ "data-thickness": thickness,
263
+ "data-track": track,
264
+ "data-cap": cap,
265
+ "data-tone": over ? "over" : void 0,
266
+ "data-animated": animated || void 0,
267
+ children: [
268
+ /* @__PURE__ */ jsx("span", { className: "hc-ui-meter__fill", style: { width: `${share}%` } }),
269
+ marker !== null && /* @__PURE__ */ jsx("span", { className: "hc-ui-meter__limit", style: { left: `${marker}%` } })
270
+ ]
271
+ }
272
+ );
273
+ });
274
+ var checkboxIcon = (className, d) => /* @__PURE__ */ jsx("svg", { className, viewBox: "0 0 24 24", fill: "none", strokeWidth: 2.4, "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d, stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" }) });
275
+ var Checkbox = forwardRef(function Checkbox2({ size = "md", indeterminate = false, className, ...props }, ref) {
276
+ const inputRef = useRef(null);
277
+ useImperativeHandle(ref, () => inputRef.current);
278
+ useEffect(() => {
279
+ if (inputRef.current) inputRef.current.indeterminate = indeterminate;
280
+ }, [indeterminate]);
281
+ return /* @__PURE__ */ jsxs("span", { className: classes("hc-ui-checkbox", className), "data-size": size, children: [
282
+ /* @__PURE__ */ jsx("input", { ...props, ref: inputRef, type: "checkbox", className: "hc-ui-checkbox__input" }),
283
+ /* @__PURE__ */ jsxs("span", { className: "hc-ui-checkbox__box", "aria-hidden": "true", children: [
284
+ checkboxIcon("hc-ui-checkbox__mark", "M5 13L9 17L19 7"),
285
+ checkboxIcon("hc-ui-checkbox__mixed", "M6 12H18")
286
+ ] })
287
+ ] });
288
+ });
289
+ var useIsomorphicLayoutEffect = typeof document === "undefined" ? useEffect : useLayoutEffect;
290
+ var scrollLocks = 0;
291
+ var restoreScroll = () => {
292
+ };
293
+ function lockScroll() {
294
+ if (scrollLocks++ === 0) {
295
+ const root = document.documentElement;
296
+ const { overflow, scrollbarGutter } = root.style;
297
+ const hasScrollbar = window.innerWidth > root.clientWidth;
298
+ root.style.overflow = "hidden";
299
+ if (hasScrollbar) root.style.scrollbarGutter = "stable";
300
+ restoreScroll = () => {
301
+ root.style.overflow = overflow;
302
+ root.style.scrollbarGutter = scrollbarGutter;
303
+ };
304
+ }
305
+ let released = false;
306
+ return () => {
307
+ if (released) return;
308
+ released = true;
309
+ if (--scrollLocks === 0) restoreScroll();
310
+ };
311
+ }
312
+ function DialogMount({ onMount }) {
313
+ useIsomorphicLayoutEffect(onMount, []);
314
+ return null;
315
+ }
316
+ var closeGlyph = /* @__PURE__ */ jsx("svg", { width: 18, height: 18, viewBox: "0 0 24 24", fill: "none", strokeWidth: 1.8, "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M6.75827 17.2426L12.0009 12M17.2435 6.75736L12.0009 12M12.0009 12L6.75827 6.75736M12.0009 12L17.2435 17.2426", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" }) });
317
+ var outside = (element, x, y) => {
318
+ const box = element.getBoundingClientRect();
319
+ return x < box.left || x > box.right || y < box.top || y > box.bottom;
320
+ };
321
+ var Dialog = forwardRef(function Dialog2({
322
+ open,
323
+ onClose,
324
+ title,
325
+ description,
326
+ children,
327
+ actions,
328
+ closeLabel,
329
+ closeIcon,
330
+ size = "md",
331
+ dismissible = true,
332
+ className,
333
+ onClick,
334
+ onPointerDown,
335
+ "aria-describedby": describedBy,
336
+ ...props
337
+ }, ref) {
338
+ const dialogRef = useRef(null);
339
+ const setRef = useCallback((node) => {
340
+ dialogRef.current = node;
341
+ if (typeof ref === "function") ref(node);
342
+ else if (ref) ref.current = node;
343
+ }, [ref]);
344
+ const id = useId();
345
+ const titleId = `${id}-title`;
346
+ const descriptionId = description ? `${id}-description` : void 0;
347
+ const [mounted, setMounted] = useState(open);
348
+ const [closing, setClosing] = useState(false);
349
+ if (open && (!mounted || closing)) {
350
+ setMounted(true);
351
+ setClosing(false);
352
+ }
353
+ if (!open && mounted && !closing) setClosing(true);
354
+ const latest = useRef({ open, onClose, dismissible, closing });
355
+ useIsomorphicLayoutEffect(() => {
356
+ latest.current = { open, onClose, dismissible, closing };
357
+ });
358
+ const keepFocus = useRef(null);
359
+ const handleMount = useCallback(() => {
360
+ const dialog = document.getElementById(titleId)?.closest("dialog");
361
+ if (!dialog) return () => {
362
+ };
363
+ const trigger = document.activeElement instanceof HTMLElement ? document.activeElement : null;
364
+ if (!dialog.open) dialog.showModal();
365
+ const kept = keepFocus.current;
366
+ keepFocus.current = null;
367
+ if (kept instanceof HTMLElement && dialog.contains(kept)) kept.focus();
368
+ const unlock = lockScroll();
369
+ return () => {
370
+ unlock();
371
+ keepFocus.current = dialog.contains(document.activeElement) ? document.activeElement : null;
372
+ if (dialog.open) dialog.close();
373
+ queueMicrotask(() => {
374
+ const active = document.activeElement;
375
+ const lost = !active || active === document.body || dialog.contains(active);
376
+ if (lost && !dialog.open && trigger?.isConnected) trigger.focus({ preventScroll: true });
377
+ });
378
+ };
379
+ }, [titleId]);
380
+ useEffect(() => {
381
+ const dialog = dialogRef.current;
382
+ if (!closing || !dialog) return;
383
+ let done = false;
384
+ const finish = () => {
385
+ if (done) return;
386
+ done = true;
387
+ setMounted(false);
388
+ setClosing(false);
389
+ };
390
+ const animations = typeof dialog.getAnimations === "function" ? dialog.getAnimations({ subtree: true }).filter((animation) => {
391
+ const effect = animation.effect;
392
+ return effect?.target === dialog && effect.getComputedTiming().endTime !== Infinity;
393
+ }) : [];
394
+ if (animations.length) Promise.all(animations.map((animation) => animation.finished)).then(finish, finish);
395
+ else finish();
396
+ return () => {
397
+ done = true;
398
+ };
399
+ }, [closing]);
400
+ const ownEvent = (event) => event.target === event.currentTarget;
401
+ const handleCancel = (event) => {
402
+ if (!ownEvent(event)) return;
403
+ event.preventDefault();
404
+ if (latest.current.dismissible && !latest.current.closing) latest.current.onClose();
405
+ };
406
+ const handleNativeClose = (event) => {
407
+ const dialog = event.currentTarget;
408
+ if (!ownEvent(event) || dialog.open || !latest.current.open || latest.current.closing) return;
409
+ if (latest.current.dismissible) latest.current.onClose();
410
+ window.setTimeout(() => {
411
+ if (latest.current.open && !latest.current.closing && dialog.isConnected && !dialog.open) dialog.showModal();
412
+ }, 0);
413
+ };
414
+ const pressedBackdrop = useRef(false);
415
+ const handlePointerDown = (event) => {
416
+ onPointerDown?.(event);
417
+ pressedBackdrop.current = ownEvent(event) && outside(event.currentTarget, event.clientX, event.clientY);
418
+ };
419
+ const handleClick = (event) => {
420
+ onClick?.(event);
421
+ const fromBackdrop = pressedBackdrop.current && ownEvent(event) && outside(event.currentTarget, event.clientX, event.clientY);
422
+ pressedBackdrop.current = false;
423
+ if (fromBackdrop && latest.current.dismissible && !latest.current.closing) latest.current.onClose();
424
+ };
425
+ if (!mounted) return null;
426
+ const hasBody = Boolean(description) || children !== void 0 && children !== null && children !== false;
427
+ return /* @__PURE__ */ jsxs(
428
+ "dialog",
429
+ {
430
+ ...props,
431
+ ref: setRef,
432
+ className: classes("hc-ui-dialog", className),
433
+ "data-size": size,
434
+ "data-closing": closing || void 0,
435
+ "aria-labelledby": titleId,
436
+ "aria-describedby": classes(descriptionId, describedBy) || void 0,
437
+ onCancel: handleCancel,
438
+ onClose: handleNativeClose,
439
+ onPointerDown: handlePointerDown,
440
+ onClick: handleClick,
441
+ children: [
442
+ /* @__PURE__ */ jsx(DialogMount, { onMount: handleMount }),
443
+ /* @__PURE__ */ jsxs("div", { className: "hc-ui-dialog__header", children: [
444
+ /* @__PURE__ */ jsx("h2", { className: "hc-ui-dialog__title", id: titleId, children: title }),
445
+ closeLabel && /* @__PURE__ */ jsx(IconButton, { className: "hc-ui-dialog__close", label: closeLabel, icon: closeIcon ?? closeGlyph, size: "sm", tone: "secondary", onClick: () => latest.current.onClose() })
446
+ ] }),
447
+ hasBody && /* @__PURE__ */ jsxs("div", { className: "hc-ui-dialog__body", children: [
448
+ description && /* @__PURE__ */ jsx("p", { className: "hc-ui-dialog__description", id: descriptionId, children: description }),
449
+ children
450
+ ] }),
451
+ actions && /* @__PURE__ */ jsx("div", { className: "hc-ui-dialog__actions", children: actions })
452
+ ]
453
+ }
454
+ );
455
+ });
456
+ var SHEET_EASE = "cubic-bezier(0.32, 0.72, 0, 1)";
457
+ var NO_DRAG = 'input, textarea, select, [contenteditable="true"], [data-hc-sheet-nodrag]';
458
+ function useSheetDrag(sheet, latest) {
459
+ useEffect(() => {
460
+ const el = sheet;
461
+ if (!el) return;
462
+ const reduce = window.matchMedia("(prefers-reduced-motion: reduce)");
463
+ let startX = 0;
464
+ let startY = 0;
465
+ let lastY = 0;
466
+ let lastT = 0;
467
+ let velocity = 0;
468
+ let tracking = false;
469
+ let dragging = false;
470
+ let inHandle = false;
471
+ let scroller = null;
472
+ const timers = /* @__PURE__ */ new Set();
473
+ const later = (run, ms) => {
474
+ const id = window.setTimeout(() => {
475
+ timers.delete(id);
476
+ run();
477
+ }, ms);
478
+ timers.add(id);
479
+ };
480
+ const expanded = () => el.hasAttribute("data-expanded");
481
+ const findScroller = (node) => {
482
+ while (node && node !== el.parentElement) {
483
+ const overflowY = getComputedStyle(node).overflowY;
484
+ if ((overflowY === "auto" || overflowY === "scroll") && node.scrollHeight > node.clientHeight + 1) return node;
485
+ if (node === el) break;
486
+ node = node.parentElement;
487
+ }
488
+ return null;
489
+ };
490
+ const settle = () => {
491
+ el.style.transition = reduce.matches ? "none" : `translate 320ms ${SHEET_EASE}`;
492
+ el.style.translate = "";
493
+ later(() => {
494
+ el.style.transition = "";
495
+ }, 340);
496
+ };
497
+ const onStart = (event) => {
498
+ if (event.touches.length !== 1 || getComputedStyle(el).getPropertyValue("--hc-sheet-drag").trim() !== "on") return;
499
+ const touch = event.touches[0];
500
+ const target = event.target;
501
+ if (target === el && outside(el, touch.clientX, touch.clientY)) return;
502
+ if (target.closest?.("dialog") !== el || target.closest(NO_DRAG)) return;
503
+ startX = touch.clientX;
504
+ startY = lastY = touch.clientY;
505
+ lastT = performance.now();
506
+ velocity = 0;
507
+ dragging = false;
508
+ tracking = true;
509
+ inHandle = Boolean(target.closest?.("[data-hc-sheet-handle]")) || touch.clientY - el.getBoundingClientRect().top < 64;
510
+ scroller = inHandle ? null : findScroller(target);
511
+ };
512
+ const onMove = (event) => {
513
+ if (!tracking) return;
514
+ const touch = event.touches[0];
515
+ const dy = touch.clientY - startY;
516
+ const dx = touch.clientX - startX;
517
+ if (!dragging) {
518
+ if (Math.abs(dx) > 8 && Math.abs(dx) > Math.abs(dy)) {
519
+ tracking = false;
520
+ return;
521
+ }
522
+ if (dy < -4 && !(inHandle && !expanded())) {
523
+ tracking = false;
524
+ return;
525
+ }
526
+ if (Math.abs(dy) < 8) return;
527
+ if (scroller && scroller.scrollTop > 0) {
528
+ tracking = false;
529
+ return;
530
+ }
531
+ dragging = true;
532
+ startY = touch.clientY;
533
+ el.style.transition = "none";
534
+ }
535
+ if (event.cancelable) event.preventDefault();
536
+ const now = performance.now();
537
+ velocity = (touch.clientY - lastY) / Math.max(1, now - lastT);
538
+ lastY = touch.clientY;
539
+ lastT = now;
540
+ const offset = touch.clientY - startY;
541
+ el.style.translate = `0 ${offset > 0 ? offset : offset / 6}px`;
542
+ };
543
+ const onEnd = () => {
544
+ if (!tracking) return;
545
+ tracking = false;
546
+ if (!dragging) return;
547
+ dragging = false;
548
+ const dy = lastY - startY;
549
+ const height = el.getBoundingClientRect().height || 1;
550
+ if (dy < -40 || velocity < -0.5) {
551
+ el.setAttribute("data-expanded", "");
552
+ settle();
553
+ return;
554
+ }
555
+ const goingDown = dy > height * 0.2 || velocity > 0.5 && dy > 20;
556
+ if (goingDown && expanded()) {
557
+ el.removeAttribute("data-expanded");
558
+ settle();
559
+ return;
560
+ }
561
+ if (!goingDown || !latest.current.dismissible) {
562
+ settle();
563
+ return;
564
+ }
565
+ el.style.transition = reduce.matches ? "none" : `translate 220ms ${SHEET_EASE}`;
566
+ el.style.translate = "0 105%";
567
+ el.setAttribute("data-dismissing", "");
568
+ later(() => latest.current.onClose(), reduce.matches ? 0 : 200);
569
+ later(() => {
570
+ if (!el.isConnected || el.hasAttribute("data-closing")) return;
571
+ el.removeAttribute("data-dismissing");
572
+ el.style.transition = reduce.matches ? "none" : `translate 320ms ${SHEET_EASE}`;
573
+ el.style.translate = "";
574
+ }, 900);
575
+ };
576
+ el.addEventListener("touchstart", onStart, { passive: true });
577
+ el.addEventListener("touchmove", onMove, { passive: false });
578
+ el.addEventListener("touchend", onEnd);
579
+ el.addEventListener("touchcancel", onEnd);
580
+ return () => {
581
+ el.removeEventListener("touchstart", onStart);
582
+ el.removeEventListener("touchmove", onMove);
583
+ el.removeEventListener("touchend", onEnd);
584
+ el.removeEventListener("touchcancel", onEnd);
585
+ timers.forEach((id) => window.clearTimeout(id));
586
+ };
587
+ }, [sheet, latest]);
588
+ }
589
+ var Sheet = forwardRef(function Sheet2({ presentation = "auto", width = 440, footer, dismissible = true, onClose, className, style, ...props }, ref) {
590
+ const [node, setNode] = useState(null);
591
+ const setRef = useCallback((element) => {
592
+ setNode(element);
593
+ setRefs(element, ref);
594
+ }, [ref]);
595
+ const latest = useRef({ onClose, dismissible });
596
+ useIsomorphicLayoutEffect(() => {
597
+ latest.current = { onClose, dismissible };
598
+ });
599
+ useSheetDrag(node, latest);
600
+ const sized = width === 440 ? style : { ...style, "--hc-sheet-width": `${width}px` };
601
+ return /* @__PURE__ */ jsx(
602
+ Dialog,
603
+ {
604
+ ...props,
605
+ ref: setRef,
606
+ size: "md",
607
+ actions: footer,
608
+ dismissible,
609
+ onClose,
610
+ className: classes("hc-ui-sheet", className),
611
+ style: sized,
612
+ "data-presentation": presentation
613
+ }
614
+ );
615
+ });
616
+ function useRovingRadios(options, value) {
617
+ const buttons = useRef([]);
618
+ const [focusIndex, setFocusIndex] = useState(null);
619
+ const chosen = options.findIndex((option) => option.value === value && !option.disabled);
620
+ const fallback = chosen >= 0 ? chosen : options.findIndex((option) => !option.disabled);
621
+ const tabStop = focusIndex !== null && options[focusIndex] && !options[focusIndex].disabled ? focusIndex : fallback;
622
+ const onKeyDown = (index) => (event) => {
623
+ const enabled = options.map((option, at) => option.disabled ? -1 : at).filter((at) => at >= 0);
624
+ if (!enabled.length) return;
625
+ const position = enabled.indexOf(index);
626
+ let next;
627
+ if (event.key === "ArrowDown" || event.key === "ArrowRight") next = enabled[(position + 1) % enabled.length];
628
+ else if (event.key === "ArrowUp" || event.key === "ArrowLeft") next = enabled[(position - 1 + enabled.length) % enabled.length];
629
+ else if (event.key === "Home") next = enabled[0];
630
+ else if (event.key === "End") next = enabled[enabled.length - 1];
631
+ else return;
632
+ event.preventDefault();
633
+ setFocusIndex(next);
634
+ buttons.current[next]?.focus();
635
+ };
636
+ const item = (index) => ({
637
+ ref: (element) => {
638
+ buttons.current[index] = element;
639
+ },
640
+ tabIndex: index === tabStop ? 0 : -1,
641
+ onKeyDown: onKeyDown(index),
642
+ onFocus: () => setFocusIndex(index)
643
+ });
644
+ return item;
645
+ }
646
+ function SheetOptions({ label, options, value, onChange, variant = "card", className, ...props }) {
647
+ const item = useRovingRadios(options, value);
648
+ const list = variant === "list";
649
+ return /* @__PURE__ */ jsx("div", { ...props, className: classes("hc-ui-sheet-options", className), role: "radiogroup", "aria-label": label, "data-variant": list ? "list" : void 0, children: options.map((option, index) => {
650
+ const on = option.value === value;
651
+ return /* @__PURE__ */ jsxs(
652
+ "button",
653
+ {
654
+ ...item(index),
655
+ type: "button",
656
+ role: "radio",
657
+ "aria-checked": on,
658
+ disabled: option.disabled,
659
+ className: "hc-ui-sheet-options__row",
660
+ "data-selected": on || void 0,
661
+ onClick: () => onChange(option.value),
662
+ children: [
663
+ option.icon && /* @__PURE__ */ jsx("span", { className: "hc-ui-sheet-options__icon", "aria-hidden": "true", children: option.icon }),
664
+ /* @__PURE__ */ jsxs("span", { className: "hc-ui-sheet-options__text", children: [
665
+ /* @__PURE__ */ jsx("span", { className: "hc-ui-sheet-options__label", children: option.label }),
666
+ option.hint && /* @__PURE__ */ jsx("span", { className: "hc-ui-sheet-options__hint", children: option.hint })
667
+ ] }),
668
+ /* @__PURE__ */ jsx("span", { className: "hc-ui-sheet-options__check", "aria-hidden": "true", children: on && /* @__PURE__ */ jsx("svg", { width: list ? 20 : 18, height: list ? 20 : 18, viewBox: "0 0 24 24", fill: "none", strokeWidth: list ? 1.8 : 2.4, "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M5 13L9 17L19 7", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
669
+ ]
670
+ },
671
+ option.value
672
+ );
673
+ }) });
674
+ }
675
+ function SheetChips({ label, options, value, onChange, className, ...props }) {
676
+ const item = useRovingRadios(options, value);
677
+ return /* @__PURE__ */ jsx("div", { ...props, className: classes("hc-ui-sheet-chips", className), role: "radiogroup", "aria-label": label, children: options.map((option, index) => /* @__PURE__ */ jsx(
678
+ "button",
679
+ {
680
+ ...item(index),
681
+ type: "button",
682
+ role: "radio",
683
+ "aria-checked": option.value === value,
684
+ disabled: option.disabled,
685
+ className: "hc-ui-chip",
686
+ onClick: () => onChange(option.value),
687
+ children: option.label
688
+ },
689
+ option.value
690
+ )) });
691
+ }
692
+ var GAP = 4;
693
+ function boundaryOf(anchor, clip) {
694
+ const box = { top: 0, left: 0, right: window.innerWidth, bottom: window.innerHeight };
695
+ if (!clip) return box;
696
+ for (let node = anchor.parentElement; node && node !== document.documentElement; node = node.parentElement) {
697
+ const style = getComputedStyle(node);
698
+ if (style.overflowX === "visible" && style.overflowY === "visible") continue;
699
+ const rect = node.getBoundingClientRect();
700
+ box.top = Math.max(box.top, rect.top);
701
+ box.left = Math.max(box.left, rect.left);
702
+ box.right = Math.min(box.right, rect.right);
703
+ box.bottom = Math.min(box.bottom, rect.bottom);
704
+ }
705
+ return box;
706
+ }
707
+ function placePopup(trigger, size, boundary, side, align) {
708
+ const room = { bottom: boundary.bottom - trigger.bottom - GAP, top: trigger.top - boundary.top - GAP };
709
+ const other = side === "bottom" ? "top" : "bottom";
710
+ const finalSide = size.height > room[side] && room[other] > room[side] ? other : side;
711
+ const fits = (edge) => edge === "end" ? trigger.right - size.width >= boundary.left : trigger.left + size.width <= boundary.right;
712
+ const finalAlign = !fits(align) && fits(align === "end" ? "start" : "end") ? align === "end" ? "start" : "end" : align;
713
+ return { side: finalSide, align: finalAlign };
714
+ }
715
+ var layers = [];
716
+ function themeOf(element) {
717
+ const scoped = element?.closest("[data-theme]")?.getAttribute("data-theme");
718
+ if (scoped === "light" || scoped === "dark") return scoped;
719
+ const classed = element?.closest(".dark, .light");
720
+ return classed ? classed.classList.contains("dark") ? "dark" : "light" : void 0;
721
+ }
722
+ var setRefs = (node, ...refs) => {
723
+ for (const ref of refs) {
724
+ if (typeof ref === "function") ref(node);
725
+ else if (ref) ref.current = node;
726
+ }
727
+ };
728
+ function usePopup({ kind, trigger, open: openProp, defaultOpen = false, onOpenChange, side = "bottom", align = "end", portal = false, theme, contentId, onShown }) {
729
+ const [uncontrolled, setUncontrolled] = useState(defaultOpen);
730
+ const open = openProp ?? uncontrolled;
731
+ const generated = useId();
732
+ const id = contentId ?? `${generated}-popup`;
733
+ const triggerRef = useRef(null);
734
+ const anchorRef = useRef(null);
735
+ const contentRef = useRef(null);
736
+ const focusAfter = useRef("none");
737
+ const reason = useRef("first");
738
+ const [placement, setPlacement] = useState({ side, align });
739
+ const [container, setContainer] = useState(null);
740
+ const latest = useRef({ open, onOpenChange, onShown });
741
+ useIsomorphicLayoutEffect(() => {
742
+ latest.current = { open, onOpenChange, onShown };
743
+ });
744
+ const setOpen = useCallback((next, after = "none") => {
745
+ if (next === latest.current.open) return;
746
+ if (!next) focusAfter.current = after;
747
+ if (openProp === void 0) setUncontrolled(next);
748
+ latest.current.onOpenChange?.(next);
749
+ }, [openProp]);
750
+ const close = useCallback((after = "trigger") => setOpen(false, after), [setOpen]);
751
+ const show = (why) => {
752
+ reason.current = why;
753
+ setOpen(true);
754
+ };
755
+ useIsomorphicLayoutEffect(() => {
756
+ if (!open || !portal) {
757
+ setContainer(null);
758
+ return;
759
+ }
760
+ const element = portal instanceof HTMLElement ? portal : triggerRef.current?.closest("dialog[open]") ?? document.body;
761
+ setContainer({ element, theme: theme ?? themeOf(triggerRef.current) });
762
+ }, [open, portal, theme]);
763
+ const place = useCallback(() => {
764
+ const content = contentRef.current;
765
+ const anchor = anchorRef.current;
766
+ if (!content || !anchor) return;
767
+ const triggerBox = (triggerRef.current ?? anchor).getBoundingClientRect();
768
+ const size = { width: content.offsetWidth, height: content.offsetHeight };
769
+ if (!portal) {
770
+ setPlacement(placePopup(anchor.getBoundingClientRect(), size, boundaryOf(anchor, true), side, align));
771
+ return;
772
+ }
773
+ const next = placePopup(triggerBox, size, boundaryOf(anchor, false), side, align);
774
+ const style = content.style;
775
+ style.top = "0px";
776
+ style.left = "0px";
777
+ const origin = content.getBoundingClientRect();
778
+ const top = next.side === "bottom" ? triggerBox.bottom + GAP : triggerBox.top - GAP - size.height;
779
+ const left = next.align === "end" ? triggerBox.right - size.width : triggerBox.left;
780
+ style.top = `${top - origin.top}px`;
781
+ style.left = `${left - origin.left}px`;
782
+ setPlacement({ ...next, top: top - origin.top, left: left - origin.left });
783
+ }, [portal, side, align]);
784
+ const ready = open && (!portal || container !== null);
785
+ useIsomorphicLayoutEffect(() => {
786
+ if (!ready) return;
787
+ place();
788
+ const content = contentRef.current;
789
+ if (content) latest.current.onShown?.(content, reason.current);
790
+ }, [ready]);
791
+ useIsomorphicLayoutEffect(() => {
792
+ if (!ready) setPlacement({ side, align });
793
+ }, [ready, side, align]);
794
+ const handlers = useRef({ close, place });
795
+ useIsomorphicLayoutEffect(() => {
796
+ handlers.current = { close, place };
797
+ });
798
+ useEffect(() => {
799
+ if (!ready) return;
800
+ const layer = { content: () => contentRef.current };
801
+ layers.push(layer);
802
+ const isTop = () => layers[layers.length - 1] === layer;
803
+ const onKey = (event) => {
804
+ if (event.key !== "Escape" || !isTop() || event.defaultPrevented) return;
805
+ event.preventDefault();
806
+ event.stopPropagation();
807
+ handlers.current.close("trigger");
808
+ };
809
+ const onPointer = (event) => {
810
+ const target = event.target;
811
+ if (anchorRef.current?.contains(target) || contentRef.current?.contains(target)) return;
812
+ const index = layers.indexOf(layer);
813
+ if (layers.slice(index + 1).some((other) => other.content()?.contains(target))) return;
814
+ handlers.current.close("none");
815
+ };
816
+ const onMove = () => handlers.current.place();
817
+ document.addEventListener("keydown", onKey, true);
818
+ document.addEventListener("pointerdown", onPointer, true);
819
+ window.addEventListener("resize", onMove);
820
+ if (portal) window.addEventListener("scroll", onMove, true);
821
+ return () => {
822
+ layers.splice(layers.indexOf(layer), 1);
823
+ document.removeEventListener("keydown", onKey, true);
824
+ document.removeEventListener("pointerdown", onPointer, true);
825
+ window.removeEventListener("resize", onMove);
826
+ window.removeEventListener("scroll", onMove, true);
827
+ };
828
+ }, [ready, portal]);
829
+ useIsomorphicLayoutEffect(() => {
830
+ if (open) return;
831
+ const after = focusAfter.current;
832
+ focusAfter.current = "none";
833
+ const active = document.activeElement;
834
+ const lost = !active || active === document.body;
835
+ if (after === "trigger" || after === "if-lost" && lost) triggerRef.current?.focus({ preventScroll: true });
836
+ }, [open]);
837
+ const triggerProps = {
838
+ ref: (node) => {
839
+ triggerRef.current = node;
840
+ },
841
+ "aria-haspopup": kind,
842
+ "aria-expanded": open,
843
+ "aria-controls": open ? id : void 0,
844
+ onClick: (event) => {
845
+ if (event.defaultPrevented) return;
846
+ if (open) close("none");
847
+ else show(event.detail === 0 ? "first" : "pointer");
848
+ },
849
+ onKeyDown: (event) => {
850
+ if (event.defaultPrevented || kind !== "menu") return;
851
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
852
+ event.preventDefault();
853
+ show(event.key === "ArrowUp" ? "last" : "first");
854
+ }
855
+ }
856
+ };
857
+ let triggerNode;
858
+ if (typeof trigger === "function") triggerNode = trigger(triggerProps, { open });
859
+ else {
860
+ const own = trigger.props;
861
+ const elementRef = trigger.ref;
862
+ triggerNode = cloneElement(trigger, {
863
+ ...triggerProps,
864
+ ref: (node) => setRefs(node, triggerProps.ref, elementRef),
865
+ onClick: (event) => {
866
+ own.onClick?.(event);
867
+ triggerProps.onClick(event);
868
+ },
869
+ onKeyDown: (event) => {
870
+ own.onKeyDown?.(event);
871
+ triggerProps.onKeyDown(event);
872
+ }
873
+ });
874
+ }
875
+ const contentAttributes = {
876
+ id,
877
+ "data-side": placement.side,
878
+ "data-align": placement.align,
879
+ "data-portal": portal ? "" : void 0,
880
+ style: portal ? { top: placement.top ?? 0, left: placement.left ?? 0, right: "auto", bottom: "auto" } : void 0
881
+ };
882
+ const wrap = (content) => {
883
+ if (!open) return null;
884
+ if (!portal) return content;
885
+ if (!container) return null;
886
+ return createPortal(/* @__PURE__ */ jsx("div", { className: "hc-ui-portal", "data-hc-ds": "", "data-theme": container.theme, children: content }), container.element);
887
+ };
888
+ return { open, close, triggerNode, anchorRef, contentRef, contentAttributes, wrap, triggerRef };
889
+ }
890
+ var mergeStyle = (base, own) => base || own ? { ...own, ...base } : void 0;
891
+ var MenuContext = createContext(null);
892
+ var RadioContext = createContext(null);
893
+ var ITEM_SELECTOR = '[role="menuitem"], [role="menuitemradio"], [role="menuitemcheckbox"]';
894
+ var itemsOf = (menu) => [...menu.querySelectorAll(ITEM_SELECTOR)].filter((item) => !item.disabled && item.closest('[role="menu"]') === menu);
895
+ var itemText = (item) => (item.querySelector(".hc-ui-menu__text")?.firstChild?.textContent ?? item.textContent ?? "").trim().toLocaleLowerCase();
896
+ var Menu = forwardRef(function Menu2({ label, trigger, children, open, defaultOpen, onOpenChange, side, align, portal, theme, anchorClassName, className, style, id, onKeyDown, ...props }, ref) {
897
+ const typed = useRef({ text: "", at: 0 });
898
+ const popup = usePopup({
899
+ kind: "menu",
900
+ trigger,
901
+ open,
902
+ defaultOpen,
903
+ onOpenChange,
904
+ side,
905
+ align,
906
+ portal,
907
+ theme,
908
+ contentId: id,
909
+ onShown: (menu, why) => {
910
+ typed.current = { text: "", at: 0 };
911
+ const items = itemsOf(menu);
912
+ const selected = items.find((item) => item.getAttribute("role") === "menuitemradio" && item.getAttribute("aria-checked") === "true");
913
+ (why === "last" ? items[items.length - 1] : selected ?? items[0])?.focus({ preventScroll: true });
914
+ }
915
+ });
916
+ const { close } = popup;
917
+ const context = useMemo(() => ({ close }), [close]);
918
+ useIsomorphicLayoutEffect(() => {
919
+ const menu = popup.contentRef.current;
920
+ const active = document.activeElement;
921
+ const lost = !active || active === document.body || menu?.contains(active) && active.disabled;
922
+ if (popup.open && menu && lost) itemsOf(menu)[0]?.focus({ preventScroll: true });
923
+ });
924
+ const handleKeyDown = (event) => {
925
+ onKeyDown?.(event);
926
+ if (event.defaultPrevented) return;
927
+ const menu = event.currentTarget;
928
+ const items = itemsOf(menu);
929
+ const current = items.indexOf(document.activeElement);
930
+ const focus = (index) => items[(index + items.length) % items.length]?.focus();
931
+ switch (event.key) {
932
+ case "ArrowDown":
933
+ event.preventDefault();
934
+ focus(current + 1);
935
+ return;
936
+ case "ArrowUp":
937
+ event.preventDefault();
938
+ focus(current < 0 ? -1 : current - 1);
939
+ return;
940
+ case "Home":
941
+ event.preventDefault();
942
+ focus(0);
943
+ return;
944
+ case "End":
945
+ event.preventDefault();
946
+ focus(-1);
947
+ return;
948
+ case "Tab":
949
+ popup.triggerRef.current?.focus({ preventScroll: true });
950
+ close("none");
951
+ return;
952
+ }
953
+ if (event.key.length !== 1 || event.ctrlKey || event.metaKey || event.altKey || !items.length) return;
954
+ const now = Date.now();
955
+ const typing = typed.current.text !== "" && now - typed.current.at <= 500;
956
+ if (event.key === " " && !typing) return;
957
+ event.preventDefault();
958
+ const key = event.key.toLocaleLowerCase();
959
+ typed.current.text = typing ? typed.current.text + key : key;
960
+ typed.current.at = now;
961
+ const query = [...typed.current.text].every((letter) => letter === key) ? key : typed.current.text;
962
+ const start = query.length === 1 ? current + 1 : Math.max(current, 0);
963
+ for (let step = 0; step < items.length; step += 1) {
964
+ const item = items[(start + step) % items.length];
965
+ if (itemText(item).startsWith(query)) {
966
+ item.focus();
967
+ break;
968
+ }
969
+ }
970
+ };
971
+ return /* @__PURE__ */ jsxs("div", { className: classes("hc-ui-popup-anchor", anchorClassName), ref: popup.anchorRef, children: [
972
+ popup.triggerNode,
973
+ popup.wrap(
974
+ /* @__PURE__ */ jsx(MenuContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
975
+ "div",
976
+ {
977
+ ...props,
978
+ ...popup.contentAttributes,
979
+ style: mergeStyle(popup.contentAttributes.style, style),
980
+ ref: (node) => setRefs(node, popup.contentRef, ref),
981
+ role: "menu",
982
+ "aria-label": label,
983
+ tabIndex: -1,
984
+ className: classes("hc-ui-menu", className),
985
+ onKeyDown: handleKeyDown,
986
+ children
987
+ }
988
+ ) })
989
+ )
990
+ ] });
991
+ });
992
+ function useMenu(name) {
993
+ const menu = useContext(MenuContext);
994
+ if (!menu) throw new Error(`${name} must be inside a Menu`);
995
+ return menu;
996
+ }
997
+ var checkGlyph = /* @__PURE__ */ jsx("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", strokeWidth: 1.8, "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M5 13L9 17L19 7", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" }) });
998
+ var MenuRow = forwardRef(function MenuRow2({ icon, hint, danger, end, role, onChoose, className, children, type = "button", onClick, ...props }, ref) {
999
+ return /* @__PURE__ */ jsxs(
1000
+ "button",
1001
+ {
1002
+ ...props,
1003
+ ref,
1004
+ type,
1005
+ role,
1006
+ tabIndex: -1,
1007
+ className: classes("hc-ui-menu__item", className),
1008
+ "data-danger": danger || void 0,
1009
+ onClick: (event) => {
1010
+ onClick?.(event);
1011
+ if (!event.defaultPrevented) onChoose(event);
1012
+ },
1013
+ children: [
1014
+ /* @__PURE__ */ jsxs("span", { className: "hc-ui-menu__text", children: [
1015
+ children,
1016
+ hint && /* @__PURE__ */ jsx("small", { className: "hc-ui-menu__hint", children: hint })
1017
+ ] }),
1018
+ end,
1019
+ icon && /* @__PURE__ */ jsx("span", { className: "hc-ui-menu__icon", "aria-hidden": "true", children: icon })
1020
+ ]
1021
+ }
1022
+ );
1023
+ });
1024
+ var MenuItem = forwardRef(function MenuItem2({ onSelect, ...props }, ref) {
1025
+ const menu = useMenu("MenuItem");
1026
+ return /* @__PURE__ */ jsx(MenuRow, { ...props, ref, role: "menuitem", onChoose: (event) => {
1027
+ onSelect?.(event);
1028
+ if (!event.defaultPrevented) menu.close("if-lost");
1029
+ } });
1030
+ });
1031
+ function MenuRadioGroup({ value, onValueChange, label, className, children, ...props }) {
1032
+ const context = useMemo(() => ({ value, onValueChange }), [value, onValueChange]);
1033
+ return /* @__PURE__ */ jsx(RadioContext.Provider, { value: context, children: /* @__PURE__ */ jsx("div", { ...props, role: "group", "aria-label": label, className: classes("hc-ui-menu__group", className), children }) });
1034
+ }
1035
+ var MenuItemRadio = forwardRef(function MenuItemRadio2({ value, ...props }, ref) {
1036
+ const menu = useMenu("MenuItemRadio");
1037
+ const group = useContext(RadioContext);
1038
+ if (!group) throw new Error("MenuItemRadio must be inside a MenuRadioGroup");
1039
+ const checked = group.value === value;
1040
+ return /* @__PURE__ */ jsx(
1041
+ MenuRow,
1042
+ {
1043
+ ...props,
1044
+ ref,
1045
+ role: "menuitemradio",
1046
+ "aria-checked": checked,
1047
+ end: checked ? /* @__PURE__ */ jsx("span", { className: "hc-ui-menu__check", children: checkGlyph }) : void 0,
1048
+ onChoose: () => {
1049
+ group.onValueChange(value);
1050
+ menu.close("trigger");
1051
+ }
1052
+ }
1053
+ );
1054
+ });
1055
+ var MenuItemCheckbox = forwardRef(function MenuItemCheckbox2({ checked, onCheckedChange, closeOnSelect = false, ...props }, ref) {
1056
+ const menu = useMenu("MenuItemCheckbox");
1057
+ return /* @__PURE__ */ jsx(
1058
+ MenuRow,
1059
+ {
1060
+ ...props,
1061
+ ref,
1062
+ role: "menuitemcheckbox",
1063
+ "aria-checked": checked,
1064
+ end: checked ? /* @__PURE__ */ jsx("span", { className: "hc-ui-menu__check", children: checkGlyph }) : void 0,
1065
+ onChoose: () => {
1066
+ onCheckedChange(!checked);
1067
+ if (closeOnSelect) menu.close("trigger");
1068
+ }
1069
+ }
1070
+ );
1071
+ });
1072
+ function MenuSeparator({ className, ...props }) {
1073
+ return /* @__PURE__ */ jsx("div", { ...props, role: "separator", className: classes("hc-ui-menu__separator", className) });
1074
+ }
1075
+ function MenuLabel({ className, ...props }) {
1076
+ return /* @__PURE__ */ jsx("div", { ...props, className: classes("hc-ui-menu__label", className) });
1077
+ }
1078
+ function SortMenu({ label, value, options, onChange, applied = false, size = "sm", triggerClassName, ...props }) {
1079
+ const current = options.find((option) => option.value === value)?.label;
1080
+ return /* @__PURE__ */ jsx(
1081
+ Menu,
1082
+ {
1083
+ ...props,
1084
+ label,
1085
+ trigger: /* @__PURE__ */ jsx(Chip, { size, applied, className: triggerClassName, "aria-label": current === void 0 ? label : `${label}: ${current}`, children: current }),
1086
+ children: /* @__PURE__ */ jsx(MenuRadioGroup, { value, onValueChange: onChange, children: options.map((option) => /* @__PURE__ */ jsx(MenuItemRadio, { value: option.value, hint: option.hint, disabled: option.disabled, children: option.label }, option.value)) })
1087
+ }
1088
+ );
1089
+ }
1090
+ var Popover = forwardRef(function Popover2({ label, trigger, children, autoFocus = false, open, defaultOpen, onOpenChange, side, align, portal, theme, anchorClassName, className, style, id, ...props }, ref) {
1091
+ const popup = usePopup({
1092
+ kind: "dialog",
1093
+ trigger,
1094
+ open,
1095
+ defaultOpen,
1096
+ onOpenChange,
1097
+ side,
1098
+ align,
1099
+ portal,
1100
+ theme,
1101
+ contentId: id,
1102
+ onShown: (content) => {
1103
+ if (!autoFocus) return;
1104
+ content.querySelector('button:not(:disabled), [href], input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex="-1"])')?.focus({ preventScroll: true });
1105
+ }
1106
+ });
1107
+ const close = useCallback(() => popup.close("trigger"), [popup.close]);
1108
+ return /* @__PURE__ */ jsxs("div", { className: classes("hc-ui-popup-anchor", anchorClassName), ref: popup.anchorRef, children: [
1109
+ popup.triggerNode,
1110
+ popup.wrap(
1111
+ /* @__PURE__ */ jsx(
1112
+ "div",
1113
+ {
1114
+ ...props,
1115
+ ...popup.contentAttributes,
1116
+ style: mergeStyle(popup.contentAttributes.style, style),
1117
+ ref: (node) => setRefs(node, popup.contentRef, ref),
1118
+ role: "dialog",
1119
+ "aria-label": label,
1120
+ tabIndex: -1,
1121
+ className: classes("hc-ui-popover", className),
1122
+ children: typeof children === "function" ? children({ close }) : children
1123
+ }
1124
+ )
1125
+ )
1126
+ ] });
1127
+ });
1128
+ var arrowGlyph = (up) => glyph(12, up ? "M12 21L12 3M12 3L20.5 11.5M12 3L3.5 11.5" : "M12 3L12 21M12 21L20.5 12.5M12 21L3.5 12.5");
1129
+ function TableInner({ columns, rows, rowKey, sort, onSort, stickyHeader = false, onRowClick, selectedKey, className, ...props }, ref) {
1130
+ const alignOf = (column) => column.align ?? (column.numeric ? "end" : "start");
1131
+ const cellLook = (column) => ({
1132
+ className: column.className,
1133
+ "data-align": alignOf(column),
1134
+ "data-numeric": column.numeric || void 0,
1135
+ "data-tone": column.tone
1136
+ });
1137
+ const rowHeaderKey = columns.find((column) => column.rowHeader)?.key;
1138
+ return /* @__PURE__ */ jsxs("table", { ...props, ref, className: classes("hc-ui-table", className), "data-sticky-header": stickyHeader || void 0, "data-clickable": onRowClick ? "" : void 0, children: [
1139
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((column) => {
1140
+ const direction = column.sortable ? sort && sort.key === column.key ? sort.direction : "none" : void 0;
1141
+ return /* @__PURE__ */ jsx(
1142
+ "th",
1143
+ {
1144
+ scope: "col",
1145
+ ...cellLook(column),
1146
+ "aria-sort": direction,
1147
+ style: column.width === void 0 ? void 0 : { width: column.width },
1148
+ children: column.sortable ? /* @__PURE__ */ jsxs("button", { type: "button", className: "hc-ui-table__sort", onClick: () => onSort?.(column.key), children: [
1149
+ column.header,
1150
+ direction !== "none" && arrowGlyph(direction === "ascending")
1151
+ ] }) : column.header
1152
+ },
1153
+ column.key
1154
+ );
1155
+ }) }) }),
1156
+ /* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => {
1157
+ const key = rowKey(row, index);
1158
+ const selected = selectedKey !== void 0 && selectedKey !== null && key === selectedKey;
1159
+ const press = onRowClick && (() => onRowClick(row, index));
1160
+ return /* @__PURE__ */ jsx("tr", { onClick: press, "data-selected": selected || void 0, children: columns.map((column) => {
1161
+ const content = column.cell(row, index);
1162
+ if (!column.rowHeader) return /* @__PURE__ */ jsx("td", { ...cellLook(column), children: content }, column.key);
1163
+ return /* @__PURE__ */ jsx("th", { scope: "row", ...cellLook(column), children: press && column.key === rowHeaderKey ? /* @__PURE__ */ jsx(
1164
+ "button",
1165
+ {
1166
+ type: "button",
1167
+ className: "hc-ui-table__row-button",
1168
+ "aria-current": selected || void 0,
1169
+ onClick: (event) => {
1170
+ event.stopPropagation();
1171
+ press();
1172
+ },
1173
+ children: content
1174
+ }
1175
+ ) : content }, column.key);
1176
+ }) }, key);
1177
+ }) })
1178
+ ] });
1179
+ }
1180
+ var Table = forwardRef(TableInner);
1181
+ var Heading = ({ level, ...props }) => {
1182
+ const Tag = `h${level}`;
1183
+ return /* @__PURE__ */ jsx(Tag, { ...props });
1184
+ };
1185
+ var PageHeader = forwardRef(function PageHeader2({ title, level = 1, count, actions, visuallyHidden = false, className, ...props }, ref) {
1186
+ return /* @__PURE__ */ jsxs("header", { ...props, ref, className: classes("hc-ui-page-header", className), "data-visually-hidden": visuallyHidden || void 0, children: [
1187
+ /* @__PURE__ */ jsxs(Heading, { level, className: "hc-ui-page-header__title", children: [
1188
+ title,
1189
+ visible(count) && count !== 0 && /* @__PURE__ */ jsxs(Fragment2, { children: [
1190
+ " ",
1191
+ /* @__PURE__ */ jsx("small", { className: "hc-ui-page-header__count", children: count })
1192
+ ] })
1193
+ ] }),
1194
+ actions && /* @__PURE__ */ jsx("div", { className: "hc-ui-page-header__actions", children: actions })
1195
+ ] });
1196
+ });
1197
+ var navArrow = glyph(14, "M9 6L15 12L9 18");
1198
+ var PanelHeader = forwardRef(function PanelHeader2({ title, level = 2, variant = "bar", eyebrow, subtitle, subtitleInline = false, icon, trail, trailLabel, actions, onClose, closeLabel, closeTitle, closeIcon, className, ...props }, ref) {
1199
+ const steps = trail && trail.length > 0 ? trail : null;
1200
+ return /* @__PURE__ */ jsxs(
1201
+ "header",
1202
+ {
1203
+ ...props,
1204
+ ref,
1205
+ className: classes("hc-ui-panel-header", className),
1206
+ "data-variant": variant,
1207
+ "data-subtitle": subtitle && subtitleInline ? "inline" : void 0,
1208
+ children: [
1209
+ icon && /* @__PURE__ */ jsx("span", { className: "hc-ui-panel-header__icon", "aria-hidden": "true", children: icon }),
1210
+ steps ? /* @__PURE__ */ jsx("nav", { className: "hc-ui-panel-header__trail", "aria-label": trailLabel, children: steps.map((step, index) => {
1211
+ const last = index === steps.length - 1;
1212
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1213
+ index > 0 && navArrow,
1214
+ last ? /* @__PURE__ */ jsx(Heading, { level, className: "hc-ui-panel-header__title", "aria-current": "location", children: step.label }) : step.onSelect ? /* @__PURE__ */ jsx("button", { type: "button", className: "hc-ui-panel-header__step", onClick: step.onSelect, children: step.label }) : /* @__PURE__ */ jsx("strong", { className: "hc-ui-panel-header__title", children: step.label })
1215
+ ] }, `${index}:${step.label}`);
1216
+ }) }) : /* @__PURE__ */ jsxs("div", { className: "hc-ui-panel-header__text", children: [
1217
+ eyebrow && /* @__PURE__ */ jsx("p", { className: "hc-ui-panel-header__eyebrow", children: eyebrow }),
1218
+ /* @__PURE__ */ jsx(Heading, { level, className: "hc-ui-panel-header__title", children: title }),
1219
+ subtitle && /* @__PURE__ */ jsx("p", { className: "hc-ui-panel-header__subtitle", children: subtitle })
1220
+ ] }),
1221
+ actions && /* @__PURE__ */ jsx("div", { className: "hc-ui-panel-header__actions", children: actions }),
1222
+ onClose && /* @__PURE__ */ jsx("button", { type: "button", className: "hc-ui-panel-header__close", onClick: onClose, "aria-label": closeLabel, title: closeTitle ?? closeLabel, children: closeIcon ?? glyph(18, XMARK) })
1223
+ ]
1224
+ }
1225
+ );
1226
+ });
1227
+ var ListRow = forwardRef(function ListRow2({ type = "button", className, ...props }, ref) {
1228
+ return /* @__PURE__ */ jsx("button", { ...props, ref, type, className: classes("hc-ui-list-row", className) });
1229
+ });
1230
+ var searchGlyph = /* @__PURE__ */ jsxs("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", strokeWidth: 1.8, "aria-hidden": "true", focusable: "false", children: [
1231
+ /* @__PURE__ */ jsx("path", { d: "M17 17L21 21", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" }),
1232
+ /* @__PURE__ */ jsx("path", { d: "M3 11C3 15.4183 6.58172 19 11 19C13.213 19 15.2161 18.1015 16.6644 16.6493C18.1077 15.2022 19 13.2053 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11Z", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round" })
1233
+ ] });
1234
+ var CommandPalette = forwardRef(function CommandPalette2({
1235
+ open,
1236
+ onClose,
1237
+ label,
1238
+ inputLabel,
1239
+ placeholder,
1240
+ query,
1241
+ onQueryChange,
1242
+ groups,
1243
+ searchIcon,
1244
+ loading,
1245
+ empty,
1246
+ selectHint,
1247
+ altHint,
1248
+ hints,
1249
+ listClassName,
1250
+ className,
1251
+ onClick,
1252
+ onPointerDown,
1253
+ ...props
1254
+ }, ref) {
1255
+ const dialogRef = useRef(null);
1256
+ const inputRef = useRef(null);
1257
+ const listRef = useRef(null);
1258
+ const setRef = useCallback((node) => setRefs(node, dialogRef, ref), [ref]);
1259
+ const id = useId();
1260
+ const listId = `${id}-list`;
1261
+ const optionId = (index2) => `${id}-option-${index2}`;
1262
+ const items = useMemo(() => groups.flatMap((group) => group.items), [groups]);
1263
+ const [active, setActive] = useState(0);
1264
+ const [seen, setSeen] = useState({ query, open });
1265
+ if (seen.query !== query || seen.open !== open) {
1266
+ setSeen({ query, open });
1267
+ if (active !== 0) setActive(0);
1268
+ }
1269
+ const current = items.length ? Math.min(active, items.length - 1) : -1;
1270
+ const latest = useRef({ open, onClose });
1271
+ useIsomorphicLayoutEffect(() => {
1272
+ latest.current = { open, onClose };
1273
+ });
1274
+ useIsomorphicLayoutEffect(() => {
1275
+ const dialog = dialogRef.current;
1276
+ if (!open || !dialog) return;
1277
+ const trigger = document.activeElement instanceof HTMLElement && !dialog.contains(document.activeElement) ? document.activeElement : null;
1278
+ if (!dialog.open) dialog.showModal();
1279
+ inputRef.current?.focus();
1280
+ const unlock = lockScroll();
1281
+ return () => {
1282
+ unlock();
1283
+ if (dialog.open) dialog.close();
1284
+ queueMicrotask(() => {
1285
+ const focused = document.activeElement;
1286
+ const lost = !focused || focused === document.body || dialog.contains(focused);
1287
+ if (lost && !dialog.open && trigger?.isConnected) trigger.focus({ preventScroll: true });
1288
+ });
1289
+ };
1290
+ }, [open]);
1291
+ useEffect(() => {
1292
+ if (open && current >= 0) listRef.current?.querySelector('[aria-selected="true"]')?.scrollIntoView({ block: "nearest" });
1293
+ }, [open, current]);
1294
+ const ownEvent = (event) => event.target === event.currentTarget;
1295
+ const handleCancel = (event) => {
1296
+ if (!ownEvent(event)) return;
1297
+ event.preventDefault();
1298
+ latest.current.onClose();
1299
+ };
1300
+ const handleNativeClose = (event) => {
1301
+ const dialog = event.currentTarget;
1302
+ if (!ownEvent(event) || dialog.open || !latest.current.open) return;
1303
+ latest.current.onClose();
1304
+ window.setTimeout(() => {
1305
+ if (latest.current.open && dialog.isConnected && !dialog.open) {
1306
+ dialog.showModal();
1307
+ inputRef.current?.focus();
1308
+ }
1309
+ }, 0);
1310
+ };
1311
+ const pressedBackdrop = useRef(false);
1312
+ const handlePointerDown = (event) => {
1313
+ onPointerDown?.(event);
1314
+ pressedBackdrop.current = ownEvent(event) && outside(event.currentTarget, event.clientX, event.clientY);
1315
+ };
1316
+ const handleClick = (event) => {
1317
+ onClick?.(event);
1318
+ const fromBackdrop = pressedBackdrop.current && ownEvent(event) && outside(event.currentTarget, event.clientX, event.clientY);
1319
+ pressedBackdrop.current = false;
1320
+ if (fromBackdrop) latest.current.onClose();
1321
+ };
1322
+ const handleKeyDown = (event) => {
1323
+ const count = items.length;
1324
+ if (!count || event.nativeEvent.isComposing || event.altKey) return;
1325
+ let next = null;
1326
+ if (event.key === "ArrowDown") next = (current + 1) % count;
1327
+ else if (event.key === "ArrowUp") next = (current - 1 + count) % count;
1328
+ else if (event.key === "Home" && !event.shiftKey) next = 0;
1329
+ else if (event.key === "End" && !event.shiftKey) next = count - 1;
1330
+ else if (event.key === "Enter") {
1331
+ const item = items[current];
1332
+ event.preventDefault();
1333
+ if ((event.metaKey || event.ctrlKey) && item.onAltSelect) item.onAltSelect();
1334
+ else item.onSelect();
1335
+ return;
1336
+ }
1337
+ if (next === null) return;
1338
+ event.preventDefault();
1339
+ setActive(next);
1340
+ };
1341
+ if (!open) return null;
1342
+ let index = 0;
1343
+ return /* @__PURE__ */ jsx(
1344
+ "dialog",
1345
+ {
1346
+ ...props,
1347
+ ref: setRef,
1348
+ className: classes("hc-ui-command-palette", className),
1349
+ "aria-label": label,
1350
+ onCancel: handleCancel,
1351
+ onClose: handleNativeClose,
1352
+ onPointerDown: handlePointerDown,
1353
+ onClick: handleClick,
1354
+ children: /* @__PURE__ */ jsxs("div", { className: "hc-ui-command-palette__box", onKeyDown: handleKeyDown, children: [
1355
+ /* @__PURE__ */ jsxs("label", { className: "hc-ui-command-palette__field", children: [
1356
+ searchIcon ?? searchGlyph,
1357
+ /* @__PURE__ */ jsx(
1358
+ "input",
1359
+ {
1360
+ ref: inputRef,
1361
+ className: "hc-ui-command-palette__input",
1362
+ value: query,
1363
+ placeholder,
1364
+ onChange: (event) => onQueryChange(event.target.value),
1365
+ autoComplete: "off",
1366
+ "aria-label": inputLabel ?? label,
1367
+ role: "combobox",
1368
+ "aria-expanded": "true",
1369
+ "aria-controls": listId,
1370
+ "aria-autocomplete": "list",
1371
+ "aria-activedescendant": current >= 0 ? optionId(current) : void 0
1372
+ }
1373
+ ),
1374
+ visible(loading) && /* @__PURE__ */ jsx("span", { className: "hc-ui-command-palette__status", children: loading })
1375
+ ] }),
1376
+ /* @__PURE__ */ jsxs(
1377
+ "div",
1378
+ {
1379
+ ref: listRef,
1380
+ className: classes("hc-ui-command-palette__list", listClassName),
1381
+ id: listId,
1382
+ role: "listbox",
1383
+ "aria-label": label,
1384
+ "aria-busy": visible(loading) || void 0,
1385
+ children: [
1386
+ visible(empty) && /* @__PURE__ */ jsx("p", { className: "hc-ui-command-palette__empty", children: empty }),
1387
+ groups.map((group, groupIndex) => {
1388
+ if (!group.items.length) return null;
1389
+ const headingId = visible(group.heading) ? `${id}-group-${groupIndex}` : void 0;
1390
+ return /* @__PURE__ */ jsxs("div", { className: "hc-ui-command-palette__group", role: headingId ? "group" : "presentation", "aria-labelledby": headingId, children: [
1391
+ headingId && /* @__PURE__ */ jsx("p", { className: "hc-ui-command-palette__heading", id: headingId, "aria-hidden": "true", children: group.heading }),
1392
+ group.items.map((item) => {
1393
+ const itemIndex = index++;
1394
+ const isActive = itemIndex === current;
1395
+ const itemAltHint = item.onAltSelect ? item.altHint ?? altHint : void 0;
1396
+ return /* @__PURE__ */ jsxs(
1397
+ "button",
1398
+ {
1399
+ type: "button",
1400
+ tabIndex: -1,
1401
+ id: optionId(itemIndex),
1402
+ role: "option",
1403
+ "aria-selected": isActive,
1404
+ className: "hc-ui-command-palette__item",
1405
+ onMouseDown: (event) => event.preventDefault(),
1406
+ onMouseMove: () => {
1407
+ if (!isActive) setActive(itemIndex);
1408
+ },
1409
+ onClick: () => item.onSelect(),
1410
+ children: [
1411
+ item.icon !== void 0 && /* @__PURE__ */ jsx("span", { className: "hc-ui-command-palette__icon", "aria-hidden": "true", children: item.icon }),
1412
+ /* @__PURE__ */ jsxs("span", { className: "hc-ui-command-palette__text", children: [
1413
+ /* @__PURE__ */ jsx("span", { className: "hc-ui-command-palette__label", children: item.label }),
1414
+ visible(item.detail) && /* @__PURE__ */ jsx("small", { className: "hc-ui-command-palette__detail", children: item.detail })
1415
+ ] }),
1416
+ isActive && visible(itemAltHint) && /* @__PURE__ */ jsx("kbd", { className: "hc-ui-command-palette__kbd", "aria-hidden": "true", children: itemAltHint }),
1417
+ isActive && visible(selectHint) && /* @__PURE__ */ jsx("kbd", { className: "hc-ui-command-palette__kbd", "aria-hidden": "true", children: selectHint })
1418
+ ]
1419
+ },
1420
+ item.key
1421
+ );
1422
+ })
1423
+ ] }, group.key);
1424
+ })
1425
+ ]
1426
+ }
1427
+ ),
1428
+ hints && hints.length > 0 && /* @__PURE__ */ jsx("footer", { className: "hc-ui-command-palette__footer", children: hints.map((hint, hintIndex) => /* @__PURE__ */ jsxs("span", { children: [
1429
+ hint.keys.map((key, keyIndex) => /* @__PURE__ */ jsx("kbd", { className: "hc-ui-command-palette__kbd", children: key }, keyIndex)),
1430
+ " ",
1431
+ hint.label
1432
+ ] }, hintIndex)) })
1433
+ ] })
1434
+ }
1435
+ );
1436
+ });
172
1437
  export {
173
1438
  Button,
1439
+ Checkbox,
174
1440
  Chip,
1441
+ CommandPalette,
1442
+ Dialog,
175
1443
  Field,
1444
+ FilterBar,
176
1445
  IconButton,
1446
+ ListRow,
1447
+ Menu,
1448
+ MenuItem,
1449
+ MenuItemCheckbox,
1450
+ MenuItemRadio,
1451
+ MenuLabel,
1452
+ MenuRadioGroup,
1453
+ MenuSeparator,
1454
+ Meter,
1455
+ PageHeader,
1456
+ PanelHeader,
1457
+ Popover,
177
1458
  SegmentedControl,
1459
+ Sheet,
1460
+ SheetChips,
1461
+ SheetOptions,
178
1462
  Skeleton,
179
- Surface
1463
+ SortMenu,
1464
+ Surface,
1465
+ Table,
1466
+ placePopup
180
1467
  };