react-os-shell 4.67.0 → 4.74.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 (58) hide show
  1. package/README.md +2 -0
  2. package/dist/{Browser-NBYPPENQ.js → Browser-ZF5X2FON.js} +6 -6
  3. package/dist/{Browser-NBYPPENQ.js.map → Browser-ZF5X2FON.js.map} +1 -1
  4. package/dist/{Calculator-UNAVT7IE.js → Calculator-SA62H5S3.js} +5 -5
  5. package/dist/{Calculator-UNAVT7IE.js.map → Calculator-SA62H5S3.js.map} +1 -1
  6. package/dist/{CurrencyConverter-KURXJHLK.js → CurrencyConverter-BMCRLZLY.js} +5 -5
  7. package/dist/{CurrencyConverter-KURXJHLK.js.map → CurrencyConverter-BMCRLZLY.js.map} +1 -1
  8. package/dist/{Documents-7CUBCETC.js → Documents-2TGJPV2Y.js} +7 -7
  9. package/dist/{Documents-7CUBCETC.js.map → Documents-2TGJPV2Y.js.map} +1 -1
  10. package/dist/{Files-UXEDRQF4.js → Files-Z3ONKUA6.js} +8 -8
  11. package/dist/{Files-UXEDRQF4.js.map → Files-Z3ONKUA6.js.map} +1 -1
  12. package/dist/{Notepad-ON4T45UP.js → Notepad-JWZS5YKJ.js} +7 -7
  13. package/dist/{Notepad-ON4T45UP.js.map → Notepad-JWZS5YKJ.js.map} +1 -1
  14. package/dist/{PomodoroTimer-J7V5VXR4.js → PomodoroTimer-DRM5W25H.js} +7 -7
  15. package/dist/{PomodoroTimer-J7V5VXR4.js.map → PomodoroTimer-DRM5W25H.js.map} +1 -1
  16. package/dist/{Preview-QINOPDT2.js → Preview-7O7W7OMQ.js} +8 -8
  17. package/dist/{Preview-QINOPDT2.js.map → Preview-7O7W7OMQ.js.map} +1 -1
  18. package/dist/{Spreadsheet-OFF3J4HN.js → Spreadsheet-CLTZSW3T.js} +6 -6
  19. package/dist/{Spreadsheet-OFF3J4HN.js.map → Spreadsheet-CLTZSW3T.js.map} +1 -1
  20. package/dist/{Stock-BSU7S7MW.js → Stock-CO5N3N2M.js} +5 -5
  21. package/dist/{Stock-BSU7S7MW.js.map → Stock-CO5N3N2M.js.map} +1 -1
  22. package/dist/{Weather-BKNRVMG6.js → Weather-IEGJX7RI.js} +5 -5
  23. package/dist/{Weather-BKNRVMG6.js.map → Weather-IEGJX7RI.js.map} +1 -1
  24. package/dist/{WorldClock-VMTD2QWD.js → WorldClock-FLW3QZYG.js} +5 -5
  25. package/dist/{WorldClock-VMTD2QWD.js.map → WorldClock-FLW3QZYG.js.map} +1 -1
  26. package/dist/apps/index.js +16 -16
  27. package/dist/{chunk-TK6HI2U4.js → chunk-2VM2FRZJ.js} +42 -11
  28. package/dist/chunk-2VM2FRZJ.js.map +1 -0
  29. package/dist/{chunk-ECE3B3FZ.js → chunk-AXWC3332.js} +3 -3
  30. package/dist/{chunk-ECE3B3FZ.js.map → chunk-AXWC3332.js.map} +1 -1
  31. package/dist/{chunk-ZCDFNZQS.js → chunk-BLLINYDD.js} +97 -5
  32. package/dist/chunk-BLLINYDD.js.map +1 -0
  33. package/dist/{chunk-HAFM6ZQD.js → chunk-EG3WEQBH.js} +4 -4
  34. package/dist/{chunk-HAFM6ZQD.js.map → chunk-EG3WEQBH.js.map} +1 -1
  35. package/dist/{chunk-GRSVL6WX.js → chunk-G7IHPEJE.js} +136 -37
  36. package/dist/chunk-G7IHPEJE.js.map +1 -0
  37. package/dist/chunk-NJDH5PHA.js +7 -0
  38. package/dist/{chunk-K35QFOJF.js.map → chunk-NJDH5PHA.js.map} +1 -1
  39. package/dist/{chunk-E2N5WEHI.js → chunk-RUAZJ54W.js} +3 -3
  40. package/dist/{chunk-E2N5WEHI.js.map → chunk-RUAZJ54W.js.map} +1 -1
  41. package/dist/{chunk-B3IYV7JN.js → chunk-S6K37RLY.js} +196 -73
  42. package/dist/chunk-S6K37RLY.js.map +1 -0
  43. package/dist/{chunk-IOCOH2QQ.js → chunk-TT2WNTDS.js} +4 -4
  44. package/dist/{chunk-IOCOH2QQ.js.map → chunk-TT2WNTDS.js.map} +1 -1
  45. package/dist/{chunk-3OCL3DB4.js → chunk-TT56U4GY.js} +3 -3
  46. package/dist/{chunk-3OCL3DB4.js.map → chunk-TT56U4GY.js.map} +1 -1
  47. package/dist/{index-DM-d12A7.d.ts → index-DVekeidu.d.ts} +171 -6
  48. package/dist/index.d.ts +2 -2
  49. package/dist/index.js +119 -33
  50. package/dist/index.js.map +1 -1
  51. package/dist/ui/index.d.ts +1 -1
  52. package/dist/ui/index.js +4 -4
  53. package/package.json +2 -2
  54. package/dist/chunk-B3IYV7JN.js.map +0 -1
  55. package/dist/chunk-GRSVL6WX.js.map +0 -1
  56. package/dist/chunk-K35QFOJF.js +0 -7
  57. package/dist/chunk-TK6HI2U4.js.map +0 -1
  58. package/dist/chunk-ZCDFNZQS.js.map +0 -1
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var VERSION = "4.74.0" ;
3
+ var APP_VERSION = VERSION;
4
+
5
+ export { APP_VERSION, VERSION };
6
+ //# sourceMappingURL=chunk-NJDH5PHA.js.map
7
+ //# sourceMappingURL=chunk-NJDH5PHA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,QAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-K35QFOJF.js","sourcesContent":["declare const __PKG_VERSION__: string | undefined;\n\n/** Package version, injected by tsup at build time. Stays as an empty\n * string when the source is consumed without a build (e.g. tests). */\nexport const VERSION: string = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : '';\n\n/** Legacy alias kept so existing consumers do not break. */\nexport const APP_VERSION = VERSION;\n"]}
1
+ {"version":3,"sources":["../src/version.ts"],"names":[],"mappings":";AAIO,IAAM,OAAA,GAAwD,QAAA;AAG9D,IAAM,WAAA,GAAc","file":"chunk-NJDH5PHA.js","sourcesContent":["declare const __PKG_VERSION__: string | undefined;\n\n/** Package version, injected by tsup at build time. Stays as an empty\n * string when the source is consumed without a build (e.g. tests). */\nexport const VERSION: string = typeof __PKG_VERSION__ === 'string' ? __PKG_VERSION__ : '';\n\n/** Legacy alias kept so existing consumers do not break. */\nexport const APP_VERSION = VERSION;\n"]}
@@ -1,4 +1,4 @@
1
- import { Modal } from './chunk-GRSVL6WX.js';
1
+ import { Modal } from './chunk-G7IHPEJE.js';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
 
4
4
  var DEFAULT_APPEARANCE = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };
@@ -138,5 +138,5 @@ function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceCha
138
138
  }
139
139
 
140
140
  export { WidgetSettingsModal, loadAppearance };
141
- //# sourceMappingURL=chunk-E2N5WEHI.js.map
142
- //# sourceMappingURL=chunk-E2N5WEHI.js.map
141
+ //# sourceMappingURL=chunk-RUAZJ54W.js.map
142
+ //# sourceMappingURL=chunk-RUAZJ54W.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/shell/WidgetSettingsModal.tsx"],"names":[],"mappings":"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","file":"chunk-E2N5WEHI.js","sourcesContent":["import Modal from './Modal';\n\nexport interface WidgetAppearance {\n activeOpacity: number;\n inactiveOpacity: number;\n activeBlur: number;\n inactiveBlur: number;\n}\n\nexport const DEFAULT_APPEARANCE: WidgetAppearance = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };\n\nexport function loadAppearance(key: string): WidgetAppearance {\n try {\n const saved = JSON.parse(localStorage.getItem(key) || '');\n // Migrate old single `blur` field to activeBlur/inactiveBlur\n if (saved.blur != null && saved.activeBlur == null) {\n saved.activeBlur = saved.blur;\n saved.inactiveBlur = saved.blur;\n delete saved.blur;\n }\n return { ...DEFAULT_APPEARANCE, ...saved };\n }\n catch { return DEFAULT_APPEARANCE; }\n}\n\n/** Reusable settings modal for widgets — renders appearance sliders + optional extra content above */\nexport default function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceChange, onSave, children }: {\n open: boolean;\n onClose: () => void;\n title: string;\n appearance: WidgetAppearance;\n onAppearanceChange: (a: WidgetAppearance) => void;\n onSave: () => void;\n children?: React.ReactNode;\n}) {\n if (!open) return null;\n\n const inp = 'w-full h-1.5 rounded-full appearance-none bg-gray-200 cursor-pointer accent-blue-500';\n const lbl = 'flex items-center justify-between text-xs text-gray-500';\n\n return (\n <div onPointerDown={e => e.stopPropagation()} onContextMenu={e => e.stopPropagation()}>\n <Modal open={open} onClose={onClose} title={title} size=\"sm\">\n <div className=\"space-y-4\">\n {children}\n\n {/* Appearance */}\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-3\">Appearance</h3>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Active</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.activeOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.activeOpacity}\n onChange={e => onAppearanceChange({ ...appearance, activeOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.activeBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.activeBlur}\n onChange={e => onAppearanceChange({ ...appearance, activeBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Inactive</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.inactiveOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.inactiveOpacity}\n onChange={e => onAppearanceChange({ ...appearance, inactiveOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.inactiveBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.inactiveBlur}\n onChange={e => onAppearanceChange({ ...appearance, inactiveBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex gap-2 pt-2\">\n <button onClick={onSave}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition\">Save</button>\n <button onClick={onClose}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg border border-gray-300 text-gray-600 hover:bg-gray-50 transition\">Cancel</button>\n </div>\n </div>\n </Modal>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/shell/WidgetSettingsModal.tsx"],"names":[],"mappings":"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","file":"chunk-RUAZJ54W.js","sourcesContent":["import Modal from './Modal';\n\nexport interface WidgetAppearance {\n activeOpacity: number;\n inactiveOpacity: number;\n activeBlur: number;\n inactiveBlur: number;\n}\n\nexport const DEFAULT_APPEARANCE: WidgetAppearance = { activeOpacity: 70, inactiveOpacity: 50, activeBlur: 0, inactiveBlur: 0 };\n\nexport function loadAppearance(key: string): WidgetAppearance {\n try {\n const saved = JSON.parse(localStorage.getItem(key) || '');\n // Migrate old single `blur` field to activeBlur/inactiveBlur\n if (saved.blur != null && saved.activeBlur == null) {\n saved.activeBlur = saved.blur;\n saved.inactiveBlur = saved.blur;\n delete saved.blur;\n }\n return { ...DEFAULT_APPEARANCE, ...saved };\n }\n catch { return DEFAULT_APPEARANCE; }\n}\n\n/** Reusable settings modal for widgets — renders appearance sliders + optional extra content above */\nexport default function WidgetSettingsModal({ open, onClose, title, appearance, onAppearanceChange, onSave, children }: {\n open: boolean;\n onClose: () => void;\n title: string;\n appearance: WidgetAppearance;\n onAppearanceChange: (a: WidgetAppearance) => void;\n onSave: () => void;\n children?: React.ReactNode;\n}) {\n if (!open) return null;\n\n const inp = 'w-full h-1.5 rounded-full appearance-none bg-gray-200 cursor-pointer accent-blue-500';\n const lbl = 'flex items-center justify-between text-xs text-gray-500';\n\n return (\n <div onPointerDown={e => e.stopPropagation()} onContextMenu={e => e.stopPropagation()}>\n <Modal open={open} onClose={onClose} title={title} size=\"sm\">\n <div className=\"space-y-4\">\n {children}\n\n {/* Appearance */}\n <div>\n <h3 className=\"text-sm font-semibold text-gray-700 mb-3\">Appearance</h3>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Active</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.activeOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.activeOpacity}\n onChange={e => onAppearanceChange({ ...appearance, activeOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.activeBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.activeBlur}\n onChange={e => onAppearanceChange({ ...appearance, activeBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n <div>\n <div className=\"text-xs font-medium text-gray-600 mb-2\">Inactive</div>\n <div className=\"space-y-2\">\n <div>\n <div className={lbl}><span>Opacity</span><span>{appearance.inactiveOpacity}%</span></div>\n <input type=\"range\" min={20} max={100} value={appearance.inactiveOpacity}\n onChange={e => onAppearanceChange({ ...appearance, inactiveOpacity: +e.target.value })} className={inp} />\n </div>\n <div>\n <div className={lbl}><span>Blur</span><span>{appearance.inactiveBlur}px</span></div>\n <input type=\"range\" min={0} max={20} value={appearance.inactiveBlur}\n onChange={e => onAppearanceChange({ ...appearance, inactiveBlur: +e.target.value })} className={inp} />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n {/* Actions */}\n <div className=\"flex gap-2 pt-2\">\n <button onClick={onSave}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition\">Save</button>\n <button onClick={onClose}\n className=\"flex-1 text-sm font-medium py-2 rounded-lg border border-gray-300 text-gray-600 hover:bg-gray-50 transition\">Cancel</button>\n </div>\n </div>\n </Modal>\n </div>\n );\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { Breadcrumbs } from './chunk-HNH7FOYB.js';
2
2
  import { SidebarLayout } from './chunk-YG45DAUT.js';
3
- import { useIsMobile, PopupMenu, PopupMenuItem, useShellPrefs } from './chunk-ZCDFNZQS.js';
3
+ import { useIsMobile, useShellStrings, PopupMenu, PopupMenuItem, useShellPrefs } from './chunk-BLLINYDD.js';
4
4
  import { registerModalEscapeInterceptor, useFocusTrap, useScrollLock } from './chunk-CDR2Q64Q.js';
5
5
  import { glassStyle } from './chunk-3CUSBZWG.js';
6
6
  import { forwardRef, useId, useCallback, useState, useRef, useEffect, createContext, useLayoutEffect, useMemo, Children, isValidElement, cloneElement, useContext, Fragment as Fragment$1, Component, useSyncExternalStore } from 'react';
@@ -639,6 +639,47 @@ function FormField({
639
639
  ) : hint ? /* @__PURE__ */ jsx("p", { id: htmlFor ? `${htmlFor}-hint` : void 0, className: "mt-1 text-[11px] text-gray-400", children: hint }) : null
640
640
  ] });
641
641
  }
642
+ function FormErrorSummary({ errors, title, autoFocus = true, className = "" }) {
643
+ const strings = useShellStrings();
644
+ const boxRef = useRef(null);
645
+ const hadErrors = useRef(false);
646
+ useEffect(() => {
647
+ const has = errors.length > 0;
648
+ if (has && !hadErrors.current && autoFocus) boxRef.current?.focus();
649
+ hadErrors.current = has;
650
+ }, [errors.length > 0, autoFocus]);
651
+ if (errors.length === 0) return null;
652
+ const focusField = (fieldId) => {
653
+ const el = document.getElementById(fieldId);
654
+ if (!el) return;
655
+ el.scrollIntoView({ block: "center" });
656
+ el.focus();
657
+ };
658
+ return /* @__PURE__ */ jsxs(
659
+ "div",
660
+ {
661
+ ref: boxRef,
662
+ role: "alert",
663
+ tabIndex: -1,
664
+ className: `rounded-md border border-red-300 bg-red-50 px-4 py-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-400 ${className}`.trim(),
665
+ children: [
666
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-red-800", children: title ?? strings.form.errorSummaryTitle }),
667
+ /* @__PURE__ */ jsx("ul", { className: "mt-1.5 space-y-1", children: errors.map((e, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
668
+ "a",
669
+ {
670
+ href: `#${e.fieldId}`,
671
+ onClick: (event) => {
672
+ event.preventDefault();
673
+ focusField(e.fieldId);
674
+ },
675
+ className: "text-sm text-red-700 underline hover:text-red-900",
676
+ children: e.message
677
+ }
678
+ ) }, `${e.fieldId}-${i}`)) })
679
+ ]
680
+ }
681
+ );
682
+ }
642
683
  function Label({ required, children, className = "", ...rest }) {
643
684
  return /* @__PURE__ */ jsxs("label", { className: `mb-1 block text-xs font-medium text-gray-600 ${className}`.trim(), ...rest, children: [
644
685
  children,
@@ -2378,7 +2419,7 @@ function FilePicker({
2378
2419
  error && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-red-600", children: error })
2379
2420
  ] });
2380
2421
  }
2381
- function ClearButton({ onClear, ariaLabel = "Clear selection" }) {
2422
+ function ClearButton({ onClear, ariaLabel }) {
2382
2423
  return /* @__PURE__ */ jsx(
2383
2424
  "button",
2384
2425
  {
@@ -2399,7 +2440,7 @@ function SearchableSelect({
2399
2440
  onChange,
2400
2441
  options,
2401
2442
  placeholder,
2402
- emptyOptionLabel = "\u2014 None \u2014",
2443
+ emptyOptionLabel,
2403
2444
  className = "",
2404
2445
  disabled,
2405
2446
  id,
@@ -2409,6 +2450,8 @@ function SearchableSelect({
2409
2450
  }) {
2410
2451
  const [open, setOpen] = useState(false);
2411
2452
  const [search, setSearchState] = useState("");
2453
+ const strings = useShellStrings();
2454
+ const noneLabel = emptyOptionLabel ?? strings.select.none;
2412
2455
  const setSearch = (next) => {
2413
2456
  setSearchState(next);
2414
2457
  onSearchChange?.(next);
@@ -2510,13 +2553,13 @@ function SearchableSelect({
2510
2553
  setSearch("");
2511
2554
  }
2512
2555
  },
2513
- placeholder: placeholder || (emptyOptionLabel || "Select\u2026"),
2556
+ placeholder: placeholder || noneLabel,
2514
2557
  className: `${INPUT_BASE} ${className} ${value ? "pr-8" : ""} ${disabled ? "bg-gray-50 text-gray-400 cursor-not-allowed" : ""} truncate`,
2515
2558
  style: adornPad ? { paddingRight: adornPad } : void 0,
2516
2559
  disabled
2517
2560
  }
2518
2561
  ),
2519
- value && !disabled && /* @__PURE__ */ jsx(ClearButton, { onClear: () => {
2562
+ value && !disabled && /* @__PURE__ */ jsx(ClearButton, { ariaLabel: strings.select.clear, onClear: () => {
2520
2563
  onChange("");
2521
2564
  setOpen(false);
2522
2565
  setSearch("");
@@ -2541,7 +2584,7 @@ function SearchableSelect({
2541
2584
  visibility: menuPos ? void 0 : "hidden",
2542
2585
  ...glassStyle()
2543
2586
  },
2544
- children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2 }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children: "No matches" }) : filtered.map((o) => /* @__PURE__ */ jsxs(
2587
+ children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2 }, children: filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children: strings.select.noMatches }) : filtered.map((o) => /* @__PURE__ */ jsxs(
2545
2588
  "button",
2546
2589
  {
2547
2590
  type: "button",
@@ -2577,6 +2620,7 @@ function TagInput({
2577
2620
  }) {
2578
2621
  const [open, setOpen] = useState(false);
2579
2622
  const [search, setSearch] = useState("");
2623
+ const strings = useShellStrings();
2580
2624
  const wrapRef = useRef(null);
2581
2625
  const inputRef = useRef(null);
2582
2626
  const menuRef = useRef(null);
@@ -2640,7 +2684,7 @@ function TagInput({
2640
2684
  "button",
2641
2685
  {
2642
2686
  type: "button",
2643
- "aria-label": `Remove ${labelFor(v)}`,
2687
+ "aria-label": `${strings.select.remove} ${labelFor(v)}`,
2644
2688
  onClick: () => remove(v),
2645
2689
  className: "text-blue-400 hover:text-red-500 focus:outline-none focus-visible:ring-1 focus-visible:ring-blue-500 rounded leading-none",
2646
2690
  children: "\xD7"
@@ -2710,7 +2754,7 @@ function TagInput({
2710
2754
  visibility: menuPos ? void 0 : "hidden",
2711
2755
  ...glassStyle()
2712
2756
  },
2713
- children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2 }, children: available.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children: options.length > 0 && value.length >= options.length ? "All options selected" : "No matches" }) : available.map((o) => /* @__PURE__ */ jsx(
2757
+ children: /* @__PURE__ */ jsx("div", { className: "overflow-y-auto", style: { maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2 }, children: available.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-3 text-sm text-gray-400 text-center", children: options.length > 0 && value.length >= options.length ? strings.select.allSelected : strings.select.noMatches }) : available.map((o) => /* @__PURE__ */ jsx(
2714
2758
  "button",
2715
2759
  {
2716
2760
  type: "button",
@@ -4441,8 +4485,9 @@ function HelpCenter({
4441
4485
  onNew,
4442
4486
  onEdit,
4443
4487
  renderBody,
4444
- emptyMessage = "No help articles yet."
4488
+ emptyMessage
4445
4489
  }) {
4490
+ const strings = useShellStrings();
4446
4491
  const [query, setQuery] = useState("");
4447
4492
  const [selectedSlug, setSelectedSlug] = useState(null);
4448
4493
  const [expanded, setExpanded] = useState({});
@@ -4475,8 +4520,8 @@ function HelpCenter({
4475
4520
  return /* @__PURE__ */ jsxs("div", { className: "flex h-full gap-4 px-4 py-3 min-h-0", children: [
4476
4521
  /* @__PURE__ */ jsxs("aside", { className: "w-64 shrink-0 flex flex-col bg-white rounded-lg shadow overflow-hidden", children: [
4477
4522
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-3 py-2 border-b border-gray-200 bg-gray-50 shrink-0", children: [
4478
- /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-900", children: "Help" }),
4479
- canEdit && onNew && /* @__PURE__ */ jsx("button", { type: "button", onClick: onNew, className: "text-xs text-blue-600 hover:underline", children: "+ New" })
4523
+ /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold text-gray-900", children: strings.help.title }),
4524
+ canEdit && onNew && /* @__PURE__ */ jsx("button", { type: "button", onClick: onNew, className: "text-xs text-blue-600 hover:underline", children: strings.help.newArticle })
4480
4525
  ] }),
4481
4526
  /* @__PURE__ */ jsx("div", { className: "px-2.5 py-2 border-b border-gray-100 shrink-0", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4482
4527
  /* @__PURE__ */ jsx(
@@ -4502,12 +4547,12 @@ function HelpCenter({
4502
4547
  type: "text",
4503
4548
  value: query,
4504
4549
  onChange: (e) => setQuery(e.target.value),
4505
- placeholder: "Search help\u2026",
4550
+ placeholder: strings.help.searchPlaceholder,
4506
4551
  className: "w-full rounded-md border border-gray-300 bg-white py-1.5 pl-8 pr-2 text-sm shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
4507
4552
  }
4508
4553
  )
4509
4554
  ] }) }),
4510
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto py-1", children: loading ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-gray-400", children: "Loading\u2026" }) : visibleGroups.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-gray-500", children: q ? "No articles match your search." : emptyMessage }) : visibleGroups.map((group) => {
4555
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto py-1", children: loading ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-gray-400", children: strings.help.loading }) : visibleGroups.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-3 py-6 text-center text-xs text-gray-500", children: q ? strings.help.noResults : emptyMessage ?? strings.help.empty }) : visibleGroups.map((group) => {
4511
4556
  const open = isGroupOpen(group.key);
4512
4557
  return /* @__PURE__ */ jsxs("div", { className: "py-0.5", children: [
4513
4558
  /* @__PURE__ */ jsxs(
@@ -4532,7 +4577,7 @@ function HelpCenter({
4532
4577
  className: `w-full text-left pl-8 pr-3 py-1.5 text-sm flex items-center gap-1.5 transition-colors ${active ? "bg-blue-50 text-blue-700 font-medium" : "text-gray-700 hover:bg-gray-50"}`,
4533
4578
  children: [
4534
4579
  /* @__PURE__ */ jsx("span", { className: "truncate", children: doc.title }),
4535
- doc.is_published === false && /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 text-[10px] text-amber-600", children: "Draft" })
4580
+ doc.is_published === false && /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 text-[10px] text-amber-600", children: strings.help.draft })
4536
4581
  ]
4537
4582
  },
4538
4583
  doc.slug
@@ -4547,7 +4592,10 @@ function HelpCenter({
4547
4592
  /* @__PURE__ */ jsx("h1", { className: "text-lg font-semibold text-gray-900 truncate", children: selected.title }),
4548
4593
  /* @__PURE__ */ jsxs("p", { className: "text-xs text-gray-500 mt-0.5", children: [
4549
4594
  selected.category_label,
4550
- selected.is_published === false && /* @__PURE__ */ jsx("span", { className: "ml-2 text-amber-600", children: "\xB7 Draft" })
4595
+ selected.is_published === false && /* @__PURE__ */ jsxs("span", { className: "ml-2 text-amber-600", children: [
4596
+ "\xB7 ",
4597
+ strings.help.draft
4598
+ ] })
4551
4599
  ] })
4552
4600
  ] }),
4553
4601
  canEdit && onEdit && /* @__PURE__ */ jsx(
@@ -4556,12 +4604,12 @@ function HelpCenter({
4556
4604
  type: "button",
4557
4605
  onClick: () => onEdit(selected),
4558
4606
  className: "shrink-0 text-sm text-blue-600 hover:underline",
4559
- children: "Edit"
4607
+ children: strings.help.edit
4560
4608
  }
4561
4609
  )
4562
4610
  ] }),
4563
- /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto px-5 py-4", children: renderBody ? renderBody(selected) : selected.body ? /* @__PURE__ */ jsx(Markdown, { children: selected.body }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 italic", children: "This article has no body yet." }) })
4564
- ] }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center px-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: loading ? "Loading\u2026" : "Pick a help article from the left." }) }) })
4611
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto px-5 py-4", children: renderBody ? renderBody(selected) : selected.body ? /* @__PURE__ */ jsx(Markdown, { children: selected.body }) : /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 italic", children: strings.help.noBody }) })
4612
+ ] }) : /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center px-6 text-center", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500", children: loading ? strings.help.loading : strings.help.pickArticle }) }) })
4565
4613
  ] });
4566
4614
  }
4567
4615
  var VARIANTS = {
@@ -5271,11 +5319,14 @@ function DataTable({
5271
5319
  minWidth,
5272
5320
  rowClassName,
5273
5321
  onRow,
5274
- emptyText = "Nothing to show",
5322
+ emptyText,
5323
+ selection,
5275
5324
  footer,
5276
5325
  virtualized,
5277
5326
  className = ""
5278
5327
  }) {
5328
+ const strings = useShellStrings();
5329
+ const emptyContent = emptyText ?? strings.table.empty;
5279
5330
  const keyOf = (row, i) => typeof rowKey === "function" ? rowKey(row, i) : String(row[rowKey]);
5280
5331
  const [startRow, setStartRow] = useState(0);
5281
5332
  const overscan = virtualized?.overscan ?? 6;
@@ -5309,6 +5360,27 @@ function DataTable({
5309
5360
  };
5310
5361
  const leaves = columns.flatMap((h) => isGroup(h) ? h.columns : [h]);
5311
5362
  const grouped = columns.some(isGroup);
5363
+ const selectedSet = new Set(selection?.selected ?? []);
5364
+ const pageKeys = selection ? data.map((row, i) => keyOf(row, i)) : [];
5365
+ const allSelected = pageKeys.length > 0 && pageKeys.every((k) => selectedSet.has(k));
5366
+ const someSelected = pageKeys.some((k) => selectedSet.has(k));
5367
+ const toggleRow = (key) => {
5368
+ if (!selection) return;
5369
+ selection.onChange(
5370
+ selectedSet.has(key) ? selection.selected.filter((k) => k !== key) : [...selection.selected, key]
5371
+ );
5372
+ };
5373
+ const toggleAll = () => {
5374
+ if (!selection) return;
5375
+ const page = new Set(pageKeys);
5376
+ selection.onChange(
5377
+ allSelected ? selection.selected.filter((k) => !page.has(k)) : [...selection.selected, ...pageKeys.filter((k) => !selectedSet.has(k))]
5378
+ );
5379
+ };
5380
+ const SELECT_W = 36;
5381
+ const selOffset = selection ? SELECT_W : 0;
5382
+ const colCount = leaves.length + (selection ? 1 : 0);
5383
+ const hasPinned = leaves.some((c) => c.fixed === "left");
5312
5384
  const cellBase = `${PAD[size]} ${size === "sm" ? "text-xs" : "text-sm"}`;
5313
5385
  const headerCell = (col, ci, rowSpan, topOffset = 0) => {
5314
5386
  const dir = directionFor(col);
@@ -5322,7 +5394,7 @@ function DataTable({
5322
5394
  "aria-sort": dir === "asc" ? "ascending" : dir === "desc" ? "descending" : col.sortable && onSortChange ? "none" : void 0,
5323
5395
  style: {
5324
5396
  width: col.width,
5325
- ...pinned ? { left: offsets[ci] ?? 0 } : {},
5397
+ ...pinned ? { left: (offsets[ci] ?? 0) + selOffset } : {},
5326
5398
  // A virtualized header pins to the top of the vertical scroll; one
5327
5399
  // sticky box can hold both axes, so a pinned column's header corner
5328
5400
  // stays put in both directions.
@@ -5372,45 +5444,73 @@ function DataTable({
5372
5444
  // page around under the user.
5373
5445
  /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 z-20 flex items-start justify-center bg-white/60 pt-8", role: "status", "aria-live": "polite", children: [
5374
5446
  /* @__PURE__ */ jsx("span", { className: "h-6 w-6 animate-spin rounded-full border-2 border-gray-200 border-t-blue-600" }),
5375
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Loading" })
5447
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: strings.table.loading })
5376
5448
  ] }),
5377
5449
  /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse tabular-nums", style: minWidth ? { minWidth } : void 0, children: [
5378
5450
  caption && /* @__PURE__ */ jsx("caption", { className: "sr-only", children: caption }),
5379
5451
  /* @__PURE__ */ jsxs("thead", { children: [
5380
- /* @__PURE__ */ jsx("tr", { ref: headRowRef, className: "border-b border-gray-200 bg-gray-50", children: columns.map((h, hi) => {
5381
- if (isGroup(h)) {
5382
- return /* @__PURE__ */ jsx(
5383
- "th",
5384
- {
5385
- scope: "colgroup",
5386
- colSpan: h.columns.length,
5387
- style: virtualized ? { top: 0 } : void 0,
5388
- className: [
5389
- cellBase,
5390
- "text-center",
5391
- "font-semibold uppercase tracking-wide text-gray-500",
5392
- size === "sm" ? "text-[10px]" : "text-xs",
5393
- "border-b border-gray-200",
5394
- virtualized ? "sticky z-10 bg-gray-50" : "",
5395
- h.headerClassName ?? ""
5396
- ].filter(Boolean).join(" "),
5397
- children: h.title
5398
- },
5399
- h.key ?? `group-${hi}`
5400
- );
5401
- }
5402
- return headerCell(h, leaves.indexOf(h), grouped ? 2 : 1);
5403
- }) }),
5452
+ /* @__PURE__ */ jsxs("tr", { ref: headRowRef, className: "border-b border-gray-200 bg-gray-50", children: [
5453
+ selection && /* @__PURE__ */ jsx(
5454
+ "th",
5455
+ {
5456
+ scope: "col",
5457
+ rowSpan: grouped ? 2 : void 0,
5458
+ style: { width: SELECT_W, ...virtualized ? { top: 0 } : {} },
5459
+ className: [
5460
+ cellBase,
5461
+ hasPinned || virtualized ? "sticky z-20 bg-gray-50" : "",
5462
+ hasPinned ? "left-0" : ""
5463
+ ].filter(Boolean).join(" "),
5464
+ children: /* @__PURE__ */ jsx(
5465
+ "input",
5466
+ {
5467
+ type: "checkbox",
5468
+ "aria-label": strings.table.selectAll,
5469
+ checked: allSelected,
5470
+ ref: (el) => {
5471
+ if (el) el.indeterminate = someSelected && !allSelected;
5472
+ },
5473
+ onChange: toggleAll,
5474
+ className: "h-4 w-4 rounded border-gray-300 text-blue-600"
5475
+ }
5476
+ )
5477
+ }
5478
+ ),
5479
+ columns.map((h, hi) => {
5480
+ if (isGroup(h)) {
5481
+ return /* @__PURE__ */ jsx(
5482
+ "th",
5483
+ {
5484
+ scope: "colgroup",
5485
+ colSpan: h.columns.length,
5486
+ style: virtualized ? { top: 0 } : void 0,
5487
+ className: [
5488
+ cellBase,
5489
+ "text-center",
5490
+ "font-semibold uppercase tracking-wide text-gray-500",
5491
+ size === "sm" ? "text-[10px]" : "text-xs",
5492
+ "border-b border-gray-200",
5493
+ virtualized ? "sticky z-10 bg-gray-50" : "",
5494
+ h.headerClassName ?? ""
5495
+ ].filter(Boolean).join(" "),
5496
+ children: h.title
5497
+ },
5498
+ h.key ?? `group-${hi}`
5499
+ );
5500
+ }
5501
+ return headerCell(h, leaves.indexOf(h), grouped ? 2 : 1);
5502
+ })
5503
+ ] }),
5404
5504
  grouped && /* @__PURE__ */ jsx("tr", { className: "border-b border-gray-200 bg-gray-50", children: columns.flatMap((h) => isGroup(h) ? h.columns : []).map(
5405
5505
  (col) => headerCell(col, leaves.indexOf(col), 1, headRowH)
5406
5506
  ) })
5407
5507
  ] }),
5408
- /* @__PURE__ */ jsx("tbody", { children: data.length === 0 && !loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: leaves.length, className: `${cellBase} py-10 text-center text-gray-500`, children: emptyText }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5409
- topPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: leaves.length, style: { height: topPad, padding: 0, border: 0 } }) }),
5508
+ /* @__PURE__ */ jsx("tbody", { children: data.length === 0 && !loading ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx("td", { colSpan: colCount, className: `${cellBase} py-10 text-center text-gray-500`, children: emptyContent }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5509
+ topPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: topPad, padding: 0, border: 0 } }) }),
5410
5510
  data.slice(start, end).map((row, si) => {
5411
5511
  const i = start + si;
5412
5512
  const rowProps = onRow?.(row, i);
5413
- return /* @__PURE__ */ jsx(
5513
+ return /* @__PURE__ */ jsxs(
5414
5514
  "tr",
5415
5515
  {
5416
5516
  style: virtualized ? { height: virtualized.rowHeight } : void 0,
@@ -5430,32 +5530,55 @@ function DataTable({
5430
5530
  rowClassName?.(row, i) ?? "",
5431
5531
  rowProps?.className ?? ""
5432
5532
  ].filter(Boolean).join(" "),
5433
- children: leaves.map((col, ci) => {
5434
- const pinned = col.fixed === "left";
5435
- return /* @__PURE__ */ jsx(
5436
- "td",
5437
- {
5438
- style: pinned ? { left: offsets[ci] ?? 0 } : void 0,
5439
- className: [
5440
- cellBase,
5441
- ALIGN2[col.align ?? (col.numeric ? "right" : "left")],
5442
- col.numeric ? "font-mono" : "",
5443
- "text-gray-900",
5444
- col.ellipsis ? "max-w-0 truncate" : "",
5445
- // A pinned cell needs its own background or the
5446
- // scrolling columns show through it.
5447
- pinned ? "sticky z-10 bg-white" : ""
5448
- ].filter(Boolean).join(" "),
5449
- children: col.render ? col.render(row, i) : col.dataIndex ? row[col.dataIndex] : null
5450
- },
5451
- col.key
5452
- );
5453
- })
5533
+ children: [
5534
+ selection && (() => {
5535
+ const key = keyOf(row, i);
5536
+ return /* @__PURE__ */ jsx(
5537
+ "td",
5538
+ {
5539
+ style: { width: SELECT_W },
5540
+ onClick: (e) => e.stopPropagation(),
5541
+ className: [cellBase, hasPinned ? "sticky left-0 z-10 bg-white" : ""].filter(Boolean).join(" "),
5542
+ children: /* @__PURE__ */ jsx(
5543
+ "input",
5544
+ {
5545
+ type: "checkbox",
5546
+ "aria-label": strings.table.selectRow,
5547
+ checked: selectedSet.has(key),
5548
+ onChange: () => toggleRow(key),
5549
+ className: "h-4 w-4 rounded border-gray-300 text-blue-600"
5550
+ }
5551
+ )
5552
+ }
5553
+ );
5554
+ })(),
5555
+ leaves.map((col, ci) => {
5556
+ const pinned = col.fixed === "left";
5557
+ return /* @__PURE__ */ jsx(
5558
+ "td",
5559
+ {
5560
+ style: pinned ? { left: (offsets[ci] ?? 0) + selOffset } : void 0,
5561
+ className: [
5562
+ cellBase,
5563
+ ALIGN2[col.align ?? (col.numeric ? "right" : "left")],
5564
+ col.numeric ? "font-mono" : "",
5565
+ "text-gray-900",
5566
+ col.ellipsis ? "max-w-0 truncate" : "",
5567
+ // A pinned cell needs its own background or the
5568
+ // scrolling columns show through it.
5569
+ pinned ? "sticky z-10 bg-white" : ""
5570
+ ].filter(Boolean).join(" "),
5571
+ children: col.render ? col.render(row, i) : col.dataIndex ? row[col.dataIndex] : null
5572
+ },
5573
+ col.key
5574
+ );
5575
+ })
5576
+ ]
5454
5577
  },
5455
5578
  keyOf(row, i)
5456
5579
  );
5457
5580
  }),
5458
- bottomPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: leaves.length, style: { height: bottomPad, padding: 0, border: 0 } }) })
5581
+ bottomPad > 0 && /* @__PURE__ */ jsx("tr", { "aria-hidden": "true", children: /* @__PURE__ */ jsx("td", { colSpan: colCount, style: { height: bottomPad, padding: 0, border: 0 } }) })
5459
5582
  ] }) })
5460
5583
  ] }),
5461
5584
  footer
@@ -6421,6 +6544,6 @@ var ALT_SHIFT_D = isMac ? "\u2325\u21E7D" : "Alt+Shift+D";
6421
6544
  var ALT_SHIFT_E = isMac ? "\u2325\u21E7E" : "Alt+Shift+E";
6422
6545
  var ALT_SHIFT_N = isMac ? "\u2325\u21E7N" : "Alt+Shift+N";
6423
6546
 
6424
- export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, Button_default, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, CMD_SHIFT_Z, CMD_Z, Calendar, Card, ChatTemplate, Checkbox_default, CheckoutTemplate, ColoredBadge, ContainerFillChart, CountBadge, DashboardTemplate, DataTable, DataTablePage, DatePicker_default, DateRangePicker, DateTimePicker_default, DescriptionList, Divider, DonutChart, Drawer, DropdownMenu, ENTER, EmailTemplate, EmptyState, ErrorBoundary, ErrorPage, FilePicker, FormField, FormLayoutPage, GROUP_COLORS, GalleryTemplate, GlobalSearch, Grid, HelpCenter, INPUT_BASE, INPUT_SIZES, IconButton_default, Inline, InputNumber_default, Input_default, Kanban, Label, LineChart, ListFooter, ListLoadError, LoadingSpinner, MAX_FRACTION_DIGITS, MOD, Markdown, MediaUploadField, MediaUploadGrid, MetricBar, MilestoneTimeline, NativeSelect, NumericKeypad, PageHeader, Pagination, Paragraph, Radio_default, Result, SHIFT, SearchableSelect, Segmented, Select_default, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, Skeleton, Sparkline, Stack, StatCard, Statistic, StatusBadge, StatusBadgeProvider, Stepper, Switch_default, Tabs, TagInput, Text, Textarea_default, TileButton_default, TimePicker_default, Title, Tooltip, TopNav, appendKey, applyThemePrefs, backspace, firstEnabledIndex, formatDate, fromKey, inputClasses, isMac, isSeverityTone, lastEnabledIndex, matchTypeahead, mediaFileName, nextEnabledIndex, resolveTheme, severityOf, tabButtonId, tabPanelId, toISODate, toKey, useClickOutside, useTheme };
6425
- //# sourceMappingURL=chunk-B3IYV7JN.js.map
6426
- //# sourceMappingURL=chunk-B3IYV7JN.js.map
6547
+ export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, Button_default, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, CMD_SHIFT_Z, CMD_Z, Calendar, Card, ChatTemplate, Checkbox_default, CheckoutTemplate, ColoredBadge, ContainerFillChart, CountBadge, DashboardTemplate, DataTable, DataTablePage, DatePicker_default, DateRangePicker, DateTimePicker_default, DescriptionList, Divider, DonutChart, Drawer, DropdownMenu, ENTER, EmailTemplate, EmptyState, ErrorBoundary, ErrorPage, FilePicker, FormErrorSummary, FormField, FormLayoutPage, GROUP_COLORS, GalleryTemplate, GlobalSearch, Grid, HelpCenter, INPUT_BASE, INPUT_SIZES, IconButton_default, Inline, InputNumber_default, Input_default, Kanban, Label, LineChart, ListFooter, ListLoadError, LoadingSpinner, MAX_FRACTION_DIGITS, MOD, Markdown, MediaUploadField, MediaUploadGrid, MetricBar, MilestoneTimeline, NativeSelect, NumericKeypad, PageHeader, Pagination, Paragraph, Radio_default, Result, SHIFT, SearchableSelect, Segmented, Select_default, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, Skeleton, Sparkline, Stack, StatCard, Statistic, StatusBadge, StatusBadgeProvider, Stepper, Switch_default, Tabs, TagInput, Text, Textarea_default, TileButton_default, TimePicker_default, Title, Tooltip, TopNav, appendKey, applyThemePrefs, backspace, firstEnabledIndex, formatDate, fromKey, inputClasses, isMac, isSeverityTone, lastEnabledIndex, matchTypeahead, mediaFileName, nextEnabledIndex, resolveTheme, severityOf, tabButtonId, tabPanelId, toISODate, toKey, useClickOutside, useTheme };
6548
+ //# sourceMappingURL=chunk-S6K37RLY.js.map
6549
+ //# sourceMappingURL=chunk-S6K37RLY.js.map