@xenide-io/the-old-ui-theme 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/README.md +9 -10
  2. package/dist/{Chip-Cq3AiAji.d.mts → Chip-BzuNgJIa.d.mts} +81 -23
  3. package/dist/{Chip-Cq3AiAji.d.ts → Chip-BzuNgJIa.d.ts} +81 -23
  4. package/dist/{ai-message-blocknote-WABTHFY7.mjs → ai-message-blocknote-D4Z6DUCJ.mjs} +9 -3
  5. package/dist/{chunk-YB4TBWHV.mjs → chunk-2EO5VCXP.mjs} +688 -388
  6. package/dist/chunk-APKRZQRO.mjs +251 -0
  7. package/dist/chunk-BS7BZI5W.mjs +19 -0
  8. package/dist/chunk-IULORI3A.mjs +8 -0
  9. package/dist/index.d.mts +3 -3
  10. package/dist/index.d.ts +3 -3
  11. package/dist/index.js +997 -576
  12. package/dist/index.mjs +7 -1
  13. package/dist/suite.d.mts +136 -57
  14. package/dist/suite.d.ts +136 -57
  15. package/dist/suite.js +3115 -882
  16. package/dist/suite.mjs +2566 -661
  17. package/dist/theme-boot-P-oqKVZF.d.mts +74 -0
  18. package/dist/theme-boot-P-oqKVZF.d.ts +74 -0
  19. package/dist/theme-boot.d.mts +2 -0
  20. package/dist/theme-boot.d.ts +2 -0
  21. package/dist/theme-boot.js +44 -0
  22. package/dist/theme-boot.mjs +8 -0
  23. package/dist/ui.d.mts +5 -29
  24. package/dist/ui.d.ts +5 -29
  25. package/dist/ui.js +647 -352
  26. package/dist/ui.mjs +1 -1
  27. package/docs/README.md +34 -0
  28. package/docs/ai-quick-reference.md +56 -0
  29. package/docs/component-library-improvement-plan.md +751 -0
  30. package/docs/component-reference.md +81 -0
  31. package/docs/components.md +48 -0
  32. package/docs/demos.md +19 -0
  33. package/docs/installation.md +117 -0
  34. package/docs/suite-audit.md +34 -0
  35. package/docs/theme-token-reference.md +67 -0
  36. package/docs/themes.md +164 -0
  37. package/package.json +22 -21
  38. package/public/fonts/OpenRunde-Bold.woff2 +0 -0
  39. package/public/fonts/OpenRunde-Medium.woff2 +0 -0
  40. package/public/fonts/OpenRunde-Regular.woff2 +0 -0
  41. package/public/fonts/OpenRunde-Semibold.woff2 +0 -0
  42. package/scripts/package-smoke.mjs +43 -0
  43. package/src/app/globals.css +2 -1
  44. package/src/components/ui/Accordion.tsx +20 -6
  45. package/src/components/ui/Avatar.tsx +5 -3
  46. package/src/components/ui/Calendar.tsx +187 -63
  47. package/src/components/ui/Card.test.tsx +38 -0
  48. package/src/components/ui/Card.tsx +77 -14
  49. package/src/components/ui/CollapsibleSection.tsx +12 -4
  50. package/src/components/ui/CommandPalette.test.tsx +91 -4
  51. package/src/components/ui/CommandPalette.tsx +138 -128
  52. package/src/components/ui/EmptyState.tsx +2 -2
  53. package/src/components/ui/FormField.tsx +1 -1
  54. package/src/components/ui/Input.tsx +42 -18
  55. package/src/components/ui/Kbd.tsx +18 -3
  56. package/src/components/ui/Modal.tsx +3 -1
  57. package/src/components/ui/Progress.tsx +14 -5
  58. package/src/components/ui/SegmentedControl.tsx +2 -2
  59. package/src/components/ui/SettingsLayout.tsx +1 -1
  60. package/src/components/ui/Stat.tsx +3 -2
  61. package/src/components/ui/Table.tsx +8 -3
  62. package/src/components/ui/Tooltip.test.tsx +70 -1
  63. package/src/components/ui/Tooltip.tsx +53 -29
  64. package/src/components/ui/Typography.tsx +103 -49
  65. package/src/components/ui/avatar-stat.test.tsx +23 -0
  66. package/src/components/ui/calendar.test.tsx +88 -0
  67. package/src/components/ui/disclosure.test.tsx +39 -0
  68. package/src/components/ui/index.ts +44 -6
  69. package/src/components/ui/progress.test.tsx +15 -0
  70. package/src/components/ui/typography.test.tsx +26 -1
  71. package/src/styles/suite-skin.css +8 -2
  72. package/src/styles/themes.css +184 -68
  73. package/src/suite/components/ai-message-blocknote.tsx +13 -2
  74. package/src/suite/components/ai-panel.tsx +41 -10
  75. package/src/suite/components/app-switcher.test.tsx +21 -6
  76. package/src/suite/components/app-switcher.tsx +7 -11
  77. package/src/suite/components/suite-app-layout.tsx +12 -3
  78. package/src/suite/components/suite-bottom-nav.tsx +0 -1
  79. package/src/suite/components/suite-clients-projects-directory.test.tsx +71 -0
  80. package/src/suite/components/suite-clients-projects-directory.tsx +943 -0
  81. package/src/suite/components/suite-integration-picker.test.tsx +224 -0
  82. package/src/suite/components/suite-integration-picker.tsx +889 -18
  83. package/src/suite/components/suite-integration-rules.test.tsx +157 -0
  84. package/src/suite/components/suite-integration-rules.tsx +471 -0
  85. package/src/suite/components/suite-mobile-drawer.test.tsx +18 -2
  86. package/src/suite/components/suite-mobile-drawer.tsx +65 -98
  87. package/src/suite/components/suite-notification-bell.tsx +29 -4
  88. package/src/suite/components/suite-sidebar.tsx +25 -25
  89. package/src/suite/components/suite-skeleton.tsx +2 -2
  90. package/src/suite/components/suite-user-menu.tsx +9 -8
  91. package/src/suite/components/theme-provider.test.tsx +87 -3
  92. package/src/suite/components/theme-provider.tsx +144 -23
  93. package/src/suite/components/today-ui.tsx +79 -68
  94. package/src/suite/components/workspace-switcher.test.tsx +56 -0
  95. package/src/suite/components/workspace-switcher.tsx +3 -3
  96. package/src/suite/icons/app-accents.ts +12 -12
  97. package/src/suite/icons/glyphs.ts +6 -12
  98. package/src/suite/index.ts +22 -0
  99. package/src/suite/lib/apps.test.ts +9 -1
  100. package/src/suite/lib/apps.ts +14 -8
  101. package/src/suite/lib/cookies.ts +53 -0
  102. package/src/suite/lib/theme-boot.ts +32 -0
  103. package/src/suite/lib/theme-cookie.ts +7 -0
  104. package/src/suite/lib/use-sidebar-width.ts +5 -51
  105. package/dist/chunk-NOI42JNZ.mjs +0 -151
  106. package/src/suite/lib/use-lock-mobile-page-zoom.test.tsx +0 -65
  107. package/src/suite/lib/use-lock-mobile-page-zoom.ts +0 -51
@@ -773,8 +773,10 @@ var Badge = forwardRef6(function Badge2(_a, ref) {
773
773
  Badge.displayName = "Badge";
774
774
 
775
775
  // src/components/ui/Card.tsx
776
- import { forwardRef as forwardRef7 } from "react";
777
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
776
+ import {
777
+ forwardRef as forwardRef7
778
+ } from "react";
779
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
778
780
  var variantMap2 = {
779
781
  default: "",
780
782
  outlined: "border-2 border-ph-border",
@@ -793,7 +795,12 @@ var Card = forwardRef7(function Card2(_a, ref) {
793
795
  className,
794
796
  bodyClassName,
795
797
  interactive = false,
796
- titleAs: Title2 = "h3"
798
+ href,
799
+ onClick,
800
+ target,
801
+ rel,
802
+ type,
803
+ titleAs: Title3 = "h3"
797
804
  } = _b, props = __objRest(_b, [
798
805
  "children",
799
806
  "title",
@@ -805,31 +812,60 @@ var Card = forwardRef7(function Card2(_a, ref) {
805
812
  "className",
806
813
  "bodyClassName",
807
814
  "interactive",
815
+ "href",
816
+ "onClick",
817
+ "target",
818
+ "rel",
819
+ "type",
808
820
  "titleAs"
809
821
  ]);
810
- return /* @__PURE__ */ jsxs5(
811
- "div",
812
- __spreadProps(__spreadValues({
813
- ref,
814
- className: cn(
815
- "ph-card",
816
- variantMap2[variant],
817
- interactive && "ph-card-interactive",
818
- className
819
- )
820
- }, props), {
821
- children: [
822
- media && /* @__PURE__ */ jsx8("div", { className: "ph-card-media", children: media }),
823
- /* @__PURE__ */ jsxs5("div", { className: cn("ph-card-body", bodyClassName), children: [
824
- title && /* @__PURE__ */ jsx8(Title2, { className: "ph-card-title", children: title }),
825
- description && /* @__PURE__ */ jsx8("p", { className: "text-sm text-ph-subtle", children: description }),
826
- children,
827
- actions && /* @__PURE__ */ jsx8("div", { className: "ph-card-actions", children: actions })
828
- ] }),
829
- footer && /* @__PURE__ */ jsx8("div", { className: "border-t border-ph-border px-6 py-4 text-xs text-ph-subtle", children: footer })
830
- ]
831
- })
822
+ const isLink = href !== void 0;
823
+ const isButton = onClick !== void 0 && !isLink;
824
+ const cardClassName = cn(
825
+ "ph-card",
826
+ variantMap2[variant],
827
+ (interactive || isLink || isButton) && "ph-card-interactive",
828
+ className
832
829
  );
830
+ const cardContent = /* @__PURE__ */ jsxs5(Fragment3, { children: [
831
+ media && /* @__PURE__ */ jsx8("div", { className: "ph-card-media", children: media }),
832
+ /* @__PURE__ */ jsxs5("div", { className: cn("ph-card-body", bodyClassName), children: [
833
+ title && /* @__PURE__ */ jsx8(Title3, { className: "ph-card-title", children: title }),
834
+ description && /* @__PURE__ */ jsx8("p", { className: "text-sm text-ph-subtle", children: description }),
835
+ children,
836
+ actions && /* @__PURE__ */ jsx8("div", { className: "ph-card-actions", children: actions })
837
+ ] }),
838
+ footer && /* @__PURE__ */ jsx8("div", { className: "border-t border-ph-border px-6 py-4 text-xs text-ph-subtle", children: footer })
839
+ ] });
840
+ if (isLink) {
841
+ return /* @__PURE__ */ jsx8(
842
+ "a",
843
+ __spreadProps(__spreadValues({
844
+ ref,
845
+ className: cardClassName,
846
+ href,
847
+ target,
848
+ rel,
849
+ onClick
850
+ }, props), {
851
+ children: cardContent
852
+ })
853
+ );
854
+ }
855
+ if (isButton) {
856
+ return /* @__PURE__ */ jsx8(
857
+ "button",
858
+ __spreadProps(__spreadValues({
859
+ ref,
860
+ type: type != null ? type : "button",
861
+ className: cardClassName,
862
+ onClick
863
+ }, props), {
864
+ children: cardContent
865
+ })
866
+ );
867
+ }
868
+ return /* @__PURE__ */ jsx8("div", __spreadProps(__spreadValues({ ref, className: cardClassName }, props), { children: cardContent }));
833
869
  });
834
870
  Card.displayName = "Card";
835
871
 
@@ -893,18 +929,45 @@ function Kbd(_a) {
893
929
  "aria-label"
894
930
  ]);
895
931
  if (variant === "token") {
896
- return /* @__PURE__ */ jsx9("code", __spreadProps(__spreadValues({ className: cn("ph-code-token ph-kbd", className), "aria-label": ariaLabel }, props), { children }));
932
+ return /* @__PURE__ */ jsx9(
933
+ "code",
934
+ __spreadProps(__spreadValues({
935
+ className: cn("ph-code-token ph-kbd", className),
936
+ role: ariaLabel ? "img" : void 0,
937
+ "aria-label": ariaLabel
938
+ }, props), {
939
+ children
940
+ })
941
+ );
897
942
  }
898
943
  const sourceKeys = (keys == null ? void 0 : keys.length) ? keys : children != null ? [children] : [];
899
944
  const displayKeys = sourceKeys.map((key) => formatKey(key, platform));
900
945
  const accessibleLabel = ariaLabel != null ? ariaLabel : getShortcutLabel(displayKeys);
901
946
  if (variant === "key") {
902
- return /* @__PURE__ */ jsx9("kbd", __spreadProps(__spreadValues({ className: cn("ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys[0] }));
947
+ return /* @__PURE__ */ jsx9(
948
+ "kbd",
949
+ __spreadProps(__spreadValues({
950
+ className: cn("ph-keycap", className),
951
+ role: accessibleLabel ? "img" : void 0,
952
+ "aria-label": accessibleLabel
953
+ }, props), {
954
+ children: displayKeys[0]
955
+ })
956
+ );
903
957
  }
904
- return /* @__PURE__ */ jsx9("kbd", __spreadProps(__spreadValues({ className: cn("ph-shortcut-group ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys.map((key, index) => /* @__PURE__ */ jsxs6("span", { className: "contents", children: [
905
- index > 0 && separator != null ? /* @__PURE__ */ jsx9("span", { className: "ph-shortcut-separator", "aria-hidden": "true", children: separator }) : null,
906
- /* @__PURE__ */ jsx9("span", { className: "ph-shortcut-key", "aria-hidden": accessibleLabel ? true : void 0, children: key })
907
- ] }, index)) }));
958
+ return /* @__PURE__ */ jsx9(
959
+ "kbd",
960
+ __spreadProps(__spreadValues({
961
+ className: cn("ph-shortcut-group ph-keycap", className),
962
+ role: accessibleLabel ? "img" : void 0,
963
+ "aria-label": accessibleLabel
964
+ }, props), {
965
+ children: displayKeys.map((key, index) => /* @__PURE__ */ jsxs6("span", { className: "contents", children: [
966
+ index > 0 && separator != null ? /* @__PURE__ */ jsx9("span", { className: "ph-shortcut-separator", "aria-hidden": "true", children: separator }) : null,
967
+ /* @__PURE__ */ jsx9("span", { className: "ph-shortcut-key", "aria-hidden": accessibleLabel ? true : void 0, children: key })
968
+ ] }, index))
969
+ })
970
+ );
908
971
  }
909
972
  function formatKey(key, platform) {
910
973
  var _a;
@@ -1038,7 +1101,7 @@ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1038
1101
  function SettingsNav(_a) {
1039
1102
  var _b = _a, { groups, className } = _b, props = __objRest(_b, ["groups", "className"]);
1040
1103
  return /* @__PURE__ */ jsx12("div", __spreadProps(__spreadValues({ className: cn("ph-settings-nav", className) }, props), { children: groups.map((group, index) => /* @__PURE__ */ jsxs9("div", { className: "ph-settings-nav__group", children: [
1041
- /* @__PURE__ */ jsx12("h3", { children: group.label }),
1104
+ /* @__PURE__ */ jsx12("p", { className: "ph-settings-nav__heading", children: group.label }),
1042
1105
  /* @__PURE__ */ jsx12("div", { className: "ph-settings-nav__items", children: group.items.map((item) => /* @__PURE__ */ jsxs9(
1043
1106
  "a",
1044
1107
  {
@@ -1369,7 +1432,8 @@ function DropdownRadioItem(_a) {
1369
1432
  }
1370
1433
 
1371
1434
  // src/components/ui/Input.tsx
1372
- import { forwardRef as forwardRef8, useId as useId3 } from "react";
1435
+ import { forwardRef as forwardRef8, useId as useId3, useState } from "react";
1436
+ import { Eye, EyeClosed } from "iconoir-react";
1373
1437
 
1374
1438
  // src/components/ui/FormField.tsx
1375
1439
  import { useId as useId2 } from "react";
@@ -1402,7 +1466,7 @@ function FormField(_a) {
1402
1466
  const errorId = error ? `${id}-error` : void 0;
1403
1467
  const controlProps = {
1404
1468
  id,
1405
- "aria-describedby": descriptionId,
1469
+ "aria-describedby": errorId != null ? errorId : descriptionId,
1406
1470
  "aria-errormessage": errorId,
1407
1471
  "aria-invalid": error ? true : void 0
1408
1472
  };
@@ -1444,6 +1508,7 @@ var Input = forwardRef8(function Input2(_a, ref) {
1444
1508
  helperText,
1445
1509
  size = "md",
1446
1510
  variant = "default",
1511
+ type = "text",
1447
1512
  className,
1448
1513
  wrapperClassName,
1449
1514
  disabled,
@@ -1457,6 +1522,7 @@ var Input = forwardRef8(function Input2(_a, ref) {
1457
1522
  "helperText",
1458
1523
  "size",
1459
1524
  "variant",
1525
+ "type",
1460
1526
  "className",
1461
1527
  "wrapperClassName",
1462
1528
  "disabled",
@@ -1466,6 +1532,8 @@ var Input = forwardRef8(function Input2(_a, ref) {
1466
1532
  const autoId = useId3();
1467
1533
  const id = idProp != null ? idProp : autoId;
1468
1534
  const hasError = Boolean(error);
1535
+ const isPassword = type === "password";
1536
+ const [revealed, setRevealed] = useState(false);
1469
1537
  return /* @__PURE__ */ jsx15(
1470
1538
  FormField,
1471
1539
  {
@@ -1477,23 +1545,39 @@ var Input = forwardRef8(function Input2(_a, ref) {
1477
1545
  required,
1478
1546
  disabled,
1479
1547
  className: wrapperClassName,
1480
- children: (fieldProps) => /* @__PURE__ */ jsx15(
1481
- "input",
1482
- __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
1483
- ref,
1484
- disabled,
1485
- required,
1486
- "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
1487
- className: cn(
1488
- "ph-input w-full",
1489
- sizeMap2[size],
1490
- variant === "ghost" && "ph-input-ghost",
1491
- hasError && "ph-input-error",
1492
- disabled && "cursor-not-allowed opacity-60",
1493
- className
1494
- )
1495
- }), props)
1496
- )
1548
+ children: (fieldProps) => /* @__PURE__ */ jsxs12("div", { className: "relative", children: [
1549
+ /* @__PURE__ */ jsx15(
1550
+ "input",
1551
+ __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
1552
+ ref,
1553
+ type: isPassword && revealed ? "text" : type,
1554
+ disabled,
1555
+ required,
1556
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
1557
+ className: cn(
1558
+ "ph-input w-full",
1559
+ isPassword && "pr-10",
1560
+ sizeMap2[size],
1561
+ variant === "ghost" && "ph-input-ghost",
1562
+ hasError && "ph-input-error",
1563
+ disabled && "cursor-not-allowed opacity-60",
1564
+ className
1565
+ )
1566
+ }), props)
1567
+ ),
1568
+ isPassword ? /* @__PURE__ */ jsx15(
1569
+ "button",
1570
+ {
1571
+ type: "button",
1572
+ onClick: () => setRevealed((current) => !current),
1573
+ "aria-label": revealed ? "Hide password" : "Show password",
1574
+ "aria-pressed": revealed,
1575
+ disabled,
1576
+ className: "absolute inset-y-0 right-0 flex w-10 items-center justify-center rounded-r-[var(--ph-radius-control)] text-ph-mutedtext transition-colors hover:text-ph-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ph-focus disabled:opacity-40",
1577
+ children: revealed ? /* @__PURE__ */ jsx15(EyeClosed, { className: "h-4 w-4", "aria-hidden": true }) : /* @__PURE__ */ jsx15(Eye, { className: "h-4 w-4", "aria-hidden": true })
1578
+ }
1579
+ ) : null
1580
+ ] })
1497
1581
  }
1498
1582
  );
1499
1583
  });
@@ -1631,7 +1715,7 @@ var Checkbox = forwardRef8(function Checkbox2(_a, ref) {
1631
1715
  type: "checkbox",
1632
1716
  disabled,
1633
1717
  "aria-invalid": hasError || void 0,
1634
- "aria-describedby": joinIds(ariaDescribedBy, descriptionId),
1718
+ "aria-describedby": joinIds(ariaDescribedBy, descriptionId, errorId),
1635
1719
  "aria-errormessage": errorId,
1636
1720
  className: cn(
1637
1721
  "ph-checkbox",
@@ -1774,7 +1858,7 @@ FileUpload.displayName = "FileUpload";
1774
1858
  // src/components/ui/Modal.tsx
1775
1859
  import * as Dialog from "@radix-ui/react-dialog";
1776
1860
  import { useRef } from "react";
1777
- import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1861
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1778
1862
  var sizeMap3 = {
1779
1863
  sm: "max-w-sm",
1780
1864
  md: "max-w-lg",
@@ -1791,6 +1875,7 @@ function Modal({
1791
1875
  footer,
1792
1876
  size = "md",
1793
1877
  className,
1878
+ bodyClassName,
1794
1879
  customLayout = false,
1795
1880
  showCloseButton = true,
1796
1881
  closeOnOutsideClick = true,
@@ -1843,10 +1928,10 @@ function Modal({
1843
1928
  onPointerDownOutside: (event) => {
1844
1929
  if (!canDismiss || !closeOnOutsideClick) event.preventDefault();
1845
1930
  },
1846
- children: customLayout ? /* @__PURE__ */ jsxs13(Fragment3, { children: [
1931
+ children: customLayout ? /* @__PURE__ */ jsxs13(Fragment4, { children: [
1847
1932
  /* @__PURE__ */ jsx16(Dialog.Title, { className: "sr-only", children: ariaLabel != null ? ariaLabel : "Dialog" }),
1848
1933
  children
1849
- ] }) : /* @__PURE__ */ jsxs13(Fragment3, { children: [
1934
+ ] }) : /* @__PURE__ */ jsxs13(Fragment4, { children: [
1850
1935
  title ? null : /* @__PURE__ */ jsx16(Dialog.Title, { className: "sr-only", children: ariaLabel != null ? ariaLabel : "Dialog" }),
1851
1936
  title || description || showCloseButton && canDismiss ? /* @__PURE__ */ jsxs13("header", { className: "ph-modal-header", children: [
1852
1937
  /* @__PURE__ */ jsxs13("div", { className: "min-w-0", children: [
@@ -1863,7 +1948,7 @@ function Modal({
1863
1948
  }
1864
1949
  ) }) : null
1865
1950
  ] }) : null,
1866
- /* @__PURE__ */ jsx16("div", { className: "ph-modal-body", children }),
1951
+ /* @__PURE__ */ jsx16("div", { className: cn("ph-modal-body", bodyClassName), children }),
1867
1952
  footer ? /* @__PURE__ */ jsx16("div", { className: "ph-modal-footer", children: footer }) : null
1868
1953
  ] })
1869
1954
  })
@@ -1991,14 +2076,25 @@ function Table({
1991
2076
  compact = false,
1992
2077
  ribbon = false,
1993
2078
  getRowStyle,
2079
+ getRowKey,
1994
2080
  className,
1995
2081
  caption
1996
2082
  }) {
1997
- return /* @__PURE__ */ jsx19("div", { className: cn("ph-table-wrap", compact && "ph-table-compact", className), children: /* @__PURE__ */ jsxs16("table", { className: cn("ph-table", zebra && "ph-table-zebra", ribbon && "ph-table--ribbon"), children: [
1998
- caption && /* @__PURE__ */ jsx19("caption", { className: "sr-only", children: caption }),
1999
- /* @__PURE__ */ jsx19("thead", { children: /* @__PURE__ */ jsx19("tr", { children: columns.map((col) => /* @__PURE__ */ jsx19("th", { className: col.className, children: col.header }, col.key)) }) }),
2000
- /* @__PURE__ */ jsx19("tbody", { children: data.map((row, i) => /* @__PURE__ */ jsx19("tr", { style: getRowStyle == null ? void 0 : getRowStyle(row), children: columns.map((col) => /* @__PURE__ */ jsx19("td", { className: col.className, children: col.cell(row) }, col.key)) }, i)) })
2001
- ] }) });
2083
+ return /* @__PURE__ */ jsx19(
2084
+ "div",
2085
+ {
2086
+ className: cn("ph-table-wrap", compact && "ph-table-compact", className),
2087
+ tabIndex: 0,
2088
+ children: /* @__PURE__ */ jsxs16("table", { className: cn("ph-table", zebra && "ph-table-zebra", ribbon && "ph-table--ribbon"), children: [
2089
+ caption && /* @__PURE__ */ jsx19("caption", { className: "sr-only", children: caption }),
2090
+ /* @__PURE__ */ jsx19("thead", { children: /* @__PURE__ */ jsx19("tr", { children: columns.map((col) => /* @__PURE__ */ jsx19("th", { className: col.className, children: col.header }, col.key)) }) }),
2091
+ /* @__PURE__ */ jsx19("tbody", { children: data.map((row, i) => {
2092
+ var _a;
2093
+ return /* @__PURE__ */ jsx19("tr", { style: getRowStyle == null ? void 0 : getRowStyle(row), children: columns.map((col) => /* @__PURE__ */ jsx19("td", { className: col.className, children: col.cell(row) }, col.key)) }, (_a = getRowKey == null ? void 0 : getRowKey(row, i)) != null ? _a : i);
2094
+ }) })
2095
+ ] })
2096
+ }
2097
+ );
2002
2098
  }
2003
2099
 
2004
2100
  // src/components/ui/Stat.tsx
@@ -2008,14 +2104,14 @@ var toneMap = {
2008
2104
  brand: "text-ph-brand",
2009
2105
  blue: "text-ph-blue",
2010
2106
  purple: "text-ph-purple",
2011
- warning: "text-amber-900"
2107
+ warning: "text-ph-warning"
2012
2108
  };
2013
2109
  var statMap = {
2014
2110
  default: "",
2015
2111
  brand: "",
2016
2112
  blue: "",
2017
2113
  purple: "",
2018
- warning: "border-amber-200 bg-amber-50/70"
2114
+ warning: "border-[color:color-mix(in_srgb,var(--ph-warning)_30%,var(--ph-border))] bg-[color:color-mix(in_srgb,var(--ph-warning)_10%,var(--ph-surface))]"
2019
2115
  };
2020
2116
  function Stat(_a) {
2021
2117
  var _b = _a, { icon, label, value, footer, tone = "default", className } = _b, props = __objRest(_b, ["icon", "label", "value", "footer", "tone", "className"]);
@@ -2035,17 +2131,17 @@ var DEFAULT_THEME_ID = "hedgehog-light";
2035
2131
  var THEMES = [
2036
2132
  {
2037
2133
  id: "hedgehog-light",
2038
- name: "HedgeHog Light",
2134
+ name: "Hedgehog Light",
2039
2135
  description: "Default Quill warm greys and orange Lemon chrome.",
2040
2136
  colorScheme: "light",
2041
- group: "HedgeHog"
2137
+ group: "Hedgehog"
2042
2138
  },
2043
2139
  {
2044
2140
  id: "hedgehog-dark",
2045
- name: "HedgeHog Dark",
2141
+ name: "Hedgehog Dark",
2046
2142
  description: "Dark app shell with HedgeHog orange accents.",
2047
2143
  colorScheme: "dark",
2048
- group: "HedgeHog"
2144
+ group: "Hedgehog"
2049
2145
  },
2050
2146
  {
2051
2147
  id: "note",
@@ -2130,6 +2226,20 @@ var THEMES = [
2130
2226
  description: "Deep plum command deck with hot pink, lime, cyan, and sunset signals.",
2131
2227
  colorScheme: "dark",
2132
2228
  group: "Malibu"
2229
+ },
2230
+ {
2231
+ id: "microsoft-light",
2232
+ name: "Microsoft Light",
2233
+ description: "Office Fluent light neutrals on white with the signature brand blue.",
2234
+ colorScheme: "light",
2235
+ group: "Microsoft"
2236
+ },
2237
+ {
2238
+ id: "microsoft-dark",
2239
+ name: "Microsoft Dark",
2240
+ description: "Office Fluent dark chrome with a bright brand-blue accent.",
2241
+ colorScheme: "dark",
2242
+ group: "Microsoft"
2133
2243
  }
2134
2244
  ];
2135
2245
  var THEME_GROUPS = Array.from(
@@ -2173,10 +2283,10 @@ function ThemeDomSync() {
2173
2283
  }
2174
2284
 
2175
2285
  // src/components/ui/ThemeSwitcher.tsx
2176
- import { useEffect, useState } from "react";
2286
+ import { useEffect, useState as useState2 } from "react";
2177
2287
  import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
2178
2288
  function ThemeSwitcher({ className }) {
2179
- const [themeId, setThemeId] = useState(DEFAULT_THEME_ID);
2289
+ const [themeId, setThemeId] = useState2(DEFAULT_THEME_ID);
2180
2290
  useEffect(() => {
2181
2291
  const id = readStoredTheme();
2182
2292
  persistTheme(id);
@@ -2202,7 +2312,7 @@ function ThemeSwitcher({ className }) {
2202
2312
  }
2203
2313
 
2204
2314
  // src/components/ui/Accordion.tsx
2205
- import { useState as useState2 } from "react";
2315
+ import { useId as useId5, useState as useState3 } from "react";
2206
2316
  import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
2207
2317
  function Accordion({
2208
2318
  items,
@@ -2210,7 +2320,8 @@ function Accordion({
2210
2320
  defaultOpen = [],
2211
2321
  className
2212
2322
  }) {
2213
- const [openItems, setOpenItems] = useState2(new Set(defaultOpen));
2323
+ const [openItems, setOpenItems] = useState3(new Set(defaultOpen));
2324
+ const idPrefix = useId5();
2214
2325
  const toggleItem = (id) => {
2215
2326
  setOpenItems((prev) => {
2216
2327
  const next = new Set(prev);
@@ -2225,41 +2336,58 @@ function Accordion({
2225
2336
  return next;
2226
2337
  });
2227
2338
  };
2228
- return /* @__PURE__ */ jsx22("div", { className: cn("divide-y divide-ph-border rounded-xl border border-ph-border bg-ph-surface", className), children: items.map((item) => {
2229
- const isOpen = openItems.has(item.id);
2230
- return /* @__PURE__ */ jsxs19("div", { className: "first:rounded-t-xl last:rounded-b-xl", children: [
2231
- /* @__PURE__ */ jsxs19(
2232
- "button",
2233
- {
2234
- type: "button",
2235
- onClick: () => toggleItem(item.id),
2236
- className: "flex w-full items-center justify-between px-5 py-4 text-left transition hover:bg-ph-muted",
2237
- children: [
2238
- /* @__PURE__ */ jsx22("span", { className: "font-semibold text-ph-ink", children: item.title }),
2239
- /* @__PURE__ */ jsx22(
2240
- IconChevronDown,
2241
- {
2242
- className: cn(
2243
- "h-5 w-5 text-ph-mutedtext transition-transform duration-200",
2244
- isOpen && "rotate-180"
2245
- )
2246
- }
2247
- )
2248
- ]
2249
- }
2339
+ return /* @__PURE__ */ jsx22(
2340
+ "div",
2341
+ {
2342
+ className: cn(
2343
+ "divide-y divide-ph-border rounded-xl border border-ph-border bg-ph-surface",
2344
+ className
2250
2345
  ),
2251
- /* @__PURE__ */ jsx22(
2252
- "div",
2253
- {
2254
- className: cn(
2255
- "grid transition-all duration-200",
2256
- isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
2346
+ children: items.map((item) => {
2347
+ const isOpen = openItems.has(item.id);
2348
+ const contentId = `accordion-${idPrefix}-${item.id}-content`;
2349
+ return /* @__PURE__ */ jsxs19("div", { className: "first:rounded-t-xl last:rounded-b-xl", children: [
2350
+ /* @__PURE__ */ jsxs19(
2351
+ "button",
2352
+ {
2353
+ type: "button",
2354
+ onClick: () => toggleItem(item.id),
2355
+ "aria-expanded": isOpen,
2356
+ "aria-controls": contentId,
2357
+ className: "flex w-full items-center justify-between px-5 py-4 text-left transition hover:bg-ph-muted",
2358
+ children: [
2359
+ /* @__PURE__ */ jsx22("span", { className: "font-semibold text-ph-ink", children: item.title }),
2360
+ /* @__PURE__ */ jsx22(
2361
+ IconChevronDown,
2362
+ {
2363
+ className: cn(
2364
+ "h-5 w-5 text-ph-mutedtext transition-transform duration-200",
2365
+ isOpen && "rotate-180"
2366
+ )
2367
+ }
2368
+ )
2369
+ ]
2370
+ }
2257
2371
  ),
2258
- children: /* @__PURE__ */ jsx22("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx22("div", { className: "px-5 pb-4 text-ph-subtle", children: item.content }) })
2259
- }
2260
- )
2261
- ] }, item.id);
2262
- }) });
2372
+ /* @__PURE__ */ jsx22(
2373
+ "div",
2374
+ {
2375
+ id: contentId,
2376
+ "aria-hidden": !isOpen,
2377
+ ref: (node) => {
2378
+ if (node) node.toggleAttribute("inert", !isOpen);
2379
+ },
2380
+ className: cn(
2381
+ "grid transition-all duration-200",
2382
+ isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
2383
+ ),
2384
+ children: /* @__PURE__ */ jsx22("div", { className: "overflow-hidden", children: /* @__PURE__ */ jsx22("div", { className: "px-5 pb-4 text-ph-subtle", children: item.content }) })
2385
+ }
2386
+ )
2387
+ ] }, item.id);
2388
+ })
2389
+ }
2390
+ );
2263
2391
  }
2264
2392
 
2265
2393
  // src/components/ui/SegmentedControl.tsx
@@ -2294,7 +2422,8 @@ function SegmentedControl({ options, value, onChange, className }) {
2294
2422
  }
2295
2423
 
2296
2424
  // src/components/ui/CommandPalette.tsx
2297
- import { useState as useState3, useEffect as useEffect2, useRef as useRef2 } from "react";
2425
+ import { useEffect as useEffect2, useId as useId6, useRef as useRef2, useState as useState4 } from "react";
2426
+ import * as Dialog2 from "@radix-ui/react-dialog";
2298
2427
  import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
2299
2428
  function CommandPalette({
2300
2429
  items,
@@ -2307,186 +2436,289 @@ function CommandPalette({
2307
2436
  inputId,
2308
2437
  inputDataTest
2309
2438
  }) {
2310
- const [query, setQuery] = useState3("");
2311
- const [selectedIndex, setSelectedIndex] = useState3(0);
2439
+ const [query, setQuery] = useState4("");
2440
+ const [selectedIndex, setSelectedIndex] = useState4(0);
2312
2441
  const inputRef = useRef2(null);
2313
- const panelRef = useRef2(null);
2314
- const previousFocusRef = useRef2(null);
2442
+ const listboxRef = useRef2(null);
2443
+ const restoreFocusRef = useRef2(null);
2444
+ const generatedId = useId6();
2445
+ const listboxId = `${id != null ? id : `command-palette-${generatedId}`}-listbox`;
2315
2446
  const filtered = items.filter(
2316
2447
  (item) => item.label.toLowerCase().includes(query.toLowerCase())
2317
2448
  );
2449
+ const activeIndex = filtered.length ? Math.min(selectedIndex, filtered.length - 1) : 0;
2450
+ const activeItem = filtered[activeIndex];
2318
2451
  useEffect2(() => {
2319
- var _a;
2320
2452
  if (!isOpen) return;
2321
- previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2322
2453
  setQuery("");
2323
2454
  setSelectedIndex(0);
2324
- (_a = inputRef.current) == null ? void 0 : _a.focus();
2325
- return () => {
2326
- var _a2;
2327
- return (_a2 = previousFocusRef.current) == null ? void 0 : _a2.focus();
2328
- };
2329
2455
  }, [isOpen]);
2330
2456
  useEffect2(() => {
2331
- const handleKeyDown = (e) => {
2332
- var _a, _b;
2333
- if (!isOpen) return;
2334
- switch (e.key) {
2335
- case "ArrowDown":
2336
- if (!filtered.length) break;
2337
- e.preventDefault();
2338
- setSelectedIndex((i) => (i + 1) % filtered.length);
2339
- break;
2340
- case "ArrowUp":
2341
- if (!filtered.length) break;
2342
- e.preventDefault();
2343
- setSelectedIndex((i) => (i - 1 + filtered.length) % filtered.length);
2344
- break;
2345
- case "Enter":
2346
- e.preventDefault();
2347
- (_a = filtered[selectedIndex]) == null ? void 0 : _a.onSelect();
2348
- onClose();
2349
- break;
2350
- case "Escape":
2351
- onClose();
2352
- break;
2353
- case "Tab": {
2354
- const focusable = (_b = panelRef.current) == null ? void 0 : _b.querySelectorAll(
2355
- 'input, button, [href], [tabindex]:not([tabindex="-1"])'
2356
- );
2357
- if (!(focusable == null ? void 0 : focusable.length)) break;
2358
- const first = focusable[0];
2359
- const last = focusable[focusable.length - 1];
2360
- if (e.shiftKey && document.activeElement === first) {
2361
- e.preventDefault();
2362
- last.focus();
2363
- } else if (!e.shiftKey && document.activeElement === last) {
2364
- e.preventDefault();
2365
- first.focus();
2366
- }
2367
- break;
2368
- }
2369
- }
2370
- };
2371
- window.addEventListener("keydown", handleKeyDown);
2372
- return () => window.removeEventListener("keydown", handleKeyDown);
2373
- }, [isOpen, filtered, selectedIndex, onClose]);
2374
- if (!isOpen) return null;
2457
+ setSelectedIndex((current) => Math.min(current, Math.max(filtered.length - 1, 0)));
2458
+ }, [filtered.length]);
2459
+ useEffect2(() => {
2460
+ var _a, _b;
2461
+ if (!isOpen || !activeItem) return;
2462
+ (_b = (_a = listboxRef.current) == null ? void 0 : _a.querySelectorAll('[role="option"]')[activeIndex]) == null ? void 0 : _b.scrollIntoView({ block: "nearest" });
2463
+ }, [activeIndex, activeItem, isOpen]);
2464
+ const handleInputKeyDown = (event) => {
2465
+ switch (event.key) {
2466
+ case "ArrowDown":
2467
+ if (!filtered.length) return;
2468
+ event.preventDefault();
2469
+ setSelectedIndex((current) => (current + 1) % filtered.length);
2470
+ return;
2471
+ case "ArrowUp":
2472
+ if (!filtered.length) return;
2473
+ event.preventDefault();
2474
+ setSelectedIndex(
2475
+ (current) => (current - 1 + filtered.length) % filtered.length
2476
+ );
2477
+ return;
2478
+ case "Enter":
2479
+ if (!activeItem) return;
2480
+ event.preventDefault();
2481
+ activeItem.onSelect();
2482
+ onClose();
2483
+ return;
2484
+ default:
2485
+ return;
2486
+ }
2487
+ };
2375
2488
  return /* @__PURE__ */ jsx24(
2376
- "div",
2489
+ Dialog2.Root,
2377
2490
  {
2378
- id,
2379
- "data-test": dataTest,
2380
- className: "fixed inset-0 z-50 flex items-start justify-center bg-black/40 pt-[20vh] backdrop-blur-sm",
2381
- onMouseDown: (event) => {
2382
- if (event.target === event.currentTarget) onClose();
2491
+ open: isOpen,
2492
+ onOpenChange: (nextOpen) => {
2493
+ if (!nextOpen) onClose();
2383
2494
  },
2384
- children: /* @__PURE__ */ jsxs21(
2385
- "div",
2386
- {
2387
- ref: panelRef,
2388
- role: "dialog",
2389
- "aria-modal": "true",
2390
- "aria-label": "Command palette",
2391
- className: cn(
2392
- "w-full max-w-xl overflow-hidden rounded-xl border border-ph-border bg-ph-surface shadow-ph-md",
2393
- className
2394
- ),
2395
- children: [
2396
- /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
2397
- /* @__PURE__ */ jsx24(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
2398
- /* @__PURE__ */ jsx24(
2399
- "input",
2495
+ children: /* @__PURE__ */ jsxs21(Dialog2.Portal, { children: [
2496
+ /* @__PURE__ */ jsx24(
2497
+ Dialog2.Overlay,
2498
+ {
2499
+ id,
2500
+ "data-test": dataTest,
2501
+ className: "fixed inset-0 z-50 bg-black/40 backdrop-blur-sm"
2502
+ }
2503
+ ),
2504
+ /* @__PURE__ */ jsxs21(
2505
+ Dialog2.Content,
2506
+ {
2507
+ className: cn(
2508
+ "fixed left-1/2 top-[20vh] z-50 w-full max-w-xl -translate-x-1/2 overflow-hidden rounded-xl border border-ph-border bg-ph-surface shadow-ph-md",
2509
+ className
2510
+ ),
2511
+ onOpenAutoFocus: (event) => {
2512
+ var _a;
2513
+ restoreFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2514
+ event.preventDefault();
2515
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
2516
+ },
2517
+ onCloseAutoFocus: (event) => {
2518
+ var _a;
2519
+ event.preventDefault();
2520
+ (_a = restoreFocusRef.current) == null ? void 0 : _a.focus();
2521
+ },
2522
+ children: [
2523
+ /* @__PURE__ */ jsx24(Dialog2.Title, { className: "sr-only", children: "Command palette" }),
2524
+ /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
2525
+ /* @__PURE__ */ jsx24(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
2526
+ /* @__PURE__ */ jsx24(
2527
+ "input",
2528
+ {
2529
+ ref: inputRef,
2530
+ id: inputId,
2531
+ "data-test": inputDataTest,
2532
+ type: "text",
2533
+ role: "combobox",
2534
+ "aria-label": "Search commands",
2535
+ "aria-autocomplete": "list",
2536
+ "aria-controls": listboxId,
2537
+ "aria-expanded": "true",
2538
+ "aria-activedescendant": activeItem ? `command-${activeItem.id}` : void 0,
2539
+ value: query,
2540
+ onChange: (event) => {
2541
+ setQuery(event.target.value);
2542
+ setSelectedIndex(0);
2543
+ },
2544
+ onKeyDown: handleInputKeyDown,
2545
+ placeholder,
2546
+ className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
2547
+ }
2548
+ ),
2549
+ /* @__PURE__ */ jsx24("kbd", { "aria-hidden": "true", className: "rounded border border-ph-border bg-ph-muted px-1.5 py-0.5 text-xs text-ph-mutedtext", children: "ESC" })
2550
+ ] }),
2551
+ /* @__PURE__ */ jsx24("div", { ref: listboxRef, id: listboxId, role: "listbox", "aria-label": "Commands", className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ jsx24("div", { role: "status", className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ jsxs21(
2552
+ "div",
2400
2553
  {
2401
- ref: inputRef,
2402
- id: inputId,
2403
- "data-test": inputDataTest,
2404
- type: "text",
2405
- "aria-label": "Search commands",
2406
- value: query,
2407
- onChange: (e) => {
2408
- setQuery(e.target.value);
2409
- setSelectedIndex(0);
2554
+ id: `command-${item.id}`,
2555
+ "data-test": `command-${item.id}`,
2556
+ role: "option",
2557
+ "aria-selected": index === activeIndex,
2558
+ onClick: () => {
2559
+ item.onSelect();
2560
+ onClose();
2410
2561
  },
2411
- placeholder,
2412
- className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
2413
- }
2414
- ),
2415
- /* @__PURE__ */ jsx24("kbd", { className: "rounded border border-ph-border bg-ph-muted px-1.5 py-0.5 text-xs text-ph-mutedtext", children: "ESC" })
2416
- ] }),
2417
- /* @__PURE__ */ jsx24("div", { className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ jsx24("div", { className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ jsxs21(
2418
- "button",
2419
- {
2420
- type: "button",
2421
- id: `command-${item.id}`,
2422
- "data-test": `command-${item.id}`,
2423
- onClick: () => {
2424
- item.onSelect();
2425
- onClose();
2562
+ onMouseEnter: () => setSelectedIndex(index),
2563
+ className: cn(
2564
+ "flex w-full cursor-pointer items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
2565
+ index === activeIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
2566
+ ),
2567
+ children: [
2568
+ item.icon && /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", className: "h-5 w-5", children: item.icon }),
2569
+ /* @__PURE__ */ jsx24("span", { className: "flex-1", children: item.label }),
2570
+ item.shortcut && /* @__PURE__ */ jsx24("kbd", { "aria-hidden": "true", className: "rounded border border-ph-border bg-ph-surface px-1.5 py-0.5 text-xs text-ph-mutedtext", children: item.shortcut })
2571
+ ]
2426
2572
  },
2427
- onMouseEnter: () => setSelectedIndex(index),
2428
- className: cn(
2429
- "flex w-full items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
2430
- index === selectedIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
2431
- ),
2432
- children: [
2433
- item.icon && /* @__PURE__ */ jsx24("span", { className: "h-5 w-5", children: item.icon }),
2434
- /* @__PURE__ */ jsx24("span", { className: "flex-1", children: item.label }),
2435
- item.shortcut && /* @__PURE__ */ jsx24("kbd", { className: "rounded border border-ph-border bg-ph-surface px-1.5 py-0.5 text-xs text-ph-mutedtext", children: item.shortcut })
2436
- ]
2437
- },
2438
- item.id
2439
- )) })
2440
- ]
2441
- }
2442
- )
2573
+ item.id
2574
+ )) })
2575
+ ]
2576
+ }
2577
+ )
2578
+ ] })
2443
2579
  }
2444
2580
  );
2445
2581
  }
2446
2582
 
2447
2583
  // src/components/ui/Calendar.tsx
2448
- import { useState as useState4 } from "react";
2584
+ import { useEffect as useEffect3, useId as useId7, useRef as useRef3, useState as useState5 } from "react";
2449
2585
  import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
2586
+ var monthNames = [
2587
+ "January",
2588
+ "February",
2589
+ "March",
2590
+ "April",
2591
+ "May",
2592
+ "June",
2593
+ "July",
2594
+ "August",
2595
+ "September",
2596
+ "October",
2597
+ "November",
2598
+ "December"
2599
+ ];
2600
+ var weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
2601
+ var fullWeekDays = [
2602
+ "Sunday",
2603
+ "Monday",
2604
+ "Tuesday",
2605
+ "Wednesday",
2606
+ "Thursday",
2607
+ "Friday",
2608
+ "Saturday"
2609
+ ];
2610
+ function startOfDay(date) {
2611
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
2612
+ }
2613
+ function startOfMonth(date) {
2614
+ return new Date(date.getFullYear(), date.getMonth(), 1);
2615
+ }
2616
+ function isSameDay(first, second) {
2617
+ return first.getFullYear() === second.getFullYear() && first.getMonth() === second.getMonth() && first.getDate() === second.getDate();
2618
+ }
2619
+ function addDays(date, amount) {
2620
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount);
2621
+ }
2622
+ function addMonths(date, amount) {
2623
+ const targetMonth = new Date(date.getFullYear(), date.getMonth() + amount, 1);
2624
+ const lastDay = new Date(
2625
+ targetMonth.getFullYear(),
2626
+ targetMonth.getMonth() + 1,
2627
+ 0
2628
+ ).getDate();
2629
+ return new Date(
2630
+ targetMonth.getFullYear(),
2631
+ targetMonth.getMonth(),
2632
+ Math.min(date.getDate(), lastDay)
2633
+ );
2634
+ }
2635
+ function dateKey(date) {
2636
+ return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
2637
+ }
2638
+ function dateLabel(date) {
2639
+ return `${fullWeekDays[date.getDay()]}, ${date.getDate()} ${monthNames[date.getMonth()]} ${date.getFullYear()}`;
2640
+ }
2450
2641
  function Calendar({ value, onChange, className }) {
2451
- const [currentMonth, setCurrentMonth] = useState4(value || /* @__PURE__ */ new Date());
2452
- const today = /* @__PURE__ */ new Date();
2642
+ const [currentMonth, setCurrentMonth] = useState5(() => startOfMonth(value != null ? value : /* @__PURE__ */ new Date()));
2643
+ const [focusedDate, setFocusedDate] = useState5(() => startOfDay(value != null ? value : /* @__PURE__ */ new Date()));
2644
+ const gridRef = useRef3(null);
2645
+ const shouldFocusDateRef = useRef3(false);
2646
+ const monthLabelId = useId7();
2647
+ const today = startOfDay(/* @__PURE__ */ new Date());
2648
+ useEffect3(() => {
2649
+ if (!value) return;
2650
+ const nextDate = startOfDay(value);
2651
+ setCurrentMonth(startOfMonth(nextDate));
2652
+ setFocusedDate(nextDate);
2653
+ }, [value]);
2654
+ useEffect3(() => {
2655
+ var _a, _b;
2656
+ if (!shouldFocusDateRef.current) return;
2657
+ (_b = (_a = gridRef.current) == null ? void 0 : _a.querySelector(`[data-date="${dateKey(focusedDate)}"]`)) == null ? void 0 : _b.focus();
2658
+ shouldFocusDateRef.current = false;
2659
+ }, [currentMonth, focusedDate]);
2453
2660
  const year = currentMonth.getFullYear();
2454
2661
  const month = currentMonth.getMonth();
2455
- const firstDay = new Date(year, month, 1).getDay();
2456
- const daysInMonth = new Date(year, month + 1, 0).getDate();
2457
- const prevMonth = () => setCurrentMonth(new Date(year, month - 1, 1));
2458
- const nextMonth = () => setCurrentMonth(new Date(year, month + 1, 1));
2459
- const monthNames = [
2460
- "January",
2461
- "February",
2462
- "March",
2463
- "April",
2464
- "May",
2465
- "June",
2466
- "July",
2467
- "August",
2468
- "September",
2469
- "October",
2470
- "November",
2471
- "December"
2472
- ];
2473
- const weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
2474
- const isSelected = (day) => {
2475
- if (!value) return false;
2476
- return value.getDate() === day && value.getMonth() === month && value.getFullYear() === year;
2662
+ const changeMonth = (amount) => {
2663
+ const nextDate = addMonths(focusedDate, amount);
2664
+ setFocusedDate(nextDate);
2665
+ setCurrentMonth(startOfMonth(nextDate));
2477
2666
  };
2478
- const isToday = (day) => {
2479
- return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
2667
+ const moveFocus = (nextDate) => {
2668
+ shouldFocusDateRef.current = true;
2669
+ setFocusedDate(nextDate);
2670
+ setCurrentMonth(startOfMonth(nextDate));
2480
2671
  };
2481
- const handleSelect = (day) => {
2482
- onChange == null ? void 0 : onChange(new Date(year, month, day));
2672
+ const handleSelect = (date) => {
2673
+ setFocusedDate(date);
2674
+ onChange == null ? void 0 : onChange(startOfDay(date));
2483
2675
  };
2484
- const days = [];
2485
- for (let i = 0; i < firstDay; i++) {
2486
- days.push(null);
2676
+ const handleDayKeyDown = (event, date) => {
2677
+ let nextDate;
2678
+ switch (event.key) {
2679
+ case "ArrowLeft":
2680
+ nextDate = addDays(date, -1);
2681
+ break;
2682
+ case "ArrowRight":
2683
+ nextDate = addDays(date, 1);
2684
+ break;
2685
+ case "ArrowUp":
2686
+ nextDate = addDays(date, -7);
2687
+ break;
2688
+ case "ArrowDown":
2689
+ nextDate = addDays(date, 7);
2690
+ break;
2691
+ case "Home":
2692
+ nextDate = addDays(date, -date.getDay());
2693
+ break;
2694
+ case "End":
2695
+ nextDate = addDays(date, 6 - date.getDay());
2696
+ break;
2697
+ case "PageUp":
2698
+ nextDate = addMonths(date, event.shiftKey ? -12 : -1);
2699
+ break;
2700
+ case "PageDown":
2701
+ nextDate = addMonths(date, event.shiftKey ? 12 : 1);
2702
+ break;
2703
+ case "Enter":
2704
+ case " ":
2705
+ event.preventDefault();
2706
+ handleSelect(date);
2707
+ return;
2708
+ default:
2709
+ return;
2710
+ }
2711
+ event.preventDefault();
2712
+ moveFocus(nextDate);
2713
+ };
2714
+ const firstDay = new Date(year, month, 1).getDay();
2715
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
2716
+ const days = Array.from({ length: firstDay }, () => null);
2717
+ for (let day = 1; day <= daysInMonth; day++) {
2718
+ days.push(new Date(year, month, day));
2487
2719
  }
2488
- for (let i = 1; i <= daysInMonth; i++) {
2489
- days.push(i);
2720
+ while (days.length < 42) {
2721
+ days.push(null);
2490
2722
  }
2491
2723
  return /* @__PURE__ */ jsxs22("div", { className: cn("w-[280px] rounded-xl border border-ph-border bg-ph-surface p-4 shadow-ph", className), children: [
2492
2724
  /* @__PURE__ */ jsxs22("div", { className: "mb-4 flex items-center justify-between", children: [
@@ -2494,13 +2726,13 @@ function Calendar({ value, onChange, className }) {
2494
2726
  "button",
2495
2727
  {
2496
2728
  type: "button",
2497
- onClick: prevMonth,
2729
+ onClick: () => changeMonth(-1),
2498
2730
  "aria-label": "Previous month",
2499
2731
  className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
2500
2732
  children: /* @__PURE__ */ jsx25(IconChevronLeft, { className: "h-5 w-5", "aria-hidden": true })
2501
2733
  }
2502
2734
  ),
2503
- /* @__PURE__ */ jsxs22("span", { className: "text-sm font-semibold text-ph-ink", children: [
2735
+ /* @__PURE__ */ jsxs22("span", { id: monthLabelId, "aria-live": "polite", className: "text-sm font-semibold text-ph-ink", children: [
2504
2736
  monthNames[month],
2505
2737
  " ",
2506
2738
  year
@@ -2509,27 +2741,56 @@ function Calendar({ value, onChange, className }) {
2509
2741
  "button",
2510
2742
  {
2511
2743
  type: "button",
2512
- onClick: nextMonth,
2744
+ onClick: () => changeMonth(1),
2513
2745
  "aria-label": "Next month",
2514
2746
  className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
2515
2747
  children: /* @__PURE__ */ jsx25(IconChevronRight, { className: "h-5 w-5", "aria-hidden": true })
2516
2748
  }
2517
2749
  )
2518
2750
  ] }),
2519
- /* @__PURE__ */ jsxs22("div", { className: "grid grid-cols-7 gap-1", children: [
2520
- weekDays.map((day) => /* @__PURE__ */ jsx25("div", { className: "py-1 text-center text-xs font-medium text-ph-mutedtext", children: day }, day)),
2521
- days.map((day, index) => /* @__PURE__ */ jsx25("div", { className: "aspect-square", children: day && /* @__PURE__ */ jsx25(
2522
- "button",
2751
+ /* @__PURE__ */ jsxs22("div", { ref: gridRef, role: "grid", "aria-labelledby": monthLabelId, children: [
2752
+ /* @__PURE__ */ jsx25("div", { role: "row", className: "grid grid-cols-7 gap-1", children: weekDays.map((day, index) => /* @__PURE__ */ jsx25(
2753
+ "div",
2523
2754
  {
2524
- type: "button",
2525
- onClick: () => handleSelect(day),
2526
- className: cn(
2527
- "flex h-full w-full items-center justify-center rounded-lg text-sm transition-colors",
2528
- isSelected(day) ? "bg-ph-brand font-semibold text-[var(--ph-on-accent)] shadow-ph" : isToday(day) ? "bg-ph-muted font-semibold text-ph-brand ring-1 ring-ph-brand/30" : "text-ph-ink hover:bg-ph-muted"
2529
- ),
2755
+ role: "columnheader",
2756
+ "aria-label": fullWeekDays[index],
2757
+ className: "py-1 text-center text-xs font-medium text-ph-mutedtext",
2530
2758
  children: day
2531
- }
2532
- ) }, index))
2759
+ },
2760
+ day
2761
+ )) }),
2762
+ Array.from({ length: 6 }, (_, week) => {
2763
+ const weekDates = days.slice(week * 7, week * 7 + 7);
2764
+ if (weekDates.length === 0 || weekDates.every((date) => !date)) return null;
2765
+ return /* @__PURE__ */ jsx25("div", { role: "row", className: "grid grid-cols-7 gap-1", children: weekDates.map(
2766
+ (date, day) => date ? /* @__PURE__ */ jsx25(
2767
+ "div",
2768
+ {
2769
+ role: "gridcell",
2770
+ "aria-selected": value ? isSameDay(value, date) : false,
2771
+ className: "aspect-square",
2772
+ children: /* @__PURE__ */ jsx25(
2773
+ "button",
2774
+ {
2775
+ type: "button",
2776
+ "data-date": dateKey(date),
2777
+ "aria-label": dateLabel(date),
2778
+ "aria-current": isSameDay(today, date) ? "date" : void 0,
2779
+ tabIndex: isSameDay(focusedDate, date) ? 0 : -1,
2780
+ onClick: () => handleSelect(date),
2781
+ onKeyDown: (event) => handleDayKeyDown(event, date),
2782
+ className: cn(
2783
+ "flex h-full w-full items-center justify-center rounded-lg text-sm transition-colors",
2784
+ value && isSameDay(value, date) ? "bg-ph-brand font-semibold text-[var(--ph-on-accent)] shadow-ph" : isSameDay(today, date) ? "bg-ph-muted font-semibold text-ph-brand ring-1 ring-ph-brand/30" : "text-ph-ink hover:bg-ph-muted"
2785
+ ),
2786
+ children: date.getDate()
2787
+ }
2788
+ )
2789
+ },
2790
+ dateKey(date)
2791
+ ) : /* @__PURE__ */ jsx25("div", { role: "gridcell", "aria-hidden": "true", className: "aspect-square" }, `empty-${week}-${day}`)
2792
+ ) }, week);
2793
+ })
2533
2794
  ] })
2534
2795
  ] });
2535
2796
  }
@@ -2538,14 +2799,16 @@ function Calendar({ value, onChange, className }) {
2538
2799
  import {
2539
2800
  cloneElement,
2540
2801
  createContext,
2802
+ useCallback,
2541
2803
  useContext,
2542
- useEffect as useEffect3,
2543
- useId as useId5,
2544
- useRef as useRef3,
2545
- useState as useState5
2804
+ useEffect as useEffect4,
2805
+ useId as useId8,
2806
+ useLayoutEffect as useLayoutEffect2,
2807
+ useRef as useRef4,
2808
+ useState as useState6
2546
2809
  } from "react";
2547
2810
  import { createPortal } from "react-dom";
2548
- import { Fragment as Fragment4, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
2811
+ import { Fragment as Fragment5, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
2549
2812
  var TooltipDelayContext = createContext(0);
2550
2813
  function TooltipProvider({
2551
2814
  children,
@@ -2553,31 +2816,15 @@ function TooltipProvider({
2553
2816
  }) {
2554
2817
  return /* @__PURE__ */ jsx26(TooltipDelayContext.Provider, { value: delayDuration, children });
2555
2818
  }
2556
- function tooltipPosition(trigger, side, align, offset) {
2819
+ function tooltipPosition(trigger, content, side, align, offset, collisionPadding) {
2557
2820
  const horizontal = align === "start" ? trigger.left : align === "end" ? trigger.right : trigger.left + trigger.width / 2;
2558
2821
  const vertical = align === "start" ? trigger.top : align === "end" ? trigger.bottom : trigger.top + trigger.height / 2;
2559
- if (side === "top")
2560
- return {
2561
- left: horizontal,
2562
- top: trigger.top - offset,
2563
- transform: "translate(-50%, -100%)"
2564
- };
2565
- if (side === "bottom")
2566
- return {
2567
- left: horizontal,
2568
- top: trigger.bottom + offset,
2569
- transform: "translate(-50%, 0)"
2570
- };
2571
- if (side === "left")
2572
- return {
2573
- left: trigger.left - offset,
2574
- top: vertical,
2575
- transform: "translate(-100%, -50%)"
2576
- };
2822
+ const position = side === "top" ? { left: horizontal - content.width / 2, top: trigger.top - offset - content.height } : side === "bottom" ? { left: horizontal - content.width / 2, top: trigger.bottom + offset } : side === "left" ? { left: trigger.left - offset - content.width, top: vertical - content.height / 2 } : { left: trigger.right + offset, top: vertical - content.height / 2 };
2823
+ const maxLeft = Math.max(collisionPadding, window.innerWidth - content.width - collisionPadding);
2824
+ const maxTop = Math.max(collisionPadding, window.innerHeight - content.height - collisionPadding);
2577
2825
  return {
2578
- left: trigger.right + offset,
2579
- top: vertical,
2580
- transform: "translate(0, -50%)"
2826
+ left: Math.min(Math.max(position.left, collisionPadding), maxLeft),
2827
+ top: Math.min(Math.max(position.top, collisionPadding), maxTop)
2581
2828
  };
2582
2829
  }
2583
2830
  function Tooltip({
@@ -2586,18 +2833,21 @@ function Tooltip({
2586
2833
  side = "top",
2587
2834
  align = "center",
2588
2835
  sideOffset = 7,
2836
+ collisionPadding = 8,
2589
2837
  className,
2590
2838
  open,
2591
2839
  defaultOpen = false,
2592
2840
  onOpenChange,
2593
- delayDuration
2841
+ delayDuration,
2842
+ disableHoverableContent = false
2594
2843
  }) {
2595
2844
  const providerDelay = useContext(TooltipDelayContext);
2596
- const generatedId = useId5().replace(/:/g, "");
2597
- const triggerRef = useRef3(null);
2598
- const timerRef = useRef3(null);
2599
- const [internalOpen, setInternalOpen] = useState5(defaultOpen);
2600
- const [position, setPosition] = useState5(null);
2845
+ const generatedId = useId8().replace(/:/g, "");
2846
+ const triggerRef = useRef4(null);
2847
+ const contentRef = useRef4(null);
2848
+ const timerRef = useRef4(null);
2849
+ const [internalOpen, setInternalOpen] = useState6(defaultOpen);
2850
+ const [position, setPosition] = useState6(null);
2601
2851
  const isOpen = open != null ? open : internalOpen;
2602
2852
  const triggerId = children.props.id;
2603
2853
  const tooltipId = triggerId ? `${triggerId}-tooltip` : `ph-tooltip-${generatedId}`;
@@ -2609,17 +2859,19 @@ function Tooltip({
2609
2859
  if (timerRef.current) clearTimeout(timerRef.current);
2610
2860
  timerRef.current = null;
2611
2861
  }
2612
- function updatePosition() {
2613
- if (!triggerRef.current) return;
2862
+ const updatePosition = useCallback(() => {
2863
+ if (!triggerRef.current || !contentRef.current) return;
2614
2864
  setPosition(
2615
2865
  tooltipPosition(
2616
2866
  triggerRef.current.getBoundingClientRect(),
2867
+ contentRef.current.getBoundingClientRect(),
2617
2868
  side,
2618
2869
  align,
2619
- sideOffset
2870
+ sideOffset,
2871
+ collisionPadding
2620
2872
  )
2621
2873
  );
2622
- }
2874
+ }, [align, collisionPadding, side, sideOffset]);
2623
2875
  function show(immediate) {
2624
2876
  clearTimer();
2625
2877
  updatePosition();
@@ -2631,7 +2883,18 @@ function Tooltip({
2631
2883
  clearTimer();
2632
2884
  setOpen(false);
2633
2885
  }
2634
- useEffect3(() => {
2886
+ function hideFromTrigger() {
2887
+ if (disableHoverableContent) {
2888
+ hide();
2889
+ return;
2890
+ }
2891
+ clearTimer();
2892
+ timerRef.current = setTimeout(() => setOpen(false), 100);
2893
+ }
2894
+ useLayoutEffect2(() => {
2895
+ if (isOpen) updatePosition();
2896
+ }, [isOpen, updatePosition]);
2897
+ useEffect4(() => {
2635
2898
  if (!isOpen) return;
2636
2899
  const reposition = () => updatePosition();
2637
2900
  window.addEventListener("resize", reposition);
@@ -2640,18 +2903,18 @@ function Tooltip({
2640
2903
  window.removeEventListener("resize", reposition);
2641
2904
  window.removeEventListener("scroll", reposition, true);
2642
2905
  };
2643
- });
2644
- useEffect3(() => () => clearTimer(), []);
2906
+ }, [isOpen, updatePosition]);
2907
+ useEffect4(() => () => clearTimer(), []);
2645
2908
  const describedBy = [children.props["aria-describedby"], tooltipId].filter(Boolean).join(" ");
2646
2909
  const trigger = cloneElement(children, { "aria-describedby": describedBy });
2647
- return /* @__PURE__ */ jsxs23(Fragment4, { children: [
2910
+ return /* @__PURE__ */ jsxs23(Fragment5, { children: [
2648
2911
  /* @__PURE__ */ jsx26(
2649
2912
  "span",
2650
2913
  {
2651
2914
  ref: triggerRef,
2652
2915
  className: "inline-flex",
2653
2916
  onMouseEnter: () => show(false),
2654
- onMouseLeave: hide,
2917
+ onMouseLeave: hideFromTrigger,
2655
2918
  onFocusCapture: () => show(true),
2656
2919
  onBlurCapture: hide,
2657
2920
  onKeyDown: (event) => {
@@ -2660,19 +2923,26 @@ function Tooltip({
2660
2923
  children: trigger
2661
2924
  }
2662
2925
  ),
2663
- isOpen && position && typeof document !== "undefined" ? createPortal(
2926
+ isOpen && typeof document !== "undefined" ? createPortal(
2664
2927
  /* @__PURE__ */ jsx26(
2665
2928
  "span",
2666
2929
  {
2667
- style: __spreadValues({ position: "fixed" }, position),
2930
+ style: __spreadProps(__spreadValues({ position: "fixed" }, position), { visibility: position ? void 0 : "hidden" }),
2668
2931
  className: "pointer-events-none z-[200]",
2669
2932
  children: /* @__PURE__ */ jsx26(
2670
2933
  "span",
2671
2934
  {
2935
+ ref: contentRef,
2672
2936
  id: tooltipId,
2673
2937
  role: "tooltip",
2674
2938
  "data-side": side,
2675
- className: cn("ph-tooltip-content", className),
2939
+ className: cn(
2940
+ "ph-tooltip-content",
2941
+ !disableHoverableContent && "pointer-events-auto",
2942
+ className
2943
+ ),
2944
+ onMouseEnter: disableHoverableContent ? void 0 : clearTimer,
2945
+ onMouseLeave: disableHoverableContent ? void 0 : hide,
2676
2946
  children: content
2677
2947
  }
2678
2948
  )
@@ -2695,7 +2965,7 @@ function EmptyState({ icon, title, description, action, className }) {
2695
2965
  ),
2696
2966
  children: [
2697
2967
  icon && /* @__PURE__ */ jsx27("div", { className: "mb-4 flex h-14 w-14 items-center justify-center rounded-full bg-ph-muted text-ph-mutedtext", children: icon }),
2698
- /* @__PURE__ */ jsx27("h3", { className: "text-base font-semibold text-ph-ink", children: title }),
2968
+ /* @__PURE__ */ jsx27("h2", { className: "text-base font-semibold text-ph-ink", children: title }),
2699
2969
  description && /* @__PURE__ */ jsx27("p", { className: "mt-1 max-w-sm text-sm text-ph-subtle", children: description }),
2700
2970
  action && /* @__PURE__ */ jsx27("div", { className: "mt-4", children: action })
2701
2971
  ]
@@ -2704,7 +2974,7 @@ function EmptyState({ icon, title, description, action, className }) {
2704
2974
  }
2705
2975
 
2706
2976
  // src/components/ui/FilterChips.tsx
2707
- import { Fragment as Fragment5, jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
2977
+ import { Fragment as Fragment6, jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
2708
2978
  function FilterChips({
2709
2979
  chips,
2710
2980
  onToggle,
@@ -2715,7 +2985,7 @@ function FilterChips({
2715
2985
  return /* @__PURE__ */ jsx28("div", { className: cn("ph-filter-chips", className), role: "group", "aria-label": ariaLabel, children: chips.map((chip) => {
2716
2986
  var _a;
2717
2987
  const label = (_a = chip.removeLabel) != null ? _a : getChipText(chip);
2718
- const content = /* @__PURE__ */ jsxs25(Fragment5, { children: [
2988
+ const content = /* @__PURE__ */ jsxs25(Fragment6, { children: [
2719
2989
  /* @__PURE__ */ jsx28("span", { className: "ph-filter-chip__label", children: chip.label }),
2720
2990
  chip.value != null ? /* @__PURE__ */ jsx28("span", { className: "ph-filter-chip__value", children: chip.value }) : null
2721
2991
  ] });
@@ -2894,10 +3164,10 @@ function FilterControls(_a) {
2894
3164
  }
2895
3165
 
2896
3166
  // src/components/ui/CodeBlock.tsx
2897
- import { useState as useState6 } from "react";
3167
+ import { useState as useState7 } from "react";
2898
3168
  import { jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
2899
3169
  function CodeBlock({ code, language = "tsx", filename, className }) {
2900
- const [copied, setCopied] = useState6(false);
3170
+ const [copied, setCopied] = useState7(false);
2901
3171
  const handleCopy = async () => {
2902
3172
  await navigator.clipboard.writeText(code);
2903
3173
  setCopied(true);
@@ -2959,7 +3229,7 @@ function ComponentDocs({ title = "Props & variants", rows, defaultOpen = false,
2959
3229
  }
2960
3230
 
2961
3231
  // src/components/ui/ShowcaseWrapper.tsx
2962
- import { useState as useState7 } from "react";
3232
+ import { useState as useState8 } from "react";
2963
3233
  import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
2964
3234
  function ShowcaseWrapper({
2965
3235
  id,
@@ -2972,7 +3242,7 @@ function ShowcaseWrapper({
2972
3242
  className
2973
3243
  }) {
2974
3244
  var _a;
2975
- const [showCode, setShowCode] = useState7(false);
3245
+ const [showCode, setShowCode] = useState8(false);
2976
3246
  const fallbackId = (_a = titleIdMap[title]) != null ? _a : title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
2977
3247
  return /* @__PURE__ */ jsxs30("section", { id: id != null ? id : fallbackId, className: cn("scroll-mt-20", className), children: [
2978
3248
  /* @__PURE__ */ jsxs30("div", { className: "ph-h2-rule mb-8", children: [
@@ -3062,11 +3332,16 @@ var titleIdMap = {
3062
3332
  };
3063
3333
 
3064
3334
  // src/components/ui/CollapsibleSection.tsx
3065
- import { useId as useId6, useState as useState8 } from "react";
3335
+ import { useId as useId9, useState as useState9 } from "react";
3066
3336
  import { jsx as jsx34, jsxs as jsxs31 } from "react/jsx-runtime";
3067
- function CollapsibleSection({ title, children, defaultOpen = true, id }) {
3068
- const [isOpen, setIsOpen] = useState8(defaultOpen);
3069
- const generatedId = useId6();
3337
+ function CollapsibleSection({
3338
+ title,
3339
+ children,
3340
+ defaultOpen = true,
3341
+ id
3342
+ }) {
3343
+ const [isOpen, setIsOpen] = useState9(defaultOpen);
3344
+ const generatedId = useId9();
3070
3345
  const contentId = `${id != null ? id : generatedId}-content`;
3071
3346
  return /* @__PURE__ */ jsxs31("section", { id, className: "scroll-mt-20", children: [
3072
3347
  /* @__PURE__ */ jsxs31(
@@ -3097,6 +3372,9 @@ function CollapsibleSection({ title, children, defaultOpen = true, id }) {
3097
3372
  {
3098
3373
  id: contentId,
3099
3374
  "aria-hidden": !isOpen,
3375
+ ref: (node) => {
3376
+ if (node) node.toggleAttribute("inert", !isOpen);
3377
+ },
3100
3378
  className: cn(
3101
3379
  "overflow-hidden transition-all duration-300",
3102
3380
  isOpen ? "max-h-[50000px] opacity-100" : "max-h-0 opacity-0"
@@ -3108,6 +3386,7 @@ function CollapsibleSection({ title, children, defaultOpen = true, id }) {
3108
3386
  }
3109
3387
 
3110
3388
  // src/components/ui/Typography.tsx
3389
+ import { forwardRef as forwardRef9 } from "react";
3111
3390
  import { jsx as jsx35 } from "react/jsx-runtime";
3112
3391
  var toneMap2 = {
3113
3392
  default: "text-ph-ink",
@@ -3130,54 +3409,62 @@ var weightMap = {
3130
3409
  function textClass(base, tone, weight, truncate, className) {
3131
3410
  return cn(base, toneMap2[tone], weight && weightMap[weight], truncate && "truncate", className);
3132
3411
  }
3133
- function Display({
3134
- children,
3135
- tone = "default",
3136
- weight,
3137
- truncate,
3138
- className
3139
- }) {
3140
- return /* @__PURE__ */ jsx35("h1", { className: textClass("ph-hero-title", tone, weight, truncate, className), children });
3141
- }
3142
- function SectionTitle({ children, tone = "default", weight, truncate, className }) {
3143
- return /* @__PURE__ */ jsx35("h2", { className: textClass("ph-section-title", tone, weight, truncate, className), children });
3144
- }
3145
- function H1({ children, tone = "default", weight, truncate, className }) {
3146
- return /* @__PURE__ */ jsx35("h1", { className: textClass("text-3xl font-bold tracking-tight md:text-4xl", tone, weight, truncate, className), children });
3147
- }
3148
- function H2({ children, tone = "default", weight, truncate, className }) {
3149
- return /* @__PURE__ */ jsx35("h2", { className: textClass("text-2xl font-bold tracking-tight", tone, weight, truncate, className), children });
3150
- }
3151
- function H3({ children, tone = "default", weight, truncate, className }) {
3152
- return /* @__PURE__ */ jsx35("h3", { className: textClass("text-xl font-semibold", tone, weight, truncate, className), children });
3153
- }
3154
- function H4({ children, tone = "default", weight, truncate, className }) {
3155
- return /* @__PURE__ */ jsx35("h4", { className: textClass("text-lg font-semibold", tone, weight, truncate, className), children });
3156
- }
3157
- function H5({ children, tone = "default", weight, truncate, className }) {
3158
- return /* @__PURE__ */ jsx35("h5", { className: textClass("text-base font-semibold", tone, weight, truncate, className), children });
3159
- }
3160
- function P({ children, tone = "default", weight, truncate, className }) {
3161
- return /* @__PURE__ */ jsx35("p", { className: textClass("text-base leading-relaxed", tone, weight, truncate, className), children });
3162
- }
3163
- function Small({ children, tone = "default", weight, truncate, className }) {
3164
- return /* @__PURE__ */ jsx35("span", { className: textClass("text-sm leading-relaxed", tone, weight, truncate, className), children });
3165
- }
3166
- function Caption({ children, tone = "muted", weight, truncate, className }) {
3167
- return /* @__PURE__ */ jsx35("span", { className: textClass("text-[11px] font-medium uppercase tracking-wider", tone, weight, truncate, className), children });
3168
- }
3169
- function Overline({ children, tone = "muted", weight, truncate, className }) {
3170
- return /* @__PURE__ */ jsx35("span", { className: textClass("text-[10px] font-bold uppercase tracking-[0.15em]", tone, weight, truncate, className), children });
3171
- }
3172
- function Lead({ children, tone = "subtle", weight, truncate, className }) {
3173
- return /* @__PURE__ */ jsx35("p", { className: textClass("ph-lead", tone, weight, truncate, className), children });
3174
- }
3175
- function Mono({ children, tone = "default", weight, truncate, className }) {
3176
- return /* @__PURE__ */ jsx35("code", { className: textClass("text-sm font-mono leading-relaxed", tone, weight, truncate, className), children });
3177
- }
3178
- function Label({ children, tone = "default", weight, truncate, className }) {
3179
- return /* @__PURE__ */ jsx35("label", { className: textClass("text-sm font-medium", tone, weight, truncate, className), children });
3180
- }
3412
+ var Display = forwardRef9(function Display2(_a, ref) {
3413
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3414
+ return /* @__PURE__ */ jsx35("h1", __spreadProps(__spreadValues({ ref }, props), { className: textClass("ph-hero-title", tone, weight, truncate, className), children }));
3415
+ });
3416
+ var SectionTitle = forwardRef9(function SectionTitle2(_a, ref) {
3417
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3418
+ return /* @__PURE__ */ jsx35("h2", __spreadProps(__spreadValues({ ref }, props), { className: textClass("ph-section-title", tone, weight, truncate, className), children }));
3419
+ });
3420
+ var H1 = forwardRef9(function H12(_a, ref) {
3421
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3422
+ return /* @__PURE__ */ jsx35("h1", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-3xl font-bold tracking-tight md:text-4xl", tone, weight, truncate, className), children }));
3423
+ });
3424
+ var H2 = forwardRef9(function H22(_a, ref) {
3425
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3426
+ return /* @__PURE__ */ jsx35("h2", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-2xl font-bold tracking-tight", tone, weight, truncate, className), children }));
3427
+ });
3428
+ var H3 = forwardRef9(function H32(_a, ref) {
3429
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3430
+ return /* @__PURE__ */ jsx35("h3", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-xl font-semibold", tone, weight, truncate, className), children }));
3431
+ });
3432
+ var H4 = forwardRef9(function H42(_a, ref) {
3433
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3434
+ return /* @__PURE__ */ jsx35("h4", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-lg font-semibold", tone, weight, truncate, className), children }));
3435
+ });
3436
+ var H5 = forwardRef9(function H52(_a, ref) {
3437
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3438
+ return /* @__PURE__ */ jsx35("h5", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-base font-semibold", tone, weight, truncate, className), children }));
3439
+ });
3440
+ var P = forwardRef9(function P2(_a, ref) {
3441
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3442
+ return /* @__PURE__ */ jsx35("p", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-base leading-relaxed", tone, weight, truncate, className), children }));
3443
+ });
3444
+ var Small = forwardRef9(function Small2(_a, ref) {
3445
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3446
+ return /* @__PURE__ */ jsx35("span", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-sm leading-relaxed", tone, weight, truncate, className), children }));
3447
+ });
3448
+ var Caption = forwardRef9(function Caption2(_a, ref) {
3449
+ var _b = _a, { children, tone = "muted", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3450
+ return /* @__PURE__ */ jsx35("span", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-[11px] font-medium uppercase tracking-wider", tone, weight, truncate, className), children }));
3451
+ });
3452
+ var Overline = forwardRef9(function Overline2(_a, ref) {
3453
+ var _b = _a, { children, tone = "muted", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3454
+ return /* @__PURE__ */ jsx35("span", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-[10px] font-bold uppercase tracking-[0.15em]", tone, weight, truncate, className), children }));
3455
+ });
3456
+ var Lead = forwardRef9(function Lead2(_a, ref) {
3457
+ var _b = _a, { children, tone = "subtle", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3458
+ return /* @__PURE__ */ jsx35("p", __spreadProps(__spreadValues({ ref }, props), { className: textClass("ph-lead", tone, weight, truncate, className), children }));
3459
+ });
3460
+ var Mono = forwardRef9(function Mono2(_a, ref) {
3461
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3462
+ return /* @__PURE__ */ jsx35("code", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-sm font-mono leading-relaxed", tone, weight, truncate, className), children }));
3463
+ });
3464
+ var Label = forwardRef9(function Label2(_a, ref) {
3465
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3466
+ return /* @__PURE__ */ jsx35("label", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-sm font-medium", tone, weight, truncate, className), children }));
3467
+ });
3181
3468
 
3182
3469
  // src/components/ui/Avatar.tsx
3183
3470
  import { jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
@@ -3189,9 +3476,9 @@ var sizeMap4 = {
3189
3476
  xl: "h-24 w-24 text-3xl"
3190
3477
  };
3191
3478
  var statusMap = {
3192
- online: "bg-emerald-500",
3479
+ online: "bg-ph-success",
3193
3480
  offline: "bg-ph-mutedtext",
3194
- away: "bg-amber-400",
3481
+ away: "bg-ph-warning",
3195
3482
  busy: "bg-ph-danger"
3196
3483
  };
3197
3484
  function Avatar(_a) {
@@ -3227,8 +3514,10 @@ function Avatar(_a) {
3227
3514
  status && /* @__PURE__ */ jsx36(
3228
3515
  "span",
3229
3516
  {
3517
+ role: "img",
3518
+ "aria-label": `${status} status`,
3230
3519
  className: cn(
3231
- "absolute bottom-0 right-1 h-2.5 w-2.5 rounded-full border-2 border-white",
3520
+ "absolute bottom-0 right-1 h-2.5 w-2.5 rounded-full border-2 border-ph-surface",
3232
3521
  statusMap[status]
3233
3522
  )
3234
3523
  }
@@ -3255,6 +3544,7 @@ function AvatarGroup(_a) {
3255
3544
  }
3256
3545
 
3257
3546
  // src/components/ui/Progress.tsx
3547
+ import { useId as useId10 } from "react";
3258
3548
  import { jsx as jsx37, jsxs as jsxs33 } from "react/jsx-runtime";
3259
3549
  var sizeMap5 = {
3260
3550
  sm: "h-1",
@@ -3269,7 +3559,9 @@ function Progress(_a) {
3269
3559
  label,
3270
3560
  showPercentage = false,
3271
3561
  size = "md",
3272
- className
3562
+ className,
3563
+ "aria-label": ariaLabel,
3564
+ "aria-labelledby": ariaLabelledBy
3273
3565
  } = _b, props = __objRest(_b, [
3274
3566
  "value",
3275
3567
  "max",
@@ -3277,12 +3569,17 @@ function Progress(_a) {
3277
3569
  "label",
3278
3570
  "showPercentage",
3279
3571
  "size",
3280
- "className"
3572
+ "className",
3573
+ "aria-label",
3574
+ "aria-labelledby"
3281
3575
  ]);
3282
- const percentage = Math.min(100, Math.max(0, value / max * 100));
3576
+ const labelId = useId10();
3577
+ const safeMax = Number.isFinite(max) && max > 0 ? max : 100;
3578
+ const safeValue = Number.isFinite(value) ? Math.min(safeMax, Math.max(0, value)) : 0;
3579
+ const percentage = safeValue / safeMax * 100;
3283
3580
  return /* @__PURE__ */ jsxs33("div", __spreadProps(__spreadValues({ className: cn("w-full", className) }, props), { children: [
3284
3581
  (label || showPercentage) && /* @__PURE__ */ jsxs33("div", { className: "mb-1.5 flex justify-between text-sm text-ph-subtle", children: [
3285
- label && /* @__PURE__ */ jsx37("span", { children: label }),
3582
+ label && /* @__PURE__ */ jsx37("span", { id: labelId, children: label }),
3286
3583
  showPercentage && /* @__PURE__ */ jsxs33("span", { className: "tabular-nums", children: [
3287
3584
  Math.round(percentage),
3288
3585
  "%"
@@ -3294,18 +3591,20 @@ function Progress(_a) {
3294
3591
  className: cn("ph-progress-bar", color),
3295
3592
  style: { width: `${percentage}%` },
3296
3593
  role: "progressbar",
3297
- "aria-valuenow": value,
3594
+ "aria-valuenow": safeValue,
3298
3595
  "aria-valuemin": 0,
3299
- "aria-valuemax": max
3596
+ "aria-valuemax": safeMax,
3597
+ "aria-label": label ? void 0 : ariaLabel != null ? ariaLabel : "Progress",
3598
+ "aria-labelledby": label ? ariaLabelledBy != null ? ariaLabelledBy : labelId : ariaLabelledBy
3300
3599
  }
3301
3600
  ) })
3302
3601
  ] }));
3303
3602
  }
3304
3603
 
3305
3604
  // src/components/ui/Link.tsx
3306
- import { forwardRef as forwardRef9 } from "react";
3605
+ import { forwardRef as forwardRef10 } from "react";
3307
3606
  import { jsx as jsx38 } from "react/jsx-runtime";
3308
- var Link = forwardRef9(function Link2(_a, ref) {
3607
+ var Link = forwardRef10(function Link2(_a, ref) {
3309
3608
  var _b = _a, {
3310
3609
  className,
3311
3610
  disabled = false,
@@ -3385,9 +3684,9 @@ function Dot(_a) {
3385
3684
  Dot.displayName = "Dot";
3386
3685
 
3387
3686
  // src/components/ui/Chip.tsx
3388
- import { forwardRef as forwardRef10 } from "react";
3687
+ import { forwardRef as forwardRef11 } from "react";
3389
3688
  import { jsx as jsx41, jsxs as jsxs35 } from "react/jsx-runtime";
3390
- var Chip = forwardRef10(function Chip2(_a, ref) {
3689
+ var Chip = forwardRef11(function Chip2(_a, ref) {
3391
3690
  var _b = _a, {
3392
3691
  selected = false,
3393
3692
  onRemove,
@@ -3445,6 +3744,7 @@ Chip.displayName = "Chip";
3445
3744
 
3446
3745
  export {
3447
3746
  ButtonChrome,
3747
+ cn,
3448
3748
  Button,
3449
3749
  IconBase,
3450
3750
  createIconBase,