@xenide-io/the-old-ui-theme 0.5.2 → 0.5.4

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 (59) hide show
  1. package/README.md +47 -34
  2. package/dist/{index-Od4pIP4F.d.mts → Chip-C5hRFAhe.d.mts} +10 -606
  3. package/dist/{index-Od4pIP4F.d.ts → Chip-C5hRFAhe.d.ts} +10 -606
  4. package/dist/{chunk-G53YLHVE.mjs → chunk-E5ZBQYEX.mjs} +59 -9
  5. package/dist/{chunk-RZXHZWUB.mjs → chunk-SBBKXV35.mjs} +174 -222
  6. package/dist/index.d.mts +4 -80
  7. package/dist/index.d.ts +4 -80
  8. package/dist/index.js +562 -3746
  9. package/dist/index.mjs +3 -765
  10. package/dist/suite.d.mts +56 -25
  11. package/dist/suite.d.ts +56 -25
  12. package/dist/suite.js +248 -107
  13. package/dist/suite.mjs +217 -105
  14. package/dist/ui.d.mts +608 -2
  15. package/dist/ui.d.ts +608 -2
  16. package/dist/ui.js +232 -230
  17. package/dist/ui.mjs +2 -2
  18. package/package.json +2 -6
  19. package/scripts/install-theme-dev.sh +60 -0
  20. package/scripts/sync-posthog-icons.mjs +75 -0
  21. package/src/app/globals.css +1 -0
  22. package/src/components/ui/Chip.tsx +36 -18
  23. package/src/components/ui/CommandPalette.test.tsx +41 -0
  24. package/src/components/ui/CommandPalette.tsx +58 -9
  25. package/src/components/ui/DropdownMenu.tsx +50 -11
  26. package/src/components/ui/SegmentedControl.tsx +2 -1
  27. package/src/components/ui/SettingsLayout.tsx +19 -5
  28. package/src/components/ui/ThemeSwitcher.tsx +12 -3
  29. package/src/components/ui/interaction-primitives.test.tsx +52 -0
  30. package/src/styles/suite-skin.css +53 -1
  31. package/src/styles/themes.css +445 -1656
  32. package/src/suite/components/app-switcher.tsx +32 -25
  33. package/src/suite/components/command-palette-host.tsx +20 -8
  34. package/src/suite/components/suite-app-layout.tsx +31 -10
  35. package/src/suite/components/suite-bottom-nav.tsx +23 -18
  36. package/src/suite/components/suite-layout.test.tsx +44 -0
  37. package/src/suite/components/suite-layout.tsx +3 -3
  38. package/src/suite/components/suite-mobile-drawer.tsx +12 -0
  39. package/src/suite/components/suite-mobile-header.tsx +15 -9
  40. package/src/suite/components/suite-notification-bell.tsx +23 -11
  41. package/src/suite/components/suite-settings-mobile-nav.tsx +2 -0
  42. package/src/suite/components/suite-sidebar.tsx +54 -43
  43. package/src/suite/components/suite-user-menu.tsx +54 -26
  44. package/src/suite/components/today-page-frame.tsx +1 -1
  45. package/src/suite/icons/app-accents.ts +38 -43
  46. package/src/suite/icons/glyph-parts.tsx +16 -9
  47. package/src/suite/icons/glyphs.ts +130 -99
  48. package/src/suite/lib/apps.ts +1 -1
  49. package/src/suite/lib/injected.ts +12 -11
  50. package/src/suite/lib/use-sidebar-width.ts +23 -8
  51. package/src/components/charts/index.ts +0 -9
  52. package/src/components/charts/quill/BarChart.tsx +0 -85
  53. package/src/components/charts/quill/FunnelChart.tsx +0 -49
  54. package/src/components/charts/quill/InsightShell.tsx +0 -27
  55. package/src/components/charts/quill/MetricCard.tsx +0 -44
  56. package/src/components/charts/quill/PieChart.tsx +0 -81
  57. package/src/components/charts/quill/Sparkline.tsx +0 -57
  58. package/src/components/charts/quill/TimeSeriesLineChart.tsx +0 -62
  59. package/src/components/charts/quill/index.ts +0 -9
@@ -596,7 +596,14 @@ function DropdownContent({
596
596
  sticky: "partial",
597
597
  children: [
598
598
  children,
599
- /* @__PURE__ */ jsx5(DropdownPrimitive.Arrow, { className: "ph-dropdown-arrow", width: 12, height: 6 })
599
+ /* @__PURE__ */ jsx5(
600
+ DropdownPrimitive.Arrow,
601
+ {
602
+ className: "ph-dropdown-arrow",
603
+ width: 12,
604
+ height: 6
605
+ }
606
+ )
600
607
  ]
601
608
  }
602
609
  ) });
@@ -604,6 +611,8 @@ function DropdownContent({
604
611
  function DropdownMenu(_a) {
605
612
  var _b = _a, {
606
613
  trigger,
614
+ triggerId,
615
+ triggerDataTest,
607
616
  children,
608
617
  align,
609
618
  side,
@@ -621,6 +630,8 @@ function DropdownMenu(_a) {
621
630
  disabled
622
631
  } = _b, props = __objRest(_b, [
623
632
  "trigger",
633
+ "triggerId",
634
+ "triggerDataTest",
624
635
  "children",
625
636
  "align",
626
637
  "side",
@@ -645,7 +656,17 @@ function DropdownMenu(_a) {
645
656
  onOpenChange,
646
657
  modal,
647
658
  children: [
648
- /* @__PURE__ */ jsx5(DropdownPrimitive.Trigger, { asChild: true, disabled, children: /* @__PURE__ */ jsx5("button", { type: "button", className: "ph-dropdown-trigger", "aria-label": ariaLabel, children: trigger }) }),
659
+ /* @__PURE__ */ jsx5(DropdownPrimitive.Trigger, { asChild: true, disabled, children: /* @__PURE__ */ jsx5(
660
+ "button",
661
+ {
662
+ type: "button",
663
+ id: triggerId,
664
+ "data-test": triggerDataTest,
665
+ className: "ph-dropdown-trigger",
666
+ "aria-label": ariaLabel,
667
+ children: trigger
668
+ }
669
+ ) }),
649
670
  /* @__PURE__ */ jsx5(
650
671
  DropdownContent,
651
672
  {
@@ -733,7 +754,15 @@ function DropdownButton(_a) {
733
754
  split && "ph-btn-split"
734
755
  ),
735
756
  "aria-label": ariaLabel,
736
- children: /* @__PURE__ */ jsx5(ButtonChrome, { label, icon, sideIcon: trailing, split })
757
+ children: /* @__PURE__ */ jsx5(
758
+ ButtonChrome,
759
+ {
760
+ label,
761
+ icon,
762
+ sideIcon: trailing,
763
+ split
764
+ }
765
+ )
737
766
  }
738
767
  ) }),
739
768
  /* @__PURE__ */ jsx5(
@@ -754,7 +783,15 @@ function DropdownButton(_a) {
754
783
  ) }));
755
784
  }
756
785
  function DropdownItem(_a) {
757
- var _b = _a, { className, children, disabled } = _b, props = __objRest(_b, ["className", "children", "disabled"]);
786
+ var _b = _a, {
787
+ className,
788
+ children,
789
+ disabled
790
+ } = _b, props = __objRest(_b, [
791
+ "className",
792
+ "children",
793
+ "disabled"
794
+ ]);
758
795
  return /* @__PURE__ */ jsx5(DropdownPrimitive.Item, { asChild: true, disabled, children: /* @__PURE__ */ jsx5(
759
796
  "button",
760
797
  __spreadProps(__spreadValues({
@@ -770,11 +807,24 @@ function DropdownRadioGroup(props) {
770
807
  return /* @__PURE__ */ jsx5(DropdownPrimitive.RadioGroup, __spreadValues({}, props));
771
808
  }
772
809
  function DropdownRadioItem(_a) {
773
- var _b = _a, { className, children } = _b, props = __objRest(_b, ["className", "children"]);
774
- return /* @__PURE__ */ jsxs3(DropdownPrimitive.RadioItem, __spreadProps(__spreadValues({ className: cn("ph-dropdown-item ph-dropdown-radio-item", className) }, props), { children: [
775
- /* @__PURE__ */ jsx5("span", { className: "ph-dropdown-item-indicator", "aria-hidden": true, children: /* @__PURE__ */ jsx5(DropdownPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx5(IconCheck, { className: "h-3.5 w-3.5" }) }) }),
776
- /* @__PURE__ */ jsx5("span", { children })
777
- ] }));
810
+ var _b = _a, {
811
+ className,
812
+ children
813
+ } = _b, props = __objRest(_b, [
814
+ "className",
815
+ "children"
816
+ ]);
817
+ return /* @__PURE__ */ jsxs3(
818
+ DropdownPrimitive.RadioItem,
819
+ __spreadProps(__spreadValues({
820
+ className: cn("ph-dropdown-item ph-dropdown-radio-item", className)
821
+ }, props), {
822
+ children: [
823
+ /* @__PURE__ */ jsx5("span", { className: "ph-dropdown-item-indicator", "aria-hidden": true, children: /* @__PURE__ */ jsx5(DropdownPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx5(IconCheck, { className: "h-3.5 w-3.5" }) }) }),
824
+ /* @__PURE__ */ jsx5("span", { children })
825
+ ]
826
+ })
827
+ );
778
828
  }
779
829
 
780
830
  // src/components/ui/Tooltip.tsx
@@ -19,7 +19,7 @@ import {
19
19
  IconStar,
20
20
  IconTuning,
21
21
  cn
22
- } from "./chunk-G53YLHVE.mjs";
22
+ } from "./chunk-E5ZBQYEX.mjs";
23
23
  import {
24
24
  __objRest,
25
25
  __spreadProps,
@@ -553,7 +553,12 @@ function SettingsNav(_a) {
553
553
  "a",
554
554
  {
555
555
  href: item.href,
556
- className: cn("ph-settings-nav__item", item.active && "ph-settings-nav__item--active"),
556
+ id: `settings-nav-${item.id}`,
557
+ "data-test": `settings-nav-${item.id}`,
558
+ className: cn(
559
+ "ph-settings-nav__item",
560
+ item.active && "ph-settings-nav__item--active"
561
+ ),
557
562
  "aria-current": item.active ? "page" : void 0,
558
563
  children: [
559
564
  item.icon ? /* @__PURE__ */ jsx9("span", { className: "ph-settings-nav__icon", children: item.icon }) : null,
@@ -1471,177 +1476,65 @@ var THEMES = [
1471
1476
  colorScheme: "dark",
1472
1477
  group: "HedgeHog"
1473
1478
  },
1474
- {
1475
- id: "catppuccin-light",
1476
- name: "Catppuccin Light",
1477
- description: "Catppuccin Latte \u2014 soft pastels and mauve accent.",
1478
- colorScheme: "light",
1479
- group: "Catppuccin"
1480
- },
1481
- {
1482
- id: "catppuccin-dark",
1483
- name: "Catppuccin Dark",
1484
- description: "Catppuccin Mocha \u2014 deep base and lavender peach.",
1485
- colorScheme: "dark",
1486
- group: "Catppuccin"
1487
- },
1488
- {
1489
- id: "sheets",
1490
- name: "Sheets",
1491
- description: "Spreadsheet green on office neutrals.",
1492
- colorScheme: "light",
1493
- group: "Productivity"
1494
- },
1495
- {
1496
- id: "sheets-dark",
1497
- name: "Sheets Dark",
1498
- description: "Dark shell with spreadsheet green accent.",
1499
- colorScheme: "dark",
1500
- group: "Productivity"
1501
- },
1502
1479
  {
1503
1480
  id: "note",
1504
- name: "Note",
1481
+ name: "Note Light",
1505
1482
  description: "Notebook purple on lavender-white chrome.",
1506
1483
  colorScheme: "light",
1507
- group: "Productivity"
1484
+ group: "Note"
1508
1485
  },
1509
1486
  {
1510
1487
  id: "note-dark",
1511
1488
  name: "Note Dark",
1512
1489
  description: "Dark notebook purple \u2014 night reading mode.",
1513
1490
  colorScheme: "dark",
1514
- group: "Productivity"
1515
- },
1516
- {
1517
- id: "presentation",
1518
- name: "Presentation",
1519
- description: "Orange-red on office neutrals.",
1520
- colorScheme: "light",
1521
- group: "Productivity"
1522
- },
1523
- {
1524
- id: "presentation-dark",
1525
- name: "Presentation Dark",
1526
- description: "Dark shell with orange-red accent.",
1527
- colorScheme: "dark",
1528
- group: "Productivity"
1529
- },
1530
- {
1531
- id: "socials",
1532
- name: "Socials",
1533
- description: "Meta blue accent on familiar social greys.",
1534
- colorScheme: "light",
1535
- group: "Social"
1536
- },
1537
- {
1538
- id: "socials-dark",
1539
- name: "Socials Dark",
1540
- description: "Social dark mode \u2014 #18191A base and Meta blue.",
1541
- colorScheme: "dark",
1542
- group: "Social"
1543
- },
1544
- {
1545
- id: "chats-light",
1546
- name: "Chats Light",
1547
- description: "Aubergine brand on clean workspace neutrals.",
1548
- colorScheme: "light",
1549
- group: "Chats"
1550
- },
1551
- {
1552
- id: "chats-dark",
1553
- name: "Chats Dark",
1554
- description: "Dark sidebar \u2014 #1A1D21 base and green highlights.",
1555
- colorScheme: "dark",
1556
- group: "Chats"
1557
- },
1558
- {
1559
- id: "xenide-light",
1560
- name: "Xenide Light",
1561
- description: "xenide.io light \u2014 Excel green + purple on neutral greys.",
1562
- colorScheme: "light",
1563
- group: "Xenide"
1564
- },
1565
- {
1566
- id: "xenide-dark",
1567
- name: "Xenide Dark",
1568
- description: "xenide.io dark \u2014 #0A0A0F base, emerald green + violet.",
1569
- colorScheme: "dark",
1570
- group: "Xenide"
1571
- },
1572
- {
1573
- id: "bikini-bottom",
1574
- name: "Bikini Bottom",
1575
- description: "SpongeBob palette \u2014 ocean canvas, readable surfaces, character accents.",
1576
- colorScheme: "light",
1577
- group: "Fun"
1578
- },
1579
- {
1580
- id: "bikini-bottom-dark",
1581
- name: "Bikini Bottom Dark",
1582
- description: "Bikini Bottom at night \u2014 deep ocean with neon character accents.",
1583
- colorScheme: "dark",
1584
- group: "Fun"
1491
+ group: "Note"
1585
1492
  },
1586
1493
  {
1587
1494
  id: "turtletime",
1588
- name: "TurtleTime",
1495
+ name: "TurtleTime Light",
1589
1496
  description: "Turtle mascot palette \u2014 shell orange, leaf green, and warm cream.",
1590
1497
  colorScheme: "light",
1591
- group: "Fun"
1498
+ group: "TurtleTime"
1592
1499
  },
1593
1500
  {
1594
1501
  id: "turtletime-dark",
1595
1502
  name: "TurtleTime Dark",
1596
1503
  description: "TurtleTime after dusk \u2014 dark olive shell with bright orange clock accents.",
1597
1504
  colorScheme: "dark",
1598
- group: "Fun"
1599
- },
1600
- {
1601
- id: "github-light",
1602
- name: "GitHub Light",
1603
- description: "GitHub Primer \u2014 #f6f8fa canvas and emphasis blue accents.",
1604
- colorScheme: "light",
1605
- group: "GitHub"
1606
- },
1607
- {
1608
- id: "github-dark",
1609
- name: "GitHub Dark",
1610
- description: "GitHub dark dimmed \u2014 #0d1117 base and #4493f8 links.",
1611
- colorScheme: "dark",
1612
- group: "GitHub"
1505
+ group: "TurtleTime"
1613
1506
  },
1614
1507
  {
1615
1508
  id: "rosepine-light",
1616
- name: "Ros\xE9 Pine Dawn",
1509
+ name: "Ros\xE9 Pine Light",
1617
1510
  description: "Ros\xE9 Pine Dawn \u2014 warm paper base with muted iris accents.",
1618
1511
  colorScheme: "light",
1619
1512
  group: "Ros\xE9 Pine"
1620
1513
  },
1621
1514
  {
1622
1515
  id: "rosepine-dark",
1623
- name: "Ros\xE9 Pine",
1516
+ name: "Ros\xE9 Pine Dark",
1624
1517
  description: "Ros\xE9 Pine Main \u2014 moonlit base with iris and love accents.",
1625
1518
  colorScheme: "dark",
1626
1519
  group: "Ros\xE9 Pine"
1627
1520
  },
1628
1521
  {
1629
- id: "notion",
1630
- name: "Notion",
1631
- description: "Notion light \u2014 warm off-white canvas, Notion blue accent, signature dark text.",
1522
+ id: "kraken-light",
1523
+ name: "Kraken Light",
1524
+ description: "Medium-inspired warm paper, editorial black actions, and publication yellow.",
1632
1525
  colorScheme: "light",
1633
- group: "Productivity"
1526
+ group: "Kraken"
1634
1527
  },
1635
1528
  {
1636
- id: "notion-dark",
1637
- name: "Notion Dark",
1638
- description: "Notion dark mode \u2014 dark charcoal canvas with blue accent and clean typography.",
1529
+ id: "kraken-dark",
1530
+ name: "Kraken Dark",
1531
+ description: "Medium-inspired night reading canvas with white actions and publication yellow.",
1639
1532
  colorScheme: "dark",
1640
- group: "Productivity"
1533
+ group: "Kraken"
1641
1534
  },
1642
1535
  {
1643
1536
  id: "deepsea-light",
1644
- name: "Tokyo Night Day",
1537
+ name: "Tokyo Day",
1645
1538
  description: "Tokyo Night Day \u2014 soft bluish greys with vivid blue and purple accents.",
1646
1539
  colorScheme: "light",
1647
1540
  group: "Tokyo Night"
@@ -1654,21 +1547,23 @@ var THEMES = [
1654
1547
  group: "Tokyo Night"
1655
1548
  },
1656
1549
  {
1657
- id: "kraken-light",
1658
- name: "Kraken Light",
1659
- description: "Medium-inspired warm paper, editorial black actions, and classic publication yellow.",
1550
+ id: "malibu-light",
1551
+ name: "Malibu Light",
1552
+ description: "Sun-bleached GTA San Andreas palette with hot pink, sunset orange, and lime signals.",
1660
1553
  colorScheme: "light",
1661
- group: "Kraken"
1554
+ group: "Malibu"
1662
1555
  },
1663
1556
  {
1664
- id: "kraken-dark",
1665
- name: "Kraken Dark",
1666
- description: "Medium-inspired night reading canvas with white actions and classic publication yellow.",
1557
+ id: "malibu-dark",
1558
+ name: "Malibu Dark",
1559
+ description: "Deep plum command deck with hot pink, lime, cyan, and sunset signals.",
1667
1560
  colorScheme: "dark",
1668
- group: "Kraken"
1561
+ group: "Malibu"
1669
1562
  }
1670
1563
  ];
1671
- var THEME_GROUPS = Array.from(new Set(THEMES.map((theme) => theme.group)));
1564
+ var THEME_GROUPS = Array.from(
1565
+ new Set(THEMES.map((theme) => theme.group))
1566
+ );
1672
1567
  function isThemeId(value) {
1673
1568
  return THEMES.some((theme) => theme.id === value);
1674
1569
  }
@@ -1679,7 +1574,7 @@ function getTheme(id) {
1679
1574
  // src/themes/init-theme.ts
1680
1575
  var STORAGE_KEY = "ph-theme";
1681
1576
  var VALID_THEMES = THEMES.map((theme) => theme.id);
1682
- var THEME_INIT_SCRIPT = `(function(){try{var k="${STORAGE_KEY}",d="${DEFAULT_THEME_ID}",v=${JSON.stringify(VALID_THEMES)},t=localStorage.getItem(k);if(t==="xenide")t="xenide-light";if(!t||v.indexOf(t)<0)t=d;document.documentElement.setAttribute("data-theme",t)}catch(e){document.documentElement.setAttribute("data-theme","${DEFAULT_THEME_ID}")}})();`;
1577
+ var THEME_INIT_SCRIPT = `(function(){try{var k="${STORAGE_KEY}",d="${DEFAULT_THEME_ID}",v=${JSON.stringify(VALID_THEMES)},t=localStorage.getItem(k);if(!t||v.indexOf(t)<0)t=d;document.documentElement.setAttribute("data-theme",t)}catch(e){document.documentElement.setAttribute("data-theme","${DEFAULT_THEME_ID}")}})();`;
1683
1578
  function persistTheme(themeId) {
1684
1579
  if (typeof window === "undefined") {
1685
1580
  return;
@@ -1695,9 +1590,6 @@ function readStoredTheme() {
1695
1590
  return DEFAULT_THEME_ID;
1696
1591
  }
1697
1592
  const stored = localStorage.getItem(STORAGE_KEY);
1698
- if (stored === "xenide") {
1699
- return "xenide-light";
1700
- }
1701
1593
  return stored && isThemeId(stored) ? stored : DEFAULT_THEME_ID;
1702
1594
  }
1703
1595
 
@@ -1723,7 +1615,7 @@ function ThemeManager({ children }) {
1723
1615
  import { useEffect, useState } from "react";
1724
1616
  import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
1725
1617
  function ThemeSwitcher({ className }) {
1726
- const [themeId, setThemeId] = useState("hedgehog-light");
1618
+ const [themeId, setThemeId] = useState(DEFAULT_THEME_ID);
1727
1619
  useEffect(() => {
1728
1620
  const id = readStoredTheme();
1729
1621
  persistTheme(id);
@@ -1874,9 +1766,10 @@ function SegmentedControl({ options, value, onChange, className }) {
1874
1766
  "button",
1875
1767
  {
1876
1768
  type: "button",
1769
+ "aria-pressed": value === option.value,
1877
1770
  onClick: () => onChange(option.value),
1878
1771
  className: cn(
1879
- "relative flex items-center gap-1.5 rounded-md px-3.5 py-1.5 text-sm font-medium transition-all",
1772
+ "relative flex min-h-11 items-center gap-1.5 rounded-md px-3.5 py-1.5 text-sm font-medium transition-all sm:min-h-9",
1880
1773
  value === option.value ? "bg-ph-surface text-ph-ink shadow-ph" : "text-ph-subtle hover:text-ph-ink"
1881
1774
  ),
1882
1775
  children: [
@@ -1898,32 +1791,44 @@ function CommandPalette({
1898
1791
  isOpen,
1899
1792
  onClose,
1900
1793
  placeholder = "Type a command or search...",
1901
- className
1794
+ className,
1795
+ id,
1796
+ dataTest,
1797
+ inputId,
1798
+ inputDataTest
1902
1799
  }) {
1903
1800
  const [query, setQuery] = useState3("");
1904
1801
  const [selectedIndex, setSelectedIndex] = useState3(0);
1905
1802
  const inputRef = useRef2(null);
1803
+ const panelRef = useRef2(null);
1804
+ const previousFocusRef = useRef2(null);
1906
1805
  const filtered = items.filter(
1907
1806
  (item) => item.label.toLowerCase().includes(query.toLowerCase())
1908
1807
  );
1909
1808
  useEffect2(() => {
1910
1809
  var _a;
1911
- if (isOpen) {
1912
- setQuery("");
1913
- setSelectedIndex(0);
1914
- (_a = inputRef.current) == null ? void 0 : _a.focus();
1915
- }
1810
+ if (!isOpen) return;
1811
+ previousFocusRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
1812
+ setQuery("");
1813
+ setSelectedIndex(0);
1814
+ (_a = inputRef.current) == null ? void 0 : _a.focus();
1815
+ return () => {
1816
+ var _a2;
1817
+ return (_a2 = previousFocusRef.current) == null ? void 0 : _a2.focus();
1818
+ };
1916
1819
  }, [isOpen]);
1917
1820
  useEffect2(() => {
1918
1821
  const handleKeyDown = (e) => {
1919
- var _a;
1822
+ var _a, _b;
1920
1823
  if (!isOpen) return;
1921
1824
  switch (e.key) {
1922
1825
  case "ArrowDown":
1826
+ if (!filtered.length) break;
1923
1827
  e.preventDefault();
1924
1828
  setSelectedIndex((i) => (i + 1) % filtered.length);
1925
1829
  break;
1926
1830
  case "ArrowUp":
1831
+ if (!filtered.length) break;
1927
1832
  e.preventDefault();
1928
1833
  setSelectedIndex((i) => (i - 1 + filtered.length) % filtered.length);
1929
1834
  break;
@@ -1935,62 +1840,98 @@ function CommandPalette({
1935
1840
  case "Escape":
1936
1841
  onClose();
1937
1842
  break;
1843
+ case "Tab": {
1844
+ const focusable = (_b = panelRef.current) == null ? void 0 : _b.querySelectorAll(
1845
+ 'input, button, [href], [tabindex]:not([tabindex="-1"])'
1846
+ );
1847
+ if (!(focusable == null ? void 0 : focusable.length)) break;
1848
+ const first = focusable[0];
1849
+ const last = focusable[focusable.length - 1];
1850
+ if (e.shiftKey && document.activeElement === first) {
1851
+ e.preventDefault();
1852
+ last.focus();
1853
+ } else if (!e.shiftKey && document.activeElement === last) {
1854
+ e.preventDefault();
1855
+ first.focus();
1856
+ }
1857
+ break;
1858
+ }
1938
1859
  }
1939
1860
  };
1940
1861
  window.addEventListener("keydown", handleKeyDown);
1941
1862
  return () => window.removeEventListener("keydown", handleKeyDown);
1942
1863
  }, [isOpen, filtered, selectedIndex, onClose]);
1943
1864
  if (!isOpen) return null;
1944
- return /* @__PURE__ */ jsx26("div", { className: "fixed inset-0 z-50 flex items-start justify-center bg-black/40 pt-[20vh] backdrop-blur-sm", children: /* @__PURE__ */ jsxs23(
1865
+ return /* @__PURE__ */ jsx26(
1945
1866
  "div",
1946
1867
  {
1947
- className: cn(
1948
- "w-full max-w-xl overflow-hidden rounded-xl border border-ph-border bg-ph-surface shadow-ph-md",
1949
- className
1950
- ),
1951
- children: [
1952
- /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
1953
- /* @__PURE__ */ jsx26(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
1954
- /* @__PURE__ */ jsx26(
1955
- "input",
1956
- {
1957
- ref: inputRef,
1958
- type: "text",
1959
- value: query,
1960
- onChange: (e) => {
1961
- setQuery(e.target.value);
1962
- setSelectedIndex(0);
1963
- },
1964
- placeholder,
1965
- className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
1966
- }
1868
+ id,
1869
+ "data-test": dataTest,
1870
+ className: "fixed inset-0 z-50 flex items-start justify-center bg-black/40 pt-[20vh] backdrop-blur-sm",
1871
+ onMouseDown: (event) => {
1872
+ if (event.target === event.currentTarget) onClose();
1873
+ },
1874
+ children: /* @__PURE__ */ jsxs23(
1875
+ "div",
1876
+ {
1877
+ ref: panelRef,
1878
+ role: "dialog",
1879
+ "aria-modal": "true",
1880
+ "aria-label": "Command palette",
1881
+ className: cn(
1882
+ "w-full max-w-xl overflow-hidden rounded-xl border border-ph-border bg-ph-surface shadow-ph-md",
1883
+ className
1967
1884
  ),
1968
- /* @__PURE__ */ jsx26("kbd", { className: "rounded border border-ph-border bg-ph-muted px-1.5 py-0.5 text-xs text-ph-mutedtext", children: "ESC" })
1969
- ] }),
1970
- /* @__PURE__ */ jsx26("div", { className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ jsx26("div", { className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ jsxs23(
1971
- "button",
1972
- {
1973
- type: "button",
1974
- onClick: () => {
1975
- item.onSelect();
1976
- onClose();
1977
- },
1978
- onMouseEnter: () => setSelectedIndex(index),
1979
- className: cn(
1980
- "flex w-full items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
1981
- index === selectedIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
1982
- ),
1983
- children: [
1984
- item.icon && /* @__PURE__ */ jsx26("span", { className: "h-5 w-5", children: item.icon }),
1985
- /* @__PURE__ */ jsx26("span", { className: "flex-1", children: item.label }),
1986
- item.shortcut && /* @__PURE__ */ jsx26("kbd", { className: "rounded border border-ph-border bg-ph-surface px-1.5 py-0.5 text-xs text-ph-mutedtext", children: item.shortcut })
1987
- ]
1988
- },
1989
- item.id
1990
- )) })
1991
- ]
1885
+ children: [
1886
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-3 border-b border-ph-border px-4 py-3", children: [
1887
+ /* @__PURE__ */ jsx26(IconSearch, { className: "h-5 w-5 text-ph-mutedtext" }),
1888
+ /* @__PURE__ */ jsx26(
1889
+ "input",
1890
+ {
1891
+ ref: inputRef,
1892
+ id: inputId,
1893
+ "data-test": inputDataTest,
1894
+ type: "text",
1895
+ "aria-label": "Search commands",
1896
+ value: query,
1897
+ onChange: (e) => {
1898
+ setQuery(e.target.value);
1899
+ setSelectedIndex(0);
1900
+ },
1901
+ placeholder,
1902
+ className: "flex-1 bg-transparent text-ph-ink outline-none placeholder:text-ph-mutedtext"
1903
+ }
1904
+ ),
1905
+ /* @__PURE__ */ jsx26("kbd", { className: "rounded border border-ph-border bg-ph-muted px-1.5 py-0.5 text-xs text-ph-mutedtext", children: "ESC" })
1906
+ ] }),
1907
+ /* @__PURE__ */ jsx26("div", { className: "max-h-[50vh] overflow-y-auto py-2", children: filtered.length === 0 ? /* @__PURE__ */ jsx26("div", { className: "px-4 py-8 text-center text-sm text-ph-mutedtext", children: "No results found." }) : filtered.map((item, index) => /* @__PURE__ */ jsxs23(
1908
+ "button",
1909
+ {
1910
+ type: "button",
1911
+ id: `command-${item.id}`,
1912
+ "data-test": `command-${item.id}`,
1913
+ onClick: () => {
1914
+ item.onSelect();
1915
+ onClose();
1916
+ },
1917
+ onMouseEnter: () => setSelectedIndex(index),
1918
+ className: cn(
1919
+ "flex w-full items-center gap-3 px-4 py-2.5 text-left text-sm transition-colors",
1920
+ index === selectedIndex ? "bg-ph-muted text-ph-ink" : "text-ph-subtle"
1921
+ ),
1922
+ children: [
1923
+ item.icon && /* @__PURE__ */ jsx26("span", { className: "h-5 w-5", children: item.icon }),
1924
+ /* @__PURE__ */ jsx26("span", { className: "flex-1", children: item.label }),
1925
+ item.shortcut && /* @__PURE__ */ jsx26("kbd", { className: "rounded border border-ph-border bg-ph-surface px-1.5 py-0.5 text-xs text-ph-mutedtext", children: item.shortcut })
1926
+ ]
1927
+ },
1928
+ item.id
1929
+ )) })
1930
+ ]
1931
+ }
1932
+ )
1992
1933
  }
1993
- ) });
1934
+ );
1994
1935
  }
1995
1936
 
1996
1937
  // src/components/ui/Calendar.tsx
@@ -4288,34 +4229,45 @@ var Chip = forwardRef13(function Chip2(_a, ref) {
4288
4229
  "children",
4289
4230
  "className"
4290
4231
  ]);
4291
- return /* @__PURE__ */ jsxs60(
4232
+ const chipClassName = cn(
4233
+ "ph-chip",
4234
+ selected && "ph-chip--selected",
4235
+ className
4236
+ );
4237
+ if (onRemove) {
4238
+ const removeLabel = typeof children === "string" ? `Remove ${children}` : "Remove";
4239
+ return /* @__PURE__ */ jsxs60("span", { className: chipClassName, children: [
4240
+ /* @__PURE__ */ jsx72(
4241
+ "button",
4242
+ __spreadProps(__spreadValues({
4243
+ ref,
4244
+ type: "button",
4245
+ className: "min-w-0 bg-transparent p-0 text-inherit"
4246
+ }, props), {
4247
+ children: /* @__PURE__ */ jsx72("span", { className: "ph-chip__text", children })
4248
+ })
4249
+ ),
4250
+ /* @__PURE__ */ jsx72(
4251
+ "button",
4252
+ {
4253
+ type: "button",
4254
+ onClick: onRemove,
4255
+ disabled: props.disabled,
4256
+ className: "ph-chip__remove",
4257
+ "aria-label": removeLabel,
4258
+ children: /* @__PURE__ */ jsx72("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx72("path", { d: "M2 2l6 6M8 2l-6 6" }) })
4259
+ }
4260
+ )
4261
+ ] });
4262
+ }
4263
+ return /* @__PURE__ */ jsx72(
4292
4264
  "button",
4293
4265
  __spreadProps(__spreadValues({
4294
4266
  ref,
4295
4267
  type: "button",
4296
- className: cn(
4297
- "ph-chip",
4298
- selected && "ph-chip--selected",
4299
- className
4300
- )
4268
+ className: chipClassName
4301
4269
  }, props), {
4302
- children: [
4303
- /* @__PURE__ */ jsx72("span", { className: "ph-chip__text", children }),
4304
- onRemove && /* @__PURE__ */ jsx72(
4305
- "span",
4306
- {
4307
- role: "button",
4308
- tabIndex: -1,
4309
- onClick: (e) => {
4310
- e.stopPropagation();
4311
- onRemove();
4312
- },
4313
- className: "ph-chip__remove",
4314
- "aria-label": "Remove",
4315
- children: /* @__PURE__ */ jsx72("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", children: /* @__PURE__ */ jsx72("path", { d: "M2 2l6 6M8 2l-6 6" }) })
4316
- }
4317
- )
4318
- ]
4270
+ children: /* @__PURE__ */ jsx72("span", { className: "ph-chip__text", children })
4319
4271
  })
4320
4272
  );
4321
4273
  });