@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
package/dist/ui.js CHANGED
@@ -914,7 +914,12 @@ var Card = (0, import_react7.forwardRef)(function Card2(_a, ref) {
914
914
  className,
915
915
  bodyClassName,
916
916
  interactive = false,
917
- titleAs: Title2 = "h3"
917
+ href,
918
+ onClick,
919
+ target,
920
+ rel,
921
+ type,
922
+ titleAs: Title3 = "h3"
918
923
  } = _b, props = __objRest(_b, [
919
924
  "children",
920
925
  "title",
@@ -926,31 +931,60 @@ var Card = (0, import_react7.forwardRef)(function Card2(_a, ref) {
926
931
  "className",
927
932
  "bodyClassName",
928
933
  "interactive",
934
+ "href",
935
+ "onClick",
936
+ "target",
937
+ "rel",
938
+ "type",
929
939
  "titleAs"
930
940
  ]);
931
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
932
- "div",
933
- __spreadProps(__spreadValues({
934
- ref,
935
- className: cn(
936
- "ph-card",
937
- variantMap2[variant],
938
- interactive && "ph-card-interactive",
939
- className
940
- )
941
- }, props), {
942
- children: [
943
- media && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ph-card-media", children: media }),
944
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cn("ph-card-body", bodyClassName), children: [
945
- title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Title2, { className: "ph-card-title", children: title }),
946
- description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm text-ph-subtle", children: description }),
947
- children,
948
- actions && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ph-card-actions", children: actions })
949
- ] }),
950
- footer && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "border-t border-ph-border px-6 py-4 text-xs text-ph-subtle", children: footer })
951
- ]
952
- })
941
+ const isLink = href !== void 0;
942
+ const isButton = onClick !== void 0 && !isLink;
943
+ const cardClassName = cn(
944
+ "ph-card",
945
+ variantMap2[variant],
946
+ (interactive || isLink || isButton) && "ph-card-interactive",
947
+ className
953
948
  );
949
+ const cardContent = /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
950
+ media && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ph-card-media", children: media }),
951
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: cn("ph-card-body", bodyClassName), children: [
952
+ title && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Title3, { className: "ph-card-title", children: title }),
953
+ description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm text-ph-subtle", children: description }),
954
+ children,
955
+ actions && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "ph-card-actions", children: actions })
956
+ ] }),
957
+ footer && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "border-t border-ph-border px-6 py-4 text-xs text-ph-subtle", children: footer })
958
+ ] });
959
+ if (isLink) {
960
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
961
+ "a",
962
+ __spreadProps(__spreadValues({
963
+ ref,
964
+ className: cardClassName,
965
+ href,
966
+ target,
967
+ rel,
968
+ onClick
969
+ }, props), {
970
+ children: cardContent
971
+ })
972
+ );
973
+ }
974
+ if (isButton) {
975
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
976
+ "button",
977
+ __spreadProps(__spreadValues({
978
+ ref,
979
+ type: type != null ? type : "button",
980
+ className: cardClassName,
981
+ onClick
982
+ }, props), {
983
+ children: cardContent
984
+ })
985
+ );
986
+ }
987
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", __spreadProps(__spreadValues({ ref, className: cardClassName }, props), { children: cardContent }));
954
988
  });
955
989
  Card.displayName = "Card";
956
990
 
@@ -1014,18 +1048,45 @@ function Kbd(_a) {
1014
1048
  "aria-label"
1015
1049
  ]);
1016
1050
  if (variant === "token") {
1017
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", __spreadProps(__spreadValues({ className: cn("ph-code-token ph-kbd", className), "aria-label": ariaLabel }, props), { children }));
1051
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1052
+ "code",
1053
+ __spreadProps(__spreadValues({
1054
+ className: cn("ph-code-token ph-kbd", className),
1055
+ role: ariaLabel ? "img" : void 0,
1056
+ "aria-label": ariaLabel
1057
+ }, props), {
1058
+ children
1059
+ })
1060
+ );
1018
1061
  }
1019
1062
  const sourceKeys = (keys == null ? void 0 : keys.length) ? keys : children != null ? [children] : [];
1020
1063
  const displayKeys = sourceKeys.map((key) => formatKey(key, platform));
1021
1064
  const accessibleLabel = ariaLabel != null ? ariaLabel : getShortcutLabel(displayKeys);
1022
1065
  if (variant === "key") {
1023
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("kbd", __spreadProps(__spreadValues({ className: cn("ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys[0] }));
1066
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1067
+ "kbd",
1068
+ __spreadProps(__spreadValues({
1069
+ className: cn("ph-keycap", className),
1070
+ role: accessibleLabel ? "img" : void 0,
1071
+ "aria-label": accessibleLabel
1072
+ }, props), {
1073
+ children: displayKeys[0]
1074
+ })
1075
+ );
1024
1076
  }
1025
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("kbd", __spreadProps(__spreadValues({ className: cn("ph-shortcut-group ph-keycap", className), "aria-label": accessibleLabel }, props), { children: displayKeys.map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "contents", children: [
1026
- index > 0 && separator != null ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ph-shortcut-separator", "aria-hidden": "true", children: separator }) : null,
1027
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ph-shortcut-key", "aria-hidden": accessibleLabel ? true : void 0, children: key })
1028
- ] }, index)) }));
1077
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1078
+ "kbd",
1079
+ __spreadProps(__spreadValues({
1080
+ className: cn("ph-shortcut-group ph-keycap", className),
1081
+ role: accessibleLabel ? "img" : void 0,
1082
+ "aria-label": accessibleLabel
1083
+ }, props), {
1084
+ children: displayKeys.map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "contents", children: [
1085
+ index > 0 && separator != null ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ph-shortcut-separator", "aria-hidden": "true", children: separator }) : null,
1086
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "ph-shortcut-key", "aria-hidden": accessibleLabel ? true : void 0, children: key })
1087
+ ] }, index))
1088
+ })
1089
+ );
1029
1090
  }
1030
1091
  function formatKey(key, platform) {
1031
1092
  var _a;
@@ -1159,7 +1220,7 @@ var import_jsx_runtime12 = require("react/jsx-runtime");
1159
1220
  function SettingsNav(_a) {
1160
1221
  var _b = _a, { groups, className } = _b, props = __objRest(_b, ["groups", "className"]);
1161
1222
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", __spreadProps(__spreadValues({ className: cn("ph-settings-nav", className) }, props), { children: groups.map((group, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "ph-settings-nav__group", children: [
1162
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { children: group.label }),
1223
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "ph-settings-nav__heading", children: group.label }),
1163
1224
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "ph-settings-nav__items", children: group.items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1164
1225
  "a",
1165
1226
  {
@@ -1491,6 +1552,7 @@ function DropdownRadioItem(_a) {
1491
1552
 
1492
1553
  // src/components/ui/Input.tsx
1493
1554
  var import_react10 = require("react");
1555
+ var import_iconoir_react = require("iconoir-react");
1494
1556
 
1495
1557
  // src/components/ui/FormField.tsx
1496
1558
  var import_react9 = require("react");
@@ -1523,7 +1585,7 @@ function FormField(_a) {
1523
1585
  const errorId = error ? `${id}-error` : void 0;
1524
1586
  const controlProps = {
1525
1587
  id,
1526
- "aria-describedby": descriptionId,
1588
+ "aria-describedby": errorId != null ? errorId : descriptionId,
1527
1589
  "aria-errormessage": errorId,
1528
1590
  "aria-invalid": error ? true : void 0
1529
1591
  };
@@ -1565,6 +1627,7 @@ var Input = (0, import_react10.forwardRef)(function Input2(_a, ref) {
1565
1627
  helperText,
1566
1628
  size = "md",
1567
1629
  variant = "default",
1630
+ type = "text",
1568
1631
  className,
1569
1632
  wrapperClassName,
1570
1633
  disabled,
@@ -1578,6 +1641,7 @@ var Input = (0, import_react10.forwardRef)(function Input2(_a, ref) {
1578
1641
  "helperText",
1579
1642
  "size",
1580
1643
  "variant",
1644
+ "type",
1581
1645
  "className",
1582
1646
  "wrapperClassName",
1583
1647
  "disabled",
@@ -1587,6 +1651,8 @@ var Input = (0, import_react10.forwardRef)(function Input2(_a, ref) {
1587
1651
  const autoId = (0, import_react10.useId)();
1588
1652
  const id = idProp != null ? idProp : autoId;
1589
1653
  const hasError = Boolean(error);
1654
+ const isPassword = type === "password";
1655
+ const [revealed, setRevealed] = (0, import_react10.useState)(false);
1590
1656
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1591
1657
  FormField,
1592
1658
  {
@@ -1598,23 +1664,39 @@ var Input = (0, import_react10.forwardRef)(function Input2(_a, ref) {
1598
1664
  required,
1599
1665
  disabled,
1600
1666
  className: wrapperClassName,
1601
- children: (fieldProps) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1602
- "input",
1603
- __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
1604
- ref,
1605
- disabled,
1606
- required,
1607
- "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
1608
- className: cn(
1609
- "ph-input w-full",
1610
- sizeMap2[size],
1611
- variant === "ghost" && "ph-input-ghost",
1612
- hasError && "ph-input-error",
1613
- disabled && "cursor-not-allowed opacity-60",
1614
- className
1615
- )
1616
- }), props)
1617
- )
1667
+ children: (fieldProps) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "relative", children: [
1668
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1669
+ "input",
1670
+ __spreadValues(__spreadProps(__spreadValues({}, fieldProps), {
1671
+ ref,
1672
+ type: isPassword && revealed ? "text" : type,
1673
+ disabled,
1674
+ required,
1675
+ "aria-describedby": joinIds(ariaDescribedBy, fieldProps["aria-describedby"]),
1676
+ className: cn(
1677
+ "ph-input w-full",
1678
+ isPassword && "pr-10",
1679
+ sizeMap2[size],
1680
+ variant === "ghost" && "ph-input-ghost",
1681
+ hasError && "ph-input-error",
1682
+ disabled && "cursor-not-allowed opacity-60",
1683
+ className
1684
+ )
1685
+ }), props)
1686
+ ),
1687
+ isPassword ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1688
+ "button",
1689
+ {
1690
+ type: "button",
1691
+ onClick: () => setRevealed((current) => !current),
1692
+ "aria-label": revealed ? "Hide password" : "Show password",
1693
+ "aria-pressed": revealed,
1694
+ disabled,
1695
+ 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",
1696
+ children: revealed ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react.EyeClosed, { className: "h-4 w-4", "aria-hidden": true }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_iconoir_react.Eye, { className: "h-4 w-4", "aria-hidden": true })
1697
+ }
1698
+ ) : null
1699
+ ] })
1618
1700
  }
1619
1701
  );
1620
1702
  });
@@ -1752,7 +1834,7 @@ var Checkbox = (0, import_react10.forwardRef)(function Checkbox2(_a, ref) {
1752
1834
  type: "checkbox",
1753
1835
  disabled,
1754
1836
  "aria-invalid": hasError || void 0,
1755
- "aria-describedby": joinIds(ariaDescribedBy, descriptionId),
1837
+ "aria-describedby": joinIds(ariaDescribedBy, descriptionId, errorId),
1756
1838
  "aria-errormessage": errorId,
1757
1839
  className: cn(
1758
1840
  "ph-checkbox",
@@ -1912,6 +1994,7 @@ function Modal({
1912
1994
  footer,
1913
1995
  size = "md",
1914
1996
  className,
1997
+ bodyClassName,
1915
1998
  customLayout = false,
1916
1999
  showCloseButton = true,
1917
2000
  closeOnOutsideClick = true,
@@ -1984,7 +2067,7 @@ function Modal({
1984
2067
  }
1985
2068
  ) }) : null
1986
2069
  ] }) : null,
1987
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ph-modal-body", children }),
2070
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: cn("ph-modal-body", bodyClassName), children }),
1988
2071
  footer ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "ph-modal-footer", children: footer }) : null
1989
2072
  ] })
1990
2073
  })
@@ -2112,14 +2195,25 @@ function Table({
2112
2195
  compact = false,
2113
2196
  ribbon = false,
2114
2197
  getRowStyle,
2198
+ getRowKey,
2115
2199
  className,
2116
2200
  caption
2117
2201
  }) {
2118
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: cn("ph-table-wrap", compact && "ph-table-compact", className), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("table", { className: cn("ph-table", zebra && "ph-table-zebra", ribbon && "ph-table--ribbon"), children: [
2119
- caption && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("caption", { className: "sr-only", children: caption }),
2120
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tr", { children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: col.className, children: col.header }, col.key)) }) }),
2121
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tbody", { children: data.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tr", { style: getRowStyle == null ? void 0 : getRowStyle(row), children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: col.className, children: col.cell(row) }, col.key)) }, i)) })
2122
- ] }) });
2202
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2203
+ "div",
2204
+ {
2205
+ className: cn("ph-table-wrap", compact && "ph-table-compact", className),
2206
+ tabIndex: 0,
2207
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("table", { className: cn("ph-table", zebra && "ph-table-zebra", ribbon && "ph-table--ribbon"), children: [
2208
+ caption && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("caption", { className: "sr-only", children: caption }),
2209
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tr", { children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("th", { className: col.className, children: col.header }, col.key)) }) }),
2210
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tbody", { children: data.map((row, i) => {
2211
+ var _a;
2212
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("tr", { style: getRowStyle == null ? void 0 : getRowStyle(row), children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("td", { className: col.className, children: col.cell(row) }, col.key)) }, (_a = getRowKey == null ? void 0 : getRowKey(row, i)) != null ? _a : i);
2213
+ }) })
2214
+ ] })
2215
+ }
2216
+ );
2123
2217
  }
2124
2218
 
2125
2219
  // src/components/ui/Stat.tsx
@@ -2129,14 +2223,14 @@ var toneMap = {
2129
2223
  brand: "text-ph-brand",
2130
2224
  blue: "text-ph-blue",
2131
2225
  purple: "text-ph-purple",
2132
- warning: "text-amber-900"
2226
+ warning: "text-ph-warning"
2133
2227
  };
2134
2228
  var statMap = {
2135
2229
  default: "",
2136
2230
  brand: "",
2137
2231
  blue: "",
2138
2232
  purple: "",
2139
- warning: "border-amber-200 bg-amber-50/70"
2233
+ 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))]"
2140
2234
  };
2141
2235
  function Stat(_a) {
2142
2236
  var _b = _a, { icon, label, value, footer, tone = "default", className } = _b, props = __objRest(_b, ["icon", "label", "value", "footer", "tone", "className"]);
@@ -2156,17 +2250,17 @@ var DEFAULT_THEME_ID = "hedgehog-light";
2156
2250
  var THEMES = [
2157
2251
  {
2158
2252
  id: "hedgehog-light",
2159
- name: "HedgeHog Light",
2253
+ name: "Hedgehog Light",
2160
2254
  description: "Default Quill warm greys and orange Lemon chrome.",
2161
2255
  colorScheme: "light",
2162
- group: "HedgeHog"
2256
+ group: "Hedgehog"
2163
2257
  },
2164
2258
  {
2165
2259
  id: "hedgehog-dark",
2166
- name: "HedgeHog Dark",
2260
+ name: "Hedgehog Dark",
2167
2261
  description: "Dark app shell with HedgeHog orange accents.",
2168
2262
  colorScheme: "dark",
2169
- group: "HedgeHog"
2263
+ group: "Hedgehog"
2170
2264
  },
2171
2265
  {
2172
2266
  id: "note",
@@ -2251,6 +2345,20 @@ var THEMES = [
2251
2345
  description: "Deep plum command deck with hot pink, lime, cyan, and sunset signals.",
2252
2346
  colorScheme: "dark",
2253
2347
  group: "Malibu"
2348
+ },
2349
+ {
2350
+ id: "microsoft-light",
2351
+ name: "Microsoft Light",
2352
+ description: "Office Fluent light neutrals on white with the signature brand blue.",
2353
+ colorScheme: "light",
2354
+ group: "Microsoft"
2355
+ },
2356
+ {
2357
+ id: "microsoft-dark",
2358
+ name: "Microsoft Dark",
2359
+ description: "Office Fluent dark chrome with a bright brand-blue accent.",
2360
+ colorScheme: "dark",
2361
+ group: "Microsoft"
2254
2362
  }
2255
2363
  ];
2256
2364
  var THEME_GROUPS = Array.from(
@@ -2329,6 +2437,7 @@ function Accordion({
2329
2437
  className
2330
2438
  }) {
2331
2439
  const [openItems, setOpenItems] = (0, import_react15.useState)(new Set(defaultOpen));
2440
+ const idPrefix = (0, import_react15.useId)();
2332
2441
  const toggleItem = (id) => {
2333
2442
  setOpenItems((prev) => {
2334
2443
  const next = new Set(prev);
@@ -2343,41 +2452,58 @@ function Accordion({
2343
2452
  return next;
2344
2453
  });
2345
2454
  };
2346
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: cn("divide-y divide-ph-border rounded-xl border border-ph-border bg-ph-surface", className), children: items.map((item) => {
2347
- const isOpen = openItems.has(item.id);
2348
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "first:rounded-t-xl last:rounded-b-xl", children: [
2349
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2350
- "button",
2351
- {
2352
- type: "button",
2353
- onClick: () => toggleItem(item.id),
2354
- className: "flex w-full items-center justify-between px-5 py-4 text-left transition hover:bg-ph-muted",
2355
- children: [
2356
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "font-semibold text-ph-ink", children: item.title }),
2357
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2358
- IconChevronDown,
2359
- {
2360
- className: cn(
2361
- "h-5 w-5 text-ph-mutedtext transition-transform duration-200",
2362
- isOpen && "rotate-180"
2363
- )
2364
- }
2365
- )
2366
- ]
2367
- }
2455
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2456
+ "div",
2457
+ {
2458
+ className: cn(
2459
+ "divide-y divide-ph-border rounded-xl border border-ph-border bg-ph-surface",
2460
+ className
2368
2461
  ),
2369
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2370
- "div",
2371
- {
2372
- className: cn(
2373
- "grid transition-all duration-200",
2374
- isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
2462
+ children: items.map((item) => {
2463
+ const isOpen = openItems.has(item.id);
2464
+ const contentId = `accordion-${idPrefix}-${item.id}-content`;
2465
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className: "first:rounded-t-xl last:rounded-b-xl", children: [
2466
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
2467
+ "button",
2468
+ {
2469
+ type: "button",
2470
+ onClick: () => toggleItem(item.id),
2471
+ "aria-expanded": isOpen,
2472
+ "aria-controls": contentId,
2473
+ className: "flex w-full items-center justify-between px-5 py-4 text-left transition hover:bg-ph-muted",
2474
+ children: [
2475
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { className: "font-semibold text-ph-ink", children: item.title }),
2476
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2477
+ IconChevronDown,
2478
+ {
2479
+ className: cn(
2480
+ "h-5 w-5 text-ph-mutedtext transition-transform duration-200",
2481
+ isOpen && "rotate-180"
2482
+ )
2483
+ }
2484
+ )
2485
+ ]
2486
+ }
2375
2487
  ),
2376
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "px-5 pb-4 text-ph-subtle", children: item.content }) })
2377
- }
2378
- )
2379
- ] }, item.id);
2380
- }) });
2488
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2489
+ "div",
2490
+ {
2491
+ id: contentId,
2492
+ "aria-hidden": !isOpen,
2493
+ ref: (node) => {
2494
+ if (node) node.toggleAttribute("inert", !isOpen);
2495
+ },
2496
+ className: cn(
2497
+ "grid transition-all duration-200",
2498
+ isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
2499
+ ),
2500
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className: "px-5 pb-4 text-ph-subtle", children: item.content }) })
2501
+ }
2502
+ )
2503
+ ] }, item.id);
2504
+ })
2505
+ }
2506
+ );
2381
2507
  }
2382
2508
 
2383
2509
  // src/components/ui/SegmentedControl.tsx
@@ -2413,6 +2539,7 @@ function SegmentedControl({ options, value, onChange, className }) {
2413
2539
 
2414
2540
  // src/components/ui/CommandPalette.tsx
2415
2541
  var import_react16 = require("react");
2542
+ var Dialog2 = __toESM(require("@radix-ui/react-dialog"));
2416
2543
  var import_jsx_runtime24 = require("react/jsx-runtime");
2417
2544
  function CommandPalette({
2418
2545
  items,
@@ -2428,136 +2555,143 @@ function CommandPalette({
2428
2555
  const [query, setQuery] = (0, import_react16.useState)("");
2429
2556
  const [selectedIndex, setSelectedIndex] = (0, import_react16.useState)(0);
2430
2557
  const inputRef = (0, import_react16.useRef)(null);
2431
- const panelRef = (0, import_react16.useRef)(null);
2432
- const previousFocusRef = (0, import_react16.useRef)(null);
2558
+ const listboxRef = (0, import_react16.useRef)(null);
2559
+ const restoreFocusRef = (0, import_react16.useRef)(null);
2560
+ const generatedId = (0, import_react16.useId)();
2561
+ const listboxId = `${id != null ? id : `command-palette-${generatedId}`}-listbox`;
2433
2562
  const filtered = items.filter(
2434
2563
  (item) => item.label.toLowerCase().includes(query.toLowerCase())
2435
2564
  );
2565
+ const activeIndex = filtered.length ? Math.min(selectedIndex, filtered.length - 1) : 0;
2566
+ const activeItem = filtered[activeIndex];
2436
2567
  (0, import_react16.useEffect)(() => {
2437
- var _a;
2438
2568
  if (!isOpen) return;
2439
- previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2440
2569
  setQuery("");
2441
2570
  setSelectedIndex(0);
2442
- (_a = inputRef.current) == null ? void 0 : _a.focus();
2443
- return () => {
2444
- var _a2;
2445
- return (_a2 = previousFocusRef.current) == null ? void 0 : _a2.focus();
2446
- };
2447
2571
  }, [isOpen]);
2448
2572
  (0, import_react16.useEffect)(() => {
2449
- const handleKeyDown = (e) => {
2450
- var _a, _b;
2451
- if (!isOpen) return;
2452
- switch (e.key) {
2453
- case "ArrowDown":
2454
- if (!filtered.length) break;
2455
- e.preventDefault();
2456
- setSelectedIndex((i) => (i + 1) % filtered.length);
2457
- break;
2458
- case "ArrowUp":
2459
- if (!filtered.length) break;
2460
- e.preventDefault();
2461
- setSelectedIndex((i) => (i - 1 + filtered.length) % filtered.length);
2462
- break;
2463
- case "Enter":
2464
- e.preventDefault();
2465
- (_a = filtered[selectedIndex]) == null ? void 0 : _a.onSelect();
2466
- onClose();
2467
- break;
2468
- case "Escape":
2469
- onClose();
2470
- break;
2471
- case "Tab": {
2472
- const focusable = (_b = panelRef.current) == null ? void 0 : _b.querySelectorAll(
2473
- 'input, button, [href], [tabindex]:not([tabindex="-1"])'
2474
- );
2475
- if (!(focusable == null ? void 0 : focusable.length)) break;
2476
- const first = focusable[0];
2477
- const last = focusable[focusable.length - 1];
2478
- if (e.shiftKey && document.activeElement === first) {
2479
- e.preventDefault();
2480
- last.focus();
2481
- } else if (!e.shiftKey && document.activeElement === last) {
2482
- e.preventDefault();
2483
- first.focus();
2484
- }
2485
- break;
2486
- }
2487
- }
2488
- };
2489
- window.addEventListener("keydown", handleKeyDown);
2490
- return () => window.removeEventListener("keydown", handleKeyDown);
2491
- }, [isOpen, filtered, selectedIndex, onClose]);
2492
- if (!isOpen) return null;
2573
+ setSelectedIndex((current) => Math.min(current, Math.max(filtered.length - 1, 0)));
2574
+ }, [filtered.length]);
2575
+ (0, import_react16.useEffect)(() => {
2576
+ var _a, _b;
2577
+ if (!isOpen || !activeItem) return;
2578
+ (_b = (_a = listboxRef.current) == null ? void 0 : _a.querySelectorAll('[role="option"]')[activeIndex]) == null ? void 0 : _b.scrollIntoView({ block: "nearest" });
2579
+ }, [activeIndex, activeItem, isOpen]);
2580
+ const handleInputKeyDown = (event) => {
2581
+ switch (event.key) {
2582
+ case "ArrowDown":
2583
+ if (!filtered.length) return;
2584
+ event.preventDefault();
2585
+ setSelectedIndex((current) => (current + 1) % filtered.length);
2586
+ return;
2587
+ case "ArrowUp":
2588
+ if (!filtered.length) return;
2589
+ event.preventDefault();
2590
+ setSelectedIndex(
2591
+ (current) => (current - 1 + filtered.length) % filtered.length
2592
+ );
2593
+ return;
2594
+ case "Enter":
2595
+ if (!activeItem) return;
2596
+ event.preventDefault();
2597
+ activeItem.onSelect();
2598
+ onClose();
2599
+ return;
2600
+ default:
2601
+ return;
2602
+ }
2603
+ };
2493
2604
  return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2494
- "div",
2605
+ Dialog2.Root,
2495
2606
  {
2496
- id,
2497
- "data-test": dataTest,
2498
- className: "fixed inset-0 z-50 flex items-start justify-center bg-black/40 pt-[20vh] backdrop-blur-sm",
2499
- onMouseDown: (event) => {
2500
- if (event.target === event.currentTarget) onClose();
2607
+ open: isOpen,
2608
+ onOpenChange: (nextOpen) => {
2609
+ if (!nextOpen) onClose();
2501
2610
  },
2502
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2503
- "div",
2504
- {
2505
- ref: panelRef,
2506
- role: "dialog",
2507
- "aria-modal": "true",
2508
- "aria-label": "Command palette",
2509
- className: cn(
2510
- "w-full max-w-xl overflow-hidden rounded-xl border border-ph-border bg-ph-surface shadow-ph-md",
2511
- className
2512
- ),
2513
- children: [
2514
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
2515
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
2516
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2517
- "input",
2611
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(Dialog2.Portal, { children: [
2612
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2613
+ Dialog2.Overlay,
2614
+ {
2615
+ id,
2616
+ "data-test": dataTest,
2617
+ className: "fixed inset-0 z-50 bg-black/40 backdrop-blur-sm"
2618
+ }
2619
+ ),
2620
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2621
+ Dialog2.Content,
2622
+ {
2623
+ className: cn(
2624
+ "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",
2625
+ className
2626
+ ),
2627
+ onOpenAutoFocus: (event) => {
2628
+ var _a;
2629
+ restoreFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
2630
+ event.preventDefault();
2631
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
2632
+ },
2633
+ onCloseAutoFocus: (event) => {
2634
+ var _a;
2635
+ event.preventDefault();
2636
+ (_a = restoreFocusRef.current) == null ? void 0 : _a.focus();
2637
+ },
2638
+ children: [
2639
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(Dialog2.Title, { className: "sr-only", children: "Command palette" }),
2640
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
2641
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
2642
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2643
+ "input",
2644
+ {
2645
+ ref: inputRef,
2646
+ id: inputId,
2647
+ "data-test": inputDataTest,
2648
+ type: "text",
2649
+ role: "combobox",
2650
+ "aria-label": "Search commands",
2651
+ "aria-autocomplete": "list",
2652
+ "aria-controls": listboxId,
2653
+ "aria-expanded": "true",
2654
+ "aria-activedescendant": activeItem ? `command-${activeItem.id}` : void 0,
2655
+ value: query,
2656
+ onChange: (event) => {
2657
+ setQuery(event.target.value);
2658
+ setSelectedIndex(0);
2659
+ },
2660
+ onKeyDown: handleInputKeyDown,
2661
+ placeholder,
2662
+ className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
2663
+ }
2664
+ ),
2665
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("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" })
2666
+ ] }),
2667
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { ref: listboxRef, id: listboxId, role: "listbox", "aria-label": "Commands", className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "status", className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2668
+ "div",
2518
2669
  {
2519
- ref: inputRef,
2520
- id: inputId,
2521
- "data-test": inputDataTest,
2522
- type: "text",
2523
- "aria-label": "Search commands",
2524
- value: query,
2525
- onChange: (e) => {
2526
- setQuery(e.target.value);
2527
- setSelectedIndex(0);
2670
+ id: `command-${item.id}`,
2671
+ "data-test": `command-${item.id}`,
2672
+ role: "option",
2673
+ "aria-selected": index === activeIndex,
2674
+ onClick: () => {
2675
+ item.onSelect();
2676
+ onClose();
2528
2677
  },
2529
- placeholder,
2530
- className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
2531
- }
2532
- ),
2533
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("kbd", { className: "rounded border border-ph-border bg-ph-muted px-1.5 py-0.5 text-xs text-ph-mutedtext", children: "ESC" })
2534
- ] }),
2535
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
2536
- "button",
2537
- {
2538
- type: "button",
2539
- id: `command-${item.id}`,
2540
- "data-test": `command-${item.id}`,
2541
- onClick: () => {
2542
- item.onSelect();
2543
- onClose();
2678
+ onMouseEnter: () => setSelectedIndex(index),
2679
+ className: cn(
2680
+ "flex w-full cursor-pointer items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
2681
+ index === activeIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
2682
+ ),
2683
+ children: [
2684
+ item.icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { "aria-hidden": "true", className: "h-5 w-5", children: item.icon }),
2685
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "flex-1", children: item.label }),
2686
+ item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("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 })
2687
+ ]
2544
2688
  },
2545
- onMouseEnter: () => setSelectedIndex(index),
2546
- className: cn(
2547
- "flex w-full items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
2548
- index === selectedIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
2549
- ),
2550
- children: [
2551
- item.icon && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "h-5 w-5", children: item.icon }),
2552
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { className: "flex-1", children: item.label }),
2553
- item.shortcut && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("kbd", { className: "rounded border border-ph-border bg-ph-surface px-1.5 py-0.5 text-xs text-ph-mutedtext", children: item.shortcut })
2554
- ]
2555
- },
2556
- item.id
2557
- )) })
2558
- ]
2559
- }
2560
- )
2689
+ item.id
2690
+ )) })
2691
+ ]
2692
+ }
2693
+ )
2694
+ ] })
2561
2695
  }
2562
2696
  );
2563
2697
  }
@@ -2565,46 +2699,142 @@ function CommandPalette({
2565
2699
  // src/components/ui/Calendar.tsx
2566
2700
  var import_react17 = require("react");
2567
2701
  var import_jsx_runtime25 = require("react/jsx-runtime");
2702
+ var monthNames = [
2703
+ "January",
2704
+ "February",
2705
+ "March",
2706
+ "April",
2707
+ "May",
2708
+ "June",
2709
+ "July",
2710
+ "August",
2711
+ "September",
2712
+ "October",
2713
+ "November",
2714
+ "December"
2715
+ ];
2716
+ var weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
2717
+ var fullWeekDays = [
2718
+ "Sunday",
2719
+ "Monday",
2720
+ "Tuesday",
2721
+ "Wednesday",
2722
+ "Thursday",
2723
+ "Friday",
2724
+ "Saturday"
2725
+ ];
2726
+ function startOfDay(date) {
2727
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
2728
+ }
2729
+ function startOfMonth(date) {
2730
+ return new Date(date.getFullYear(), date.getMonth(), 1);
2731
+ }
2732
+ function isSameDay(first, second) {
2733
+ return first.getFullYear() === second.getFullYear() && first.getMonth() === second.getMonth() && first.getDate() === second.getDate();
2734
+ }
2735
+ function addDays(date, amount) {
2736
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + amount);
2737
+ }
2738
+ function addMonths(date, amount) {
2739
+ const targetMonth = new Date(date.getFullYear(), date.getMonth() + amount, 1);
2740
+ const lastDay = new Date(
2741
+ targetMonth.getFullYear(),
2742
+ targetMonth.getMonth() + 1,
2743
+ 0
2744
+ ).getDate();
2745
+ return new Date(
2746
+ targetMonth.getFullYear(),
2747
+ targetMonth.getMonth(),
2748
+ Math.min(date.getDate(), lastDay)
2749
+ );
2750
+ }
2751
+ function dateKey(date) {
2752
+ return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
2753
+ }
2754
+ function dateLabel(date) {
2755
+ return `${fullWeekDays[date.getDay()]}, ${date.getDate()} ${monthNames[date.getMonth()]} ${date.getFullYear()}`;
2756
+ }
2568
2757
  function Calendar({ value, onChange, className }) {
2569
- const [currentMonth, setCurrentMonth] = (0, import_react17.useState)(value || /* @__PURE__ */ new Date());
2570
- const today = /* @__PURE__ */ new Date();
2758
+ const [currentMonth, setCurrentMonth] = (0, import_react17.useState)(() => startOfMonth(value != null ? value : /* @__PURE__ */ new Date()));
2759
+ const [focusedDate, setFocusedDate] = (0, import_react17.useState)(() => startOfDay(value != null ? value : /* @__PURE__ */ new Date()));
2760
+ const gridRef = (0, import_react17.useRef)(null);
2761
+ const shouldFocusDateRef = (0, import_react17.useRef)(false);
2762
+ const monthLabelId = (0, import_react17.useId)();
2763
+ const today = startOfDay(/* @__PURE__ */ new Date());
2764
+ (0, import_react17.useEffect)(() => {
2765
+ if (!value) return;
2766
+ const nextDate = startOfDay(value);
2767
+ setCurrentMonth(startOfMonth(nextDate));
2768
+ setFocusedDate(nextDate);
2769
+ }, [value]);
2770
+ (0, import_react17.useEffect)(() => {
2771
+ var _a, _b;
2772
+ if (!shouldFocusDateRef.current) return;
2773
+ (_b = (_a = gridRef.current) == null ? void 0 : _a.querySelector(`[data-date="${dateKey(focusedDate)}"]`)) == null ? void 0 : _b.focus();
2774
+ shouldFocusDateRef.current = false;
2775
+ }, [currentMonth, focusedDate]);
2571
2776
  const year = currentMonth.getFullYear();
2572
2777
  const month = currentMonth.getMonth();
2573
- const firstDay = new Date(year, month, 1).getDay();
2574
- const daysInMonth = new Date(year, month + 1, 0).getDate();
2575
- const prevMonth = () => setCurrentMonth(new Date(year, month - 1, 1));
2576
- const nextMonth = () => setCurrentMonth(new Date(year, month + 1, 1));
2577
- const monthNames = [
2578
- "January",
2579
- "February",
2580
- "March",
2581
- "April",
2582
- "May",
2583
- "June",
2584
- "July",
2585
- "August",
2586
- "September",
2587
- "October",
2588
- "November",
2589
- "December"
2590
- ];
2591
- const weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
2592
- const isSelected = (day) => {
2593
- if (!value) return false;
2594
- return value.getDate() === day && value.getMonth() === month && value.getFullYear() === year;
2778
+ const changeMonth = (amount) => {
2779
+ const nextDate = addMonths(focusedDate, amount);
2780
+ setFocusedDate(nextDate);
2781
+ setCurrentMonth(startOfMonth(nextDate));
2595
2782
  };
2596
- const isToday = (day) => {
2597
- return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
2783
+ const moveFocus = (nextDate) => {
2784
+ shouldFocusDateRef.current = true;
2785
+ setFocusedDate(nextDate);
2786
+ setCurrentMonth(startOfMonth(nextDate));
2598
2787
  };
2599
- const handleSelect = (day) => {
2600
- onChange == null ? void 0 : onChange(new Date(year, month, day));
2788
+ const handleSelect = (date) => {
2789
+ setFocusedDate(date);
2790
+ onChange == null ? void 0 : onChange(startOfDay(date));
2601
2791
  };
2602
- const days = [];
2603
- for (let i = 0; i < firstDay; i++) {
2604
- days.push(null);
2792
+ const handleDayKeyDown = (event, date) => {
2793
+ let nextDate;
2794
+ switch (event.key) {
2795
+ case "ArrowLeft":
2796
+ nextDate = addDays(date, -1);
2797
+ break;
2798
+ case "ArrowRight":
2799
+ nextDate = addDays(date, 1);
2800
+ break;
2801
+ case "ArrowUp":
2802
+ nextDate = addDays(date, -7);
2803
+ break;
2804
+ case "ArrowDown":
2805
+ nextDate = addDays(date, 7);
2806
+ break;
2807
+ case "Home":
2808
+ nextDate = addDays(date, -date.getDay());
2809
+ break;
2810
+ case "End":
2811
+ nextDate = addDays(date, 6 - date.getDay());
2812
+ break;
2813
+ case "PageUp":
2814
+ nextDate = addMonths(date, event.shiftKey ? -12 : -1);
2815
+ break;
2816
+ case "PageDown":
2817
+ nextDate = addMonths(date, event.shiftKey ? 12 : 1);
2818
+ break;
2819
+ case "Enter":
2820
+ case " ":
2821
+ event.preventDefault();
2822
+ handleSelect(date);
2823
+ return;
2824
+ default:
2825
+ return;
2826
+ }
2827
+ event.preventDefault();
2828
+ moveFocus(nextDate);
2829
+ };
2830
+ const firstDay = new Date(year, month, 1).getDay();
2831
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
2832
+ const days = Array.from({ length: firstDay }, () => null);
2833
+ for (let day = 1; day <= daysInMonth; day++) {
2834
+ days.push(new Date(year, month, day));
2605
2835
  }
2606
- for (let i = 1; i <= daysInMonth; i++) {
2607
- days.push(i);
2836
+ while (days.length < 42) {
2837
+ days.push(null);
2608
2838
  }
2609
2839
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: cn("w-[280px] rounded-xl border border-ph-border bg-ph-surface p-4 shadow-ph", className), children: [
2610
2840
  /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "mb-4 flex items-center justify-between", children: [
@@ -2612,13 +2842,13 @@ function Calendar({ value, onChange, className }) {
2612
2842
  "button",
2613
2843
  {
2614
2844
  type: "button",
2615
- onClick: prevMonth,
2845
+ onClick: () => changeMonth(-1),
2616
2846
  "aria-label": "Previous month",
2617
2847
  className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
2618
2848
  children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(IconChevronLeft, { className: "h-5 w-5", "aria-hidden": true })
2619
2849
  }
2620
2850
  ),
2621
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { className: "text-sm font-semibold text-ph-ink", children: [
2851
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("span", { id: monthLabelId, "aria-live": "polite", className: "text-sm font-semibold text-ph-ink", children: [
2622
2852
  monthNames[month],
2623
2853
  " ",
2624
2854
  year
@@ -2627,27 +2857,56 @@ function Calendar({ value, onChange, className }) {
2627
2857
  "button",
2628
2858
  {
2629
2859
  type: "button",
2630
- onClick: nextMonth,
2860
+ onClick: () => changeMonth(1),
2631
2861
  "aria-label": "Next month",
2632
2862
  className: "rounded-lg p-1 text-ph-subtle transition hover:bg-ph-muted hover:text-ph-ink",
2633
2863
  children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(IconChevronRight, { className: "h-5 w-5", "aria-hidden": true })
2634
2864
  }
2635
2865
  )
2636
2866
  ] }),
2637
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "grid grid-cols-7 gap-1", children: [
2638
- weekDays.map((day) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "py-1 text-center text-xs font-medium text-ph-mutedtext", children: day }, day)),
2639
- days.map((day, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "aspect-square", children: day && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2640
- "button",
2867
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { ref: gridRef, role: "grid", "aria-labelledby": monthLabelId, children: [
2868
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { role: "row", className: "grid grid-cols-7 gap-1", children: weekDays.map((day, index) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2869
+ "div",
2641
2870
  {
2642
- type: "button",
2643
- onClick: () => handleSelect(day),
2644
- className: cn(
2645
- "flex h-full w-full items-center justify-center rounded-lg text-sm transition-colors",
2646
- 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"
2647
- ),
2871
+ role: "columnheader",
2872
+ "aria-label": fullWeekDays[index],
2873
+ className: "py-1 text-center text-xs font-medium text-ph-mutedtext",
2648
2874
  children: day
2649
- }
2650
- ) }, index))
2875
+ },
2876
+ day
2877
+ )) }),
2878
+ Array.from({ length: 6 }, (_, week) => {
2879
+ const weekDates = days.slice(week * 7, week * 7 + 7);
2880
+ if (weekDates.length === 0 || weekDates.every((date) => !date)) return null;
2881
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { role: "row", className: "grid grid-cols-7 gap-1", children: weekDates.map(
2882
+ (date, day) => date ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2883
+ "div",
2884
+ {
2885
+ role: "gridcell",
2886
+ "aria-selected": value ? isSameDay(value, date) : false,
2887
+ className: "aspect-square",
2888
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
2889
+ "button",
2890
+ {
2891
+ type: "button",
2892
+ "data-date": dateKey(date),
2893
+ "aria-label": dateLabel(date),
2894
+ "aria-current": isSameDay(today, date) ? "date" : void 0,
2895
+ tabIndex: isSameDay(focusedDate, date) ? 0 : -1,
2896
+ onClick: () => handleSelect(date),
2897
+ onKeyDown: (event) => handleDayKeyDown(event, date),
2898
+ className: cn(
2899
+ "flex h-full w-full items-center justify-center rounded-lg text-sm transition-colors",
2900
+ 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"
2901
+ ),
2902
+ children: date.getDate()
2903
+ }
2904
+ )
2905
+ },
2906
+ dateKey(date)
2907
+ ) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { role: "gridcell", "aria-hidden": "true", className: "aspect-square" }, `empty-${week}-${day}`)
2908
+ ) }, week);
2909
+ })
2651
2910
  ] })
2652
2911
  ] });
2653
2912
  }
@@ -2663,31 +2922,15 @@ function TooltipProvider({
2663
2922
  }) {
2664
2923
  return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(TooltipDelayContext.Provider, { value: delayDuration, children });
2665
2924
  }
2666
- function tooltipPosition(trigger, side, align, offset) {
2925
+ function tooltipPosition(trigger, content, side, align, offset, collisionPadding) {
2667
2926
  const horizontal = align === "start" ? trigger.left : align === "end" ? trigger.right : trigger.left + trigger.width / 2;
2668
2927
  const vertical = align === "start" ? trigger.top : align === "end" ? trigger.bottom : trigger.top + trigger.height / 2;
2669
- if (side === "top")
2670
- return {
2671
- left: horizontal,
2672
- top: trigger.top - offset,
2673
- transform: "translate(-50%, -100%)"
2674
- };
2675
- if (side === "bottom")
2676
- return {
2677
- left: horizontal,
2678
- top: trigger.bottom + offset,
2679
- transform: "translate(-50%, 0)"
2680
- };
2681
- if (side === "left")
2682
- return {
2683
- left: trigger.left - offset,
2684
- top: vertical,
2685
- transform: "translate(-100%, -50%)"
2686
- };
2928
+ 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 };
2929
+ const maxLeft = Math.max(collisionPadding, window.innerWidth - content.width - collisionPadding);
2930
+ const maxTop = Math.max(collisionPadding, window.innerHeight - content.height - collisionPadding);
2687
2931
  return {
2688
- left: trigger.right + offset,
2689
- top: vertical,
2690
- transform: "translate(0, -50%)"
2932
+ left: Math.min(Math.max(position.left, collisionPadding), maxLeft),
2933
+ top: Math.min(Math.max(position.top, collisionPadding), maxTop)
2691
2934
  };
2692
2935
  }
2693
2936
  function Tooltip({
@@ -2696,15 +2939,18 @@ function Tooltip({
2696
2939
  side = "top",
2697
2940
  align = "center",
2698
2941
  sideOffset = 7,
2942
+ collisionPadding = 8,
2699
2943
  className,
2700
2944
  open,
2701
2945
  defaultOpen = false,
2702
2946
  onOpenChange,
2703
- delayDuration
2947
+ delayDuration,
2948
+ disableHoverableContent = false
2704
2949
  }) {
2705
2950
  const providerDelay = (0, import_react18.useContext)(TooltipDelayContext);
2706
2951
  const generatedId = (0, import_react18.useId)().replace(/:/g, "");
2707
2952
  const triggerRef = (0, import_react18.useRef)(null);
2953
+ const contentRef = (0, import_react18.useRef)(null);
2708
2954
  const timerRef = (0, import_react18.useRef)(null);
2709
2955
  const [internalOpen, setInternalOpen] = (0, import_react18.useState)(defaultOpen);
2710
2956
  const [position, setPosition] = (0, import_react18.useState)(null);
@@ -2719,17 +2965,19 @@ function Tooltip({
2719
2965
  if (timerRef.current) clearTimeout(timerRef.current);
2720
2966
  timerRef.current = null;
2721
2967
  }
2722
- function updatePosition() {
2723
- if (!triggerRef.current) return;
2968
+ const updatePosition = (0, import_react18.useCallback)(() => {
2969
+ if (!triggerRef.current || !contentRef.current) return;
2724
2970
  setPosition(
2725
2971
  tooltipPosition(
2726
2972
  triggerRef.current.getBoundingClientRect(),
2973
+ contentRef.current.getBoundingClientRect(),
2727
2974
  side,
2728
2975
  align,
2729
- sideOffset
2976
+ sideOffset,
2977
+ collisionPadding
2730
2978
  )
2731
2979
  );
2732
- }
2980
+ }, [align, collisionPadding, side, sideOffset]);
2733
2981
  function show(immediate) {
2734
2982
  clearTimer();
2735
2983
  updatePosition();
@@ -2741,6 +2989,17 @@ function Tooltip({
2741
2989
  clearTimer();
2742
2990
  setOpen(false);
2743
2991
  }
2992
+ function hideFromTrigger() {
2993
+ if (disableHoverableContent) {
2994
+ hide();
2995
+ return;
2996
+ }
2997
+ clearTimer();
2998
+ timerRef.current = setTimeout(() => setOpen(false), 100);
2999
+ }
3000
+ (0, import_react18.useLayoutEffect)(() => {
3001
+ if (isOpen) updatePosition();
3002
+ }, [isOpen, updatePosition]);
2744
3003
  (0, import_react18.useEffect)(() => {
2745
3004
  if (!isOpen) return;
2746
3005
  const reposition = () => updatePosition();
@@ -2750,7 +3009,7 @@ function Tooltip({
2750
3009
  window.removeEventListener("resize", reposition);
2751
3010
  window.removeEventListener("scroll", reposition, true);
2752
3011
  };
2753
- });
3012
+ }, [isOpen, updatePosition]);
2754
3013
  (0, import_react18.useEffect)(() => () => clearTimer(), []);
2755
3014
  const describedBy = [children.props["aria-describedby"], tooltipId].filter(Boolean).join(" ");
2756
3015
  const trigger = (0, import_react18.cloneElement)(children, { "aria-describedby": describedBy });
@@ -2761,7 +3020,7 @@ function Tooltip({
2761
3020
  ref: triggerRef,
2762
3021
  className: "inline-flex",
2763
3022
  onMouseEnter: () => show(false),
2764
- onMouseLeave: hide,
3023
+ onMouseLeave: hideFromTrigger,
2765
3024
  onFocusCapture: () => show(true),
2766
3025
  onBlurCapture: hide,
2767
3026
  onKeyDown: (event) => {
@@ -2770,19 +3029,26 @@ function Tooltip({
2770
3029
  children: trigger
2771
3030
  }
2772
3031
  ),
2773
- isOpen && position && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(
3032
+ isOpen && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(
2774
3033
  /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2775
3034
  "span",
2776
3035
  {
2777
- style: __spreadValues({ position: "fixed" }, position),
3036
+ style: __spreadProps(__spreadValues({ position: "fixed" }, position), { visibility: position ? void 0 : "hidden" }),
2778
3037
  className: "pointer-events-none z-[200]",
2779
3038
  children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
2780
3039
  "span",
2781
3040
  {
3041
+ ref: contentRef,
2782
3042
  id: tooltipId,
2783
3043
  role: "tooltip",
2784
3044
  "data-side": side,
2785
- className: cn("ph-tooltip-content", className),
3045
+ className: cn(
3046
+ "ph-tooltip-content",
3047
+ !disableHoverableContent && "pointer-events-auto",
3048
+ className
3049
+ ),
3050
+ onMouseEnter: disableHoverableContent ? void 0 : clearTimer,
3051
+ onMouseLeave: disableHoverableContent ? void 0 : hide,
2786
3052
  children: content
2787
3053
  }
2788
3054
  )
@@ -2805,7 +3071,7 @@ function EmptyState({ icon, title, description, action, className }) {
2805
3071
  ),
2806
3072
  children: [
2807
3073
  icon && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "mb-4 flex h-14 w-14 items-center justify-center rounded-full bg-ph-muted text-ph-mutedtext", children: icon }),
2808
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h3", { className: "text-base font-semibold text-ph-ink", children: title }),
3074
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("h2", { className: "text-base font-semibold text-ph-ink", children: title }),
2809
3075
  description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "mt-1 max-w-sm text-sm text-ph-subtle", children: description }),
2810
3076
  action && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "mt-4", children: action })
2811
3077
  ]
@@ -3174,7 +3440,12 @@ var titleIdMap = {
3174
3440
  // src/components/ui/CollapsibleSection.tsx
3175
3441
  var import_react21 = require("react");
3176
3442
  var import_jsx_runtime34 = require("react/jsx-runtime");
3177
- function CollapsibleSection({ title, children, defaultOpen = true, id }) {
3443
+ function CollapsibleSection({
3444
+ title,
3445
+ children,
3446
+ defaultOpen = true,
3447
+ id
3448
+ }) {
3178
3449
  const [isOpen, setIsOpen] = (0, import_react21.useState)(defaultOpen);
3179
3450
  const generatedId = (0, import_react21.useId)();
3180
3451
  const contentId = `${id != null ? id : generatedId}-content`;
@@ -3207,6 +3478,9 @@ function CollapsibleSection({ title, children, defaultOpen = true, id }) {
3207
3478
  {
3208
3479
  id: contentId,
3209
3480
  "aria-hidden": !isOpen,
3481
+ ref: (node) => {
3482
+ if (node) node.toggleAttribute("inert", !isOpen);
3483
+ },
3210
3484
  className: cn(
3211
3485
  "overflow-hidden transition-all duration-300",
3212
3486
  isOpen ? "max-h-[50000px] opacity-100" : "max-h-0 opacity-0"
@@ -3218,6 +3492,7 @@ function CollapsibleSection({ title, children, defaultOpen = true, id }) {
3218
3492
  }
3219
3493
 
3220
3494
  // src/components/ui/Typography.tsx
3495
+ var import_react22 = require("react");
3221
3496
  var import_jsx_runtime35 = require("react/jsx-runtime");
3222
3497
  var toneMap2 = {
3223
3498
  default: "text-ph-ink",
@@ -3240,54 +3515,62 @@ var weightMap = {
3240
3515
  function textClass(base, tone, weight, truncate, className) {
3241
3516
  return cn(base, toneMap2[tone], weight && weightMap[weight], truncate && "truncate", className);
3242
3517
  }
3243
- function Display({
3244
- children,
3245
- tone = "default",
3246
- weight,
3247
- truncate,
3248
- className
3249
- }) {
3250
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { className: textClass("ph-hero-title", tone, weight, truncate, className), children });
3251
- }
3252
- function SectionTitle({ children, tone = "default", weight, truncate, className }) {
3253
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: textClass("ph-section-title", tone, weight, truncate, className), children });
3254
- }
3255
- function H1({ children, tone = "default", weight, truncate, className }) {
3256
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", { className: textClass("text-3xl font-bold tracking-tight md:text-4xl", tone, weight, truncate, className), children });
3257
- }
3258
- function H2({ children, tone = "default", weight, truncate, className }) {
3259
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", { className: textClass("text-2xl font-bold tracking-tight", tone, weight, truncate, className), children });
3260
- }
3261
- function H3({ children, tone = "default", weight, truncate, className }) {
3262
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h3", { className: textClass("text-xl font-semibold", tone, weight, truncate, className), children });
3263
- }
3264
- function H4({ children, tone = "default", weight, truncate, className }) {
3265
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h4", { className: textClass("text-lg font-semibold", tone, weight, truncate, className), children });
3266
- }
3267
- function H5({ children, tone = "default", weight, truncate, className }) {
3268
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h5", { className: textClass("text-base font-semibold", tone, weight, truncate, className), children });
3269
- }
3270
- function P({ children, tone = "default", weight, truncate, className }) {
3271
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: textClass("text-base leading-relaxed", tone, weight, truncate, className), children });
3272
- }
3273
- function Small({ children, tone = "default", weight, truncate, className }) {
3274
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: textClass("text-sm leading-relaxed", tone, weight, truncate, className), children });
3275
- }
3276
- function Caption({ children, tone = "muted", weight, truncate, className }) {
3277
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: textClass("text-[11px] font-medium uppercase tracking-wider", tone, weight, truncate, className), children });
3278
- }
3279
- function Overline({ children, tone = "muted", weight, truncate, className }) {
3280
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: textClass("text-[10px] font-bold uppercase tracking-[0.15em]", tone, weight, truncate, className), children });
3281
- }
3282
- function Lead({ children, tone = "subtle", weight, truncate, className }) {
3283
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: textClass("ph-lead", tone, weight, truncate, className), children });
3284
- }
3285
- function Mono({ children, tone = "default", weight, truncate, className }) {
3286
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", { className: textClass("text-sm font-mono leading-relaxed", tone, weight, truncate, className), children });
3287
- }
3288
- function Label({ children, tone = "default", weight, truncate, className }) {
3289
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", { className: textClass("text-sm font-medium", tone, weight, truncate, className), children });
3290
- }
3518
+ var Display = (0, import_react22.forwardRef)(function Display2(_a, ref) {
3519
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3520
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", __spreadProps(__spreadValues({ ref }, props), { className: textClass("ph-hero-title", tone, weight, truncate, className), children }));
3521
+ });
3522
+ var SectionTitle = (0, import_react22.forwardRef)(function SectionTitle2(_a, ref) {
3523
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3524
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", __spreadProps(__spreadValues({ ref }, props), { className: textClass("ph-section-title", tone, weight, truncate, className), children }));
3525
+ });
3526
+ var H1 = (0, import_react22.forwardRef)(function H12(_a, ref) {
3527
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3528
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h1", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-3xl font-bold tracking-tight md:text-4xl", tone, weight, truncate, className), children }));
3529
+ });
3530
+ var H2 = (0, import_react22.forwardRef)(function H22(_a, ref) {
3531
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3532
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h2", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-2xl font-bold tracking-tight", tone, weight, truncate, className), children }));
3533
+ });
3534
+ var H3 = (0, import_react22.forwardRef)(function H32(_a, ref) {
3535
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3536
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h3", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-xl font-semibold", tone, weight, truncate, className), children }));
3537
+ });
3538
+ var H4 = (0, import_react22.forwardRef)(function H42(_a, ref) {
3539
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3540
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h4", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-lg font-semibold", tone, weight, truncate, className), children }));
3541
+ });
3542
+ var H5 = (0, import_react22.forwardRef)(function H52(_a, ref) {
3543
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3544
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h5", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-base font-semibold", tone, weight, truncate, className), children }));
3545
+ });
3546
+ var P = (0, import_react22.forwardRef)(function P2(_a, ref) {
3547
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3548
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-base leading-relaxed", tone, weight, truncate, className), children }));
3549
+ });
3550
+ var Small = (0, import_react22.forwardRef)(function Small2(_a, ref) {
3551
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3552
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-sm leading-relaxed", tone, weight, truncate, className), children }));
3553
+ });
3554
+ var Caption = (0, import_react22.forwardRef)(function Caption2(_a, ref) {
3555
+ var _b = _a, { children, tone = "muted", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3556
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-[11px] font-medium uppercase tracking-wider", tone, weight, truncate, className), children }));
3557
+ });
3558
+ var Overline = (0, import_react22.forwardRef)(function Overline2(_a, ref) {
3559
+ var _b = _a, { children, tone = "muted", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3560
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-[10px] font-bold uppercase tracking-[0.15em]", tone, weight, truncate, className), children }));
3561
+ });
3562
+ var Lead = (0, import_react22.forwardRef)(function Lead2(_a, ref) {
3563
+ var _b = _a, { children, tone = "subtle", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3564
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", __spreadProps(__spreadValues({ ref }, props), { className: textClass("ph-lead", tone, weight, truncate, className), children }));
3565
+ });
3566
+ var Mono = (0, import_react22.forwardRef)(function Mono2(_a, ref) {
3567
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3568
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("code", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-sm font-mono leading-relaxed", tone, weight, truncate, className), children }));
3569
+ });
3570
+ var Label = (0, import_react22.forwardRef)(function Label2(_a, ref) {
3571
+ var _b = _a, { children, tone = "default", weight, truncate, className } = _b, props = __objRest(_b, ["children", "tone", "weight", "truncate", "className"]);
3572
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("label", __spreadProps(__spreadValues({ ref }, props), { className: textClass("text-sm font-medium", tone, weight, truncate, className), children }));
3573
+ });
3291
3574
 
3292
3575
  // src/components/ui/Avatar.tsx
3293
3576
  var import_jsx_runtime36 = require("react/jsx-runtime");
@@ -3299,9 +3582,9 @@ var sizeMap4 = {
3299
3582
  xl: "h-24 w-24 text-3xl"
3300
3583
  };
3301
3584
  var statusMap = {
3302
- online: "bg-emerald-500",
3585
+ online: "bg-ph-success",
3303
3586
  offline: "bg-ph-mutedtext",
3304
- away: "bg-amber-400",
3587
+ away: "bg-ph-warning",
3305
3588
  busy: "bg-ph-danger"
3306
3589
  };
3307
3590
  function Avatar(_a) {
@@ -3337,8 +3620,10 @@ function Avatar(_a) {
3337
3620
  status && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3338
3621
  "span",
3339
3622
  {
3623
+ role: "img",
3624
+ "aria-label": `${status} status`,
3340
3625
  className: cn(
3341
- "absolute bottom-0 right-1 h-2.5 w-2.5 rounded-full border-2 border-white",
3626
+ "absolute bottom-0 right-1 h-2.5 w-2.5 rounded-full border-2 border-ph-surface",
3342
3627
  statusMap[status]
3343
3628
  )
3344
3629
  }
@@ -3365,6 +3650,7 @@ function AvatarGroup(_a) {
3365
3650
  }
3366
3651
 
3367
3652
  // src/components/ui/Progress.tsx
3653
+ var import_react23 = require("react");
3368
3654
  var import_jsx_runtime37 = require("react/jsx-runtime");
3369
3655
  var sizeMap5 = {
3370
3656
  sm: "h-1",
@@ -3379,7 +3665,9 @@ function Progress(_a) {
3379
3665
  label,
3380
3666
  showPercentage = false,
3381
3667
  size = "md",
3382
- className
3668
+ className,
3669
+ "aria-label": ariaLabel,
3670
+ "aria-labelledby": ariaLabelledBy
3383
3671
  } = _b, props = __objRest(_b, [
3384
3672
  "value",
3385
3673
  "max",
@@ -3387,12 +3675,17 @@ function Progress(_a) {
3387
3675
  "label",
3388
3676
  "showPercentage",
3389
3677
  "size",
3390
- "className"
3678
+ "className",
3679
+ "aria-label",
3680
+ "aria-labelledby"
3391
3681
  ]);
3392
- const percentage = Math.min(100, Math.max(0, value / max * 100));
3682
+ const labelId = (0, import_react23.useId)();
3683
+ const safeMax = Number.isFinite(max) && max > 0 ? max : 100;
3684
+ const safeValue = Number.isFinite(value) ? Math.min(safeMax, Math.max(0, value)) : 0;
3685
+ const percentage = safeValue / safeMax * 100;
3393
3686
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", __spreadProps(__spreadValues({ className: cn("w-full", className) }, props), { children: [
3394
3687
  (label || showPercentage) && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "mb-1.5 flex justify-between text-sm text-ph-subtle", children: [
3395
- label && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: label }),
3688
+ label && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { id: labelId, children: label }),
3396
3689
  showPercentage && /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("span", { className: "tabular-nums", children: [
3397
3690
  Math.round(percentage),
3398
3691
  "%"
@@ -3404,18 +3697,20 @@ function Progress(_a) {
3404
3697
  className: cn("ph-progress-bar", color),
3405
3698
  style: { width: `${percentage}%` },
3406
3699
  role: "progressbar",
3407
- "aria-valuenow": value,
3700
+ "aria-valuenow": safeValue,
3408
3701
  "aria-valuemin": 0,
3409
- "aria-valuemax": max
3702
+ "aria-valuemax": safeMax,
3703
+ "aria-label": label ? void 0 : ariaLabel != null ? ariaLabel : "Progress",
3704
+ "aria-labelledby": label ? ariaLabelledBy != null ? ariaLabelledBy : labelId : ariaLabelledBy
3410
3705
  }
3411
3706
  ) })
3412
3707
  ] }));
3413
3708
  }
3414
3709
 
3415
3710
  // src/components/ui/Link.tsx
3416
- var import_react22 = require("react");
3711
+ var import_react24 = require("react");
3417
3712
  var import_jsx_runtime38 = require("react/jsx-runtime");
3418
- var Link = (0, import_react22.forwardRef)(function Link2(_a, ref) {
3713
+ var Link = (0, import_react24.forwardRef)(function Link2(_a, ref) {
3419
3714
  var _b = _a, {
3420
3715
  className,
3421
3716
  disabled = false,
@@ -3495,9 +3790,9 @@ function Dot(_a) {
3495
3790
  Dot.displayName = "Dot";
3496
3791
 
3497
3792
  // src/components/ui/Chip.tsx
3498
- var import_react23 = require("react");
3793
+ var import_react25 = require("react");
3499
3794
  var import_jsx_runtime41 = require("react/jsx-runtime");
3500
- var Chip = (0, import_react23.forwardRef)(function Chip2(_a, ref) {
3795
+ var Chip = (0, import_react25.forwardRef)(function Chip2(_a, ref) {
3501
3796
  var _b = _a, {
3502
3797
  selected = false,
3503
3798
  onRemove,