@nextlyhq/ui 0.0.2-alpha.56 → 0.0.2-alpha.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -33,8 +33,9 @@ var buttonVariants = cva(
33
33
  destructive: "bg-destructive-solid text-destructive-foreground border border-transparent hover:bg-destructive-600",
34
34
  // border-border is the decorative separator token, and it is the right
35
35
  // one here: a button is identified by its label and fill, so its edge
36
- // carries no meaning on its own and is not held to the 3:1 minimum that
37
- // border-input meets for controls identified by their boundary. It is
36
+ // carries no meaning on its own, unlike border-input, which is the
37
+ // token for controls identified by their boundary (that token is now
38
+ // below 1.4.11's 3:1 in light mode; see contrast/accepted.ts). It is
38
39
  // still used in preference to a faint primary alpha, which reads as a
39
40
  // tint of the brand colour rather than as an edge.
40
41
  outline: "border border-border text-foreground hover-unified bg-background",
@@ -91,11 +92,22 @@ import { cva as cva2 } from "class-variance-authority";
91
92
  import { forwardRef as forwardRef2 } from "react";
92
93
  import { jsx as jsx2 } from "react/jsx-runtime";
93
94
  var inputVariants = cva2(
94
- "file:text-foreground placeholder:text-muted-foreground placeholder:opacity-50 selection:bg-primary selection:text-primary-foreground w-full min-w-0 rounded-md border border-input bg-background text-sm transition-all duration-150 outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus:ring-0 focus:ring-offset-0 focus:outline-none focus:border-primary! focus-visible:border-primary! aria-invalid:border-destructive aria-invalid:focus:border-destructive! data-[invalid=true]:border-destructive data-[invalid=true]:focus:border-destructive!",
95
+ // `text-foreground` is explicit rather than inherited. Tailwind's preflight
96
+ // sets `color: inherit` on form controls, so without it the typed value takes
97
+ // whatever colour an ancestor happens to carry -- muted inside a
98
+ // `text-muted-foreground` block, red inside a `text-destructive` one. Select
99
+ // and Textarea have always pinned it; Input was the one control that did not,
100
+ // and callers were compensating by putting the token on a wrapper.
101
+ "file:text-foreground text-foreground placeholder:text-muted-foreground placeholder:opacity-50 selection:bg-primary selection:text-primary-foreground w-full min-w-0 rounded-md border border-input bg-background text-sm transition-all duration-150 outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 focus:ring-0 focus:ring-offset-0 focus:outline-none focus:border-primary! focus-visible:border-primary! aria-invalid:border-destructive aria-invalid:focus:border-destructive! data-[invalid=true]:border-destructive data-[invalid=true]:focus:border-destructive!",
95
102
  {
96
103
  variants: {
97
104
  size: {
98
- sm: "h-[var(--nx-control-height-sm)] px-2.5 py-2 text-sm",
105
+ // `-md` rather than `-sm`, so that a small input is the same height as
106
+ // a small button standing beside it in a toolbar or a filter row.
107
+ // Button's `sm` has always used this step; an input reading `-sm` made
108
+ // `size="sm"` mean 36px on one control and 32px on another, and a form
109
+ // row mixing them sat 4px out of line.
110
+ sm: "h-[var(--nx-control-height-md)] px-2.5 py-2 text-sm",
99
111
  default: "h-[var(--nx-control-height)] px-3 py-2.5 text-sm",
100
112
  lg: "h-[var(--nx-control-height-lg)] px-4 py-3 text-base"
101
113
  }
@@ -677,9 +689,12 @@ var Checkbox = forwardRef11(({ className, indeterminate, ...props }, ref) => /*
677
689
  ref,
678
690
  "data-slot": "checkbox",
679
691
  className: cn(
680
- // Resting border uses border-input (a visible 3:1 boundary); the checked
681
- // state switches to border-primary below, keeping the two states distinct.
682
- "peer relative h-4 w-4 shrink-0 rounded-sm border border-input ring-offset-background before:absolute before:left-1/2 before:top-1/2 before:h-6 before:w-6 before:-translate-x-1/2 before:-translate-y-1/2 before:content-[''] focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground data-[state=indeterminate]:border-primary transition-all duration-200",
692
+ // Resting border uses border-control-border, NOT border-input. An
693
+ // unchecked box has no label, value or focus ring to identify it -- the
694
+ // border is the whole control -- so it is held to 1.4.11's 3:1, which
695
+ // border-input deliberately no longer meets. The checked state switches
696
+ // to border-primary below, keeping the two states distinct.
697
+ "peer relative h-4 w-4 shrink-0 rounded-sm border border-control-border ring-offset-background before:absolute before:left-1/2 before:top-1/2 before:h-6 before:w-6 before:-translate-x-1/2 before:-translate-y-1/2 before:content-[''] focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:text-primary-foreground data-[state=indeterminate]:border-primary transition-all duration-200",
683
698
  className
684
699
  ),
685
700
  ...props,
@@ -719,13 +734,15 @@ var RadioGroupItem = forwardRef12(({ className, ...props }, ref) => {
719
734
  className: cn(
720
735
  // Unchecked outline uses primary/40 (clearly visible) instead of primary/5
721
736
  // (~5% opacity, effectively invisible); hover strengthens above the resting state.
722
- // Resting border uses border-input (a visible 3:1 boundary); the checked
723
- // state switches to border-primary below, keeping the two states distinct.
737
+ // Resting border uses border-control-border, NOT border-input. An
738
+ // unchecked radio is only its ring, with nothing else to identify it,
739
+ // so it is held to 1.4.11's 3:1 -- which border-input deliberately no
740
+ // longer meets. The checked state switches to border-primary below.
724
741
  // rounded-full is fixed rather than derived from --radius: the circle is
725
742
  // what tells the user only one option can be chosen. The thick checked
726
743
  // border leaves a background-coloured core, and because the border's
727
744
  // inner edge is curved too that core reads as a round dot.
728
- "peer h-4 w-4 shrink-0 rounded-full border border-input bg-background cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 hover:border-primary/70 data-[state=checked]:border-primary data-[state=checked]:border-[5px]",
745
+ "peer h-4 w-4 shrink-0 rounded-full border border-control-border bg-background cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none focus-visible:outline-none aria-invalid:border-destructive aria-invalid:focus:border-destructive! aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50 hover:border-primary/70 data-[state=checked]:border-primary data-[state=checked]:border-[5px]",
729
746
  className
730
747
  ),
731
748
  ...props,
@@ -749,7 +766,21 @@ function Switch({ className, ...props }) {
749
766
  className: cn(
750
767
  "peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-border transition-all outline-none focus-visible:border-primary aria-invalid:border-destructive aria-invalid:focus-visible:border-destructive! disabled:cursor-not-allowed disabled:opacity-50",
751
768
  "data-[state=checked]:bg-primary data-[state=checked]:border-primary!",
752
- "data-[state=unchecked]:bg-input data-[state=unchecked]:border-border dark:data-[state=unchecked]:bg-input/80",
769
+ // An unchecked switch is a track and a thumb and nothing else -- no
770
+ // label inside it, no value, no glyph -- so 1.4.11 applies to both the
771
+ // track against the page and the thumb against the track. `bg-input`
772
+ // cannot serve here: it is the FIELD border weight, deliberately below
773
+ // the minimum, and at that value the pill and its thumb both vanish
774
+ // into a light page. The control token is the same answer used for the
775
+ // checkbox and radio boundary, for the same reason.
776
+ // At full strength in both modes. A `/80` here read as a softening of
777
+ // the dark track and was in fact a removal of the guarantee the token
778
+ // carries: composited over the surfaces the switch renders on it
779
+ // measures 3.02 on the page, 2.94 on a card, 2.85 on a popover or the
780
+ // sidebar and 2.65 on muted, so three of the four fall under the 3:1
781
+ // this token exists to hold. Opaque, the same four are 4.23, 4.01,
782
+ // 3.79 and 3.40.
783
+ "data-[state=unchecked]:bg-control-border data-[state=unchecked]:border-control-border",
753
784
  className
754
785
  ),
755
786
  ...props,
@@ -914,41 +945,57 @@ AvatarFallback.displayName = "AvatarFallback";
914
945
 
915
946
  // src/components/tabs.tsx
916
947
  import { Root as Root7, List, Trigger as Trigger3, Content as Content3 } from "@radix-ui/react-tabs";
948
+ import { cva as cva8 } from "class-variance-authority";
917
949
  import { forwardRef as forwardRef15 } from "react";
918
950
  import { jsx as jsx20 } from "react/jsx-runtime";
919
951
  var Tabs = Root7;
920
- var TabsList = forwardRef15(
921
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
922
- List,
923
- {
924
- ref,
925
- "data-slot": "tabs-list",
926
- className: cn(
927
- // Square corners: underline tabs, so the list never draws a rounded surface.
928
- "inline-flex h-10 items-center justify-center gap-1 rounded-none p-0 text-muted-foreground",
929
- className
930
- ),
931
- ...props
932
- }
933
- )
952
+ var TABS_LIST_VARIANTS = {
953
+ default: "h-10",
954
+ ghost: "h-8 bg-transparent"
955
+ };
956
+ var tabsListVariants = cva8(
957
+ // Square corners: underline tabs, so the list never draws a rounded surface.
958
+ // `gap-1` and `p-0` are invariant across the variants, so they belong here —
959
+ // repeating them in each arm gives any future adjustment two sites to change
960
+ // and one to forget.
961
+ "inline-flex items-center justify-center gap-1 rounded-none p-0 text-muted-foreground",
962
+ {
963
+ variants: { variant: TABS_LIST_VARIANTS },
964
+ defaultVariants: { variant: "default" }
965
+ }
934
966
  );
967
+ var TabsList = forwardRef15(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx20(
968
+ List,
969
+ {
970
+ ref,
971
+ "data-slot": "tabs-list",
972
+ className: cn(tabsListVariants({ variant }), className),
973
+ ...props
974
+ }
975
+ ));
935
976
  TabsList.displayName = List.displayName;
936
- var TabsTrigger = forwardRef15(
937
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
938
- Trigger3,
939
- {
940
- ref,
941
- "data-slot": "tabs-trigger",
942
- className: cn(
943
- // Square corners: the active state is a 2px bottom border that has to
944
- // run the full width of the trigger.
945
- "inline-flex items-center justify-center whitespace-nowrap rounded-none bg-transparent px-4 py-2 text-sm font-medium cursor-pointer transition-all duration-200 border-b-2 relative -mb-0.5 data-[state=active]:border-b-primary! data-[state=active]:text-primary data-[state=inactive]:border-transparent data-[state=inactive]:text-muted-foreground hover:text-primary hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed",
946
- className
947
- ),
948
- ...props
949
- }
950
- )
977
+ var TABS_TRIGGER_SIZES = {
978
+ default: "text-sm",
979
+ sm: "text-xs"
980
+ };
981
+ var tabsTriggerVariants = cva8(
982
+ // Square corners: the active state is a 2px bottom border that has to run the
983
+ // full width of the trigger.
984
+ "inline-flex items-center justify-center whitespace-nowrap rounded-none bg-transparent px-4 py-2 font-medium cursor-pointer transition-all duration-200 border-b-2 relative -mb-0.5 data-[state=active]:border-b-primary! data-[state=active]:text-primary data-[state=inactive]:border-transparent data-[state=inactive]:text-muted-foreground hover:text-primary hover:border-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed",
985
+ {
986
+ variants: { size: TABS_TRIGGER_SIZES },
987
+ defaultVariants: { size: "default" }
988
+ }
951
989
  );
990
+ var TabsTrigger = forwardRef15(({ className, size, ...props }, ref) => /* @__PURE__ */ jsx20(
991
+ Trigger3,
992
+ {
993
+ ref,
994
+ "data-slot": "tabs-trigger",
995
+ className: cn(tabsTriggerVariants({ size }), className),
996
+ ...props
997
+ }
998
+ ));
952
999
  TabsTrigger.displayName = Trigger3.displayName;
953
1000
  var TabsContent = forwardRef15(
954
1001
  ({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
@@ -994,7 +1041,7 @@ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
994
1041
 
995
1042
  // src/components/dialog.tsx
996
1043
  import * as DialogPrimitive from "@radix-ui/react-dialog";
997
- import { cva as cva8 } from "class-variance-authority";
1044
+ import { cva as cva9 } from "class-variance-authority";
998
1045
  import { X } from "lucide-react";
999
1046
  import { forwardRef as forwardRef17 } from "react";
1000
1047
  import { jsx as jsx22, jsxs as jsxs4 } from "react/jsx-runtime";
@@ -1020,7 +1067,7 @@ var DialogOverlay = forwardRef17(({ className, ...props }, ref) => /* @__PURE__
1020
1067
  }
1021
1068
  ));
1022
1069
  DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
1023
- var dialogContentVariants = cva8("", {
1070
+ var dialogContentVariants = cva9("", {
1024
1071
  variants: {
1025
1072
  size: {
1026
1073
  sm: "max-w-sm",
@@ -1379,7 +1426,7 @@ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
1379
1426
 
1380
1427
  // src/components/select.tsx
1381
1428
  import * as SelectPrimitive from "@radix-ui/react-select";
1382
- import { cva as cva9 } from "class-variance-authority";
1429
+ import { cva as cva10 } from "class-variance-authority";
1383
1430
  import { Check as Check3, ChevronDown as ChevronDown2, ChevronUp } from "lucide-react";
1384
1431
  import { forwardRef as forwardRef20 } from "react";
1385
1432
  import { jsx as jsx25, jsxs as jsxs7 } from "react/jsx-runtime";
@@ -1396,14 +1443,17 @@ function SelectValue({
1396
1443
  }) {
1397
1444
  return /* @__PURE__ */ jsx25(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
1398
1445
  }
1399
- var selectTriggerVariants = cva9(
1446
+ var selectTriggerVariants = cva10(
1400
1447
  // hover:border-primary (full strength) keeps the hover boundary more visible
1401
1448
  // than the resting border-input, not a fainter alpha of it.
1402
1449
  "flex w-full items-center justify-between gap-2 rounded-md border border-input bg-background px-3 text-sm text-foreground cursor-pointer transition-all duration-150 focus:border-primary! focus-visible:border-primary! focus:outline-none hover:border-primary disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-primary/5 data-[placeholder]:text-muted-foreground aria-[invalid=true]:border-destructive aria-[invalid=true]:focus:border-destructive! [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg]:size-4",
1403
1450
  {
1404
1451
  variants: {
1405
1452
  size: {
1406
- sm: "h-[var(--nx-control-height-sm)] text-sm",
1453
+ // `-md`, matching Button and Input: one height for one size name. A
1454
+ // select sitting beside a small button in a filter row is the case that
1455
+ // makes a 4px difference visible.
1456
+ sm: "h-[var(--nx-control-height-md)] text-sm",
1407
1457
  default: "h-[var(--nx-control-height)] text-sm",
1408
1458
  lg: "h-[var(--nx-control-height-lg)] text-base"
1409
1459
  }
@@ -1548,7 +1598,7 @@ function SelectScrollDownButton({
1548
1598
 
1549
1599
  // src/components/sheet.tsx
1550
1600
  import * as DialogPrimitive2 from "@radix-ui/react-dialog";
1551
- import { cva as cva10 } from "class-variance-authority";
1601
+ import { cva as cva11 } from "class-variance-authority";
1552
1602
  import * as React7 from "react";
1553
1603
  import { jsx as jsx26, jsxs as jsxs8 } from "react/jsx-runtime";
1554
1604
  var Sheet = DialogPrimitive2.Root;
@@ -1574,7 +1624,7 @@ var SheetOverlay = React7.forwardRef(({ className, ...props }, ref) => /* @__PUR
1574
1624
  }
1575
1625
  ));
1576
1626
  SheetOverlay.displayName = DialogPrimitive2.Overlay.displayName;
1577
- var sheetVariants = cva10(
1627
+ var sheetVariants = cva11(
1578
1628
  "fixed z-50 gap-4 bg-background p-6 shadow-lg will-change-transform transition ease-in-out data-[state=closed]:duration-150 data-[state=open]:duration-150 data-[state=open]:animate-in data-[state=closed]:animate-out",
1579
1629
  {
1580
1630
  variants: {
@@ -1656,7 +1706,7 @@ SheetDescription.displayName = DialogPrimitive2.Description.displayName;
1656
1706
 
1657
1707
  // src/components/command.tsx
1658
1708
  import * as DialogPrimitive3 from "@radix-ui/react-dialog";
1659
- import { Command as CommandPrimitive } from "cmdk";
1709
+ import { Command as CommandPrimitive, defaultFilter } from "cmdk";
1660
1710
  import { Search } from "lucide-react";
1661
1711
  import { forwardRef as forwardRef22 } from "react";
1662
1712
  import { jsx as jsx27, jsxs as jsxs9 } from "react/jsx-runtime";
@@ -1694,13 +1744,19 @@ var CommandDialogOverlay = forwardRef22(({ className, ...props }, ref) => /* @__
1694
1744
  }
1695
1745
  ));
1696
1746
  CommandDialogOverlay.displayName = "CommandDialogOverlay";
1697
- var CommandDialog = ({ children, ...props }) => {
1747
+ var CommandDialog = ({
1748
+ children,
1749
+ commandProps,
1750
+ contentProps,
1751
+ ...props
1752
+ }) => {
1698
1753
  const portalContainer = usePortalContainer();
1699
1754
  return /* @__PURE__ */ jsx27(DialogPrimitive3.Root, { ...props, children: /* @__PURE__ */ jsxs9(DialogPrimitive3.Portal, { container: portalContainer, children: [
1700
1755
  /* @__PURE__ */ jsx27(CommandDialogOverlay, {}),
1701
1756
  /* @__PURE__ */ jsx27(
1702
1757
  DialogPrimitive3.Content,
1703
1758
  {
1759
+ ...contentProps,
1704
1760
  "data-slot": "command-content",
1705
1761
  className: cn(
1706
1762
  // Position
@@ -1726,7 +1782,19 @@ var CommandDialog = ({ children, ...props }) => {
1726
1782
  "data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
1727
1783
  "data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]"
1728
1784
  ),
1729
- children: /* @__PURE__ */ jsx27(Command, { className: "[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:mb-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-3 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4", children })
1785
+ children: /* @__PURE__ */ jsx27(
1786
+ Command,
1787
+ {
1788
+ ...commandProps,
1789
+ className: cn(
1790
+ "[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:py-2 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-wide [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:mb-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-3 [&_[cmdk-item]]:py-2 [&_[cmdk-item]_svg]:h-4 [&_[cmdk-item]_svg]:w-4",
1791
+ // Merged rather than overridden: a caller passing `className` for its own reason
1792
+ // would otherwise silently drop every layout rule this dialog depends on.
1793
+ commandProps?.className
1794
+ ),
1795
+ children
1796
+ }
1797
+ )
1730
1798
  }
1731
1799
  )
1732
1800
  ] }) });
@@ -1864,13 +1932,14 @@ var CommandShortcut = forwardRef22(
1864
1932
  }
1865
1933
  );
1866
1934
  CommandShortcut.displayName = "CommandShortcut";
1935
+ var commandDefaultFilter = defaultFilter;
1867
1936
 
1868
1937
  // src/components/spinner.tsx
1869
- import { cva as cva11 } from "class-variance-authority";
1938
+ import { cva as cva12 } from "class-variance-authority";
1870
1939
  import { Loader2 } from "lucide-react";
1871
1940
  import { forwardRef as forwardRef23 } from "react";
1872
1941
  import { jsx as jsx28 } from "react/jsx-runtime";
1873
- var spinnerVariants = cva11("animate-spin motion-reduce:animate-none", {
1942
+ var spinnerVariants = cva12("animate-spin motion-reduce:animate-none", {
1874
1943
  variants: {
1875
1944
  size: {
1876
1945
  sm: "h-4 w-4",
@@ -2111,7 +2180,7 @@ var TableSkeleton = ({
2111
2180
  ] })
2112
2181
  ] }) : /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-[60%] max-w-[120px]" }) }, colIdx)) }, rowIdx)) })
2113
2182
  ] }) }),
2114
- !hideFooter && /* @__PURE__ */ jsx33("div", { className: "table-footer border-t border-border", children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between px-2 py-4 p-4", children: [
2183
+ !hideFooter && /* @__PURE__ */ jsx33("div", { className: "table-footer border-t border-border", children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between px-2 py-4", children: [
2115
2184
  /* @__PURE__ */ jsx33("div", { className: "flex items-center gap-2 text-sm", children: /* @__PURE__ */ jsx33(GrayBar, { className: "h-4 w-[120px]" }) }),
2116
2185
  /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-6", children: [
2117
2186
  /* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
@@ -2136,11 +2205,353 @@ var TableSkeleton = ({
2136
2205
  };
2137
2206
  TableSkeleton.displayName = "TableSkeleton";
2138
2207
 
2208
+ // src/components/color-picker.tsx
2209
+ import { Pipette } from "lucide-react";
2210
+ import * as React9 from "react";
2211
+
2212
+ // src/lib/color/convert.ts
2213
+ var clamp01 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
2214
+ function normalizeHue(hue) {
2215
+ if (!Number.isFinite(hue)) return 0;
2216
+ const wrapped = hue % 360;
2217
+ return wrapped < 0 ? wrapped + 360 : wrapped;
2218
+ }
2219
+ function hsvToRgb({ h, s, v }) {
2220
+ const hue = normalizeHue(h);
2221
+ const sat = clamp01(s);
2222
+ const val = clamp01(v);
2223
+ const sector = hue / 60;
2224
+ const chroma = val * sat;
2225
+ const x = chroma * (1 - Math.abs(sector % 2 - 1));
2226
+ const base = val - chroma;
2227
+ let rgb;
2228
+ if (sector < 1) rgb = [chroma, x, 0];
2229
+ else if (sector < 2) rgb = [x, chroma, 0];
2230
+ else if (sector < 3) rgb = [0, chroma, x];
2231
+ else if (sector < 4) rgb = [0, x, chroma];
2232
+ else if (sector < 5) rgb = [x, 0, chroma];
2233
+ else rgb = [chroma, 0, x];
2234
+ return { r: rgb[0] + base, g: rgb[1] + base, b: rgb[2] + base };
2235
+ }
2236
+ function rgbToHsv({ r, g, b }) {
2237
+ const red = clamp01(r);
2238
+ const green = clamp01(g);
2239
+ const blue = clamp01(b);
2240
+ const max = Math.max(red, green, blue);
2241
+ const min = Math.min(red, green, blue);
2242
+ const chroma = max - min;
2243
+ let hue = 0;
2244
+ if (chroma !== 0) {
2245
+ if (max === red) hue = (green - blue) / chroma % 6;
2246
+ else if (max === green) hue = (blue - red) / chroma + 2;
2247
+ else hue = (red - green) / chroma + 4;
2248
+ hue *= 60;
2249
+ }
2250
+ return {
2251
+ h: normalizeHue(hue),
2252
+ s: max === 0 ? 0 : chroma / max,
2253
+ v: max
2254
+ };
2255
+ }
2256
+
2257
+ // src/lib/color/hex.ts
2258
+ var HEX = /^#?(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
2259
+ var clamp012 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
2260
+ function pair(channel) {
2261
+ const value = Number.isFinite(channel) ? clamp012(channel) : 0;
2262
+ return Math.round(value * 255).toString(16).padStart(2, "0");
2263
+ }
2264
+ function parseHex(input) {
2265
+ const text = input.trim();
2266
+ if (!HEX.test(text)) return null;
2267
+ const digits = text.replace("#", "");
2268
+ const short = digits.length < 6;
2269
+ const size = short ? 1 : 2;
2270
+ const channel = (index) => {
2271
+ const slice = digits.slice(index * size, index * size + size);
2272
+ return parseInt(short ? slice + slice : slice, 16) / 255;
2273
+ };
2274
+ const hasAlpha = digits.length === 4 || digits.length === 8;
2275
+ return {
2276
+ r: channel(0),
2277
+ g: channel(1),
2278
+ b: channel(2),
2279
+ alpha: hasAlpha ? channel(3) : 1
2280
+ };
2281
+ }
2282
+ function toHex(color, alpha = 1) {
2283
+ const opacity = Number.isFinite(alpha) ? clamp012(alpha) : 1;
2284
+ const opaque = `#${pair(color.r)}${pair(color.g)}${pair(color.b)}`;
2285
+ return opacity === 1 ? opaque : `${opaque}${pair(opacity)}`;
2286
+ }
2287
+
2288
+ // src/lib/color/picker-geometry.ts
2289
+ var clamp013 = (n) => n < 0 ? 0 : n > 1 ? 1 : n;
2290
+ function pointOnSurface(clientX, clientY, rect) {
2291
+ return {
2292
+ x: rect.width === 0 ? 0 : clamp013((clientX - rect.left) / rect.width),
2293
+ y: rect.height === 0 ? 0 : clamp013((clientY - rect.top) / rect.height)
2294
+ };
2295
+ }
2296
+ function saturationValueAt(point) {
2297
+ return { s: clamp013(point.x), v: 1 - clamp013(point.y) };
2298
+ }
2299
+ function surfacePointFor(s, v) {
2300
+ return { x: clamp013(s), y: 1 - clamp013(v) };
2301
+ }
2302
+ function hueAt(fraction) {
2303
+ const hue = clamp013(fraction) * 360;
2304
+ return hue >= 360 ? 0 : hue;
2305
+ }
2306
+ function huePosition(hue) {
2307
+ const wrapped = (hue % 360 + 360) % 360;
2308
+ return wrapped / 360;
2309
+ }
2310
+ function hueSliderValue(hue, max) {
2311
+ const step = Math.round(huePosition(hue) * (max + 1));
2312
+ return step > max ? max : step;
2313
+ }
2314
+
2315
+ // src/components/color-picker.tsx
2316
+ import { Fragment as Fragment2, jsx as jsx34, jsxs as jsxs13 } from "react/jsx-runtime";
2317
+ function toHsva(hex) {
2318
+ const parsed = parseHex(hex);
2319
+ if (!parsed) return { h: 0, s: 0, v: 0, a: 1 };
2320
+ const { r, g, b, alpha } = parsed;
2321
+ return { ...rgbToHsv({ r, g, b }), a: alpha };
2322
+ }
2323
+ function toHexString(hsva, withAlpha) {
2324
+ return toHex(hsvToRgb(hsva), withAlpha ? hsva.a : 1);
2325
+ }
2326
+ var HUE_MAX = 359;
2327
+ function hsvaFrom(color, alpha, currentHue) {
2328
+ const hsv = rgbToHsv(color);
2329
+ return { ...hsv, h: hsv.s === 0 ? currentHue : hsv.h, a: alpha };
2330
+ }
2331
+ var SLIDER = "h-3 w-full cursor-pointer appearance-none rounded-full";
2332
+ var CHECKERBOARD = "repeating-conic-gradient(#c8c8c8 0% 25%, #ffffff 0% 50%)";
2333
+ function eyeDropperSupported() {
2334
+ return typeof window !== "undefined" && "EyeDropper" in window;
2335
+ }
2336
+ function ColorPicker({
2337
+ color,
2338
+ onColorChange,
2339
+ swatches = [],
2340
+ onSwatchSelect,
2341
+ recentColors = [],
2342
+ showAlpha = false,
2343
+ className
2344
+ }) {
2345
+ const fieldId = React9.useId();
2346
+ const surfaceRef = React9.useRef(null);
2347
+ const [hsva, setHsva] = React9.useState(() => toHsva(color));
2348
+ const [draftHex, setDraftHex] = React9.useState(null);
2349
+ const rendered = toHexString(hsva, showAlpha);
2350
+ React9.useEffect(() => {
2351
+ const incoming = parseHex(color);
2352
+ if (incoming && toHex(incoming, showAlpha ? incoming.alpha : 1) !== rendered) {
2353
+ setHsva((prev) => hsvaFrom(incoming, incoming.alpha, prev.h));
2354
+ }
2355
+ }, [color, rendered, showAlpha]);
2356
+ const commit = (next) => {
2357
+ setHsva(next);
2358
+ setDraftHex(null);
2359
+ onColorChange(toHexString(next, showAlpha));
2360
+ };
2361
+ const trackPointer = (event) => {
2362
+ const rect = surfaceRef.current?.getBoundingClientRect();
2363
+ if (!rect) return;
2364
+ const { s, v } = saturationValueAt(
2365
+ pointOnSurface(event.clientX, event.clientY, rect)
2366
+ );
2367
+ commit({ ...hsva, s, v });
2368
+ };
2369
+ const nudge = (ds, dv) => {
2370
+ const { s, v } = saturationValueAt(
2371
+ surfacePointFor(hsva.s + ds, hsva.v + dv)
2372
+ );
2373
+ commit({ ...hsva, s, v });
2374
+ };
2375
+ const handleSurfaceKey = (event) => {
2376
+ const step = event.shiftKey ? 0.1 : 0.01;
2377
+ const moves = {
2378
+ ArrowLeft: [-step, 0],
2379
+ ArrowRight: [step, 0],
2380
+ ArrowUp: [0, step],
2381
+ ArrowDown: [0, -step]
2382
+ };
2383
+ const move = moves[event.key];
2384
+ if (!move) return;
2385
+ event.preventDefault();
2386
+ nudge(move[0], move[1]);
2387
+ };
2388
+ const [canPickFromScreen, setCanPickFromScreen] = React9.useState(false);
2389
+ React9.useEffect(() => {
2390
+ setCanPickFromScreen(eyeDropperSupported());
2391
+ }, []);
2392
+ const handle = surfacePointFor(hsva.s, hsva.v);
2393
+ const hueOnly = toHex(hsvToRgb({ h: hsva.h, s: 1, v: 1 }));
2394
+ const pickFromScreen = async () => {
2395
+ const ctor = window.EyeDropper;
2396
+ if (!ctor) return;
2397
+ let sampled;
2398
+ try {
2399
+ sampled = (await new ctor().open()).sRGBHex;
2400
+ } catch {
2401
+ return;
2402
+ }
2403
+ const parsed = parseHex(sampled);
2404
+ if (parsed) commit(hsvaFrom(parsed, hsva.a, hsva.h));
2405
+ };
2406
+ return /* @__PURE__ */ jsxs13("div", { className: cn("w-64 space-y-3", className), children: [
2407
+ /* @__PURE__ */ jsx34(
2408
+ "div",
2409
+ {
2410
+ ref: surfaceRef,
2411
+ role: "application",
2412
+ tabIndex: 0,
2413
+ "aria-label": `Saturation and brightness: ${Math.round(hsva.s * 100)}% saturation, ${Math.round(hsva.v * 100)}% brightness. Arrow keys adjust.`,
2414
+ className: "ring-offset-background focus-visible:ring-ring relative h-40 w-full cursor-crosshair touch-none rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
2415
+ style: {
2416
+ backgroundColor: hueOnly,
2417
+ // Value on TOP of saturation. CSS paints the first layer nearest the
2418
+ // viewer, so the reverse order lets the opaque white end of the
2419
+ // saturation ramp cover the black end of the value ramp: the
2420
+ // bottom-left corner displays white while selecting black.
2421
+ backgroundImage: "linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent)"
2422
+ },
2423
+ onKeyDown: handleSurfaceKey,
2424
+ onPointerDown: (event) => {
2425
+ event.currentTarget.setPointerCapture(event.pointerId);
2426
+ trackPointer(event);
2427
+ },
2428
+ onPointerMove: (event) => {
2429
+ if (event.buttons === 1) trackPointer(event);
2430
+ },
2431
+ children: /* @__PURE__ */ jsx34(
2432
+ "span",
2433
+ {
2434
+ "aria-hidden": "true",
2435
+ className: "pointer-events-none absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-sm ring-1 ring-black/60",
2436
+ style: { left: `${handle.x * 100}%`, top: `${handle.y * 100}%` }
2437
+ }
2438
+ )
2439
+ }
2440
+ ),
2441
+ /* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-hue`, children: "Hue" }),
2442
+ /* @__PURE__ */ jsx34(
2443
+ "input",
2444
+ {
2445
+ id: `${fieldId}-hue`,
2446
+ type: "range",
2447
+ min: 0,
2448
+ max: HUE_MAX,
2449
+ step: 1,
2450
+ value: hueSliderValue(hsva.h, HUE_MAX),
2451
+ onChange: (event) => commit({ ...hsva, h: hueAt(+event.target.value / (HUE_MAX + 1)) }),
2452
+ className: SLIDER,
2453
+ style: {
2454
+ backgroundImage: "linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00)"
2455
+ }
2456
+ }
2457
+ ),
2458
+ showAlpha && /* @__PURE__ */ jsxs13(Fragment2, { children: [
2459
+ /* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-alpha`, children: "Opacity" }),
2460
+ /* @__PURE__ */ jsx34(
2461
+ "input",
2462
+ {
2463
+ id: `${fieldId}-alpha`,
2464
+ type: "range",
2465
+ min: 0,
2466
+ max: 100,
2467
+ step: 1,
2468
+ value: Math.round(hsva.a * 100),
2469
+ onChange: (event) => commit({ ...hsva, a: +event.target.value / 100 }),
2470
+ className: SLIDER,
2471
+ style: {
2472
+ // The ramp runs to the colour being edited, over a chequerboard,
2473
+ // so the track shows what the slider actually controls. Without
2474
+ // any background this rendered as a blank 12px strip whose only
2475
+ // label was screen-reader-only.
2476
+ backgroundImage: `linear-gradient(to right, transparent, ${toHexString({ ...hsva, a: 1 }, false)}), ${CHECKERBOARD}`,
2477
+ backgroundSize: "100% 100%, 8px 8px"
2478
+ }
2479
+ }
2480
+ )
2481
+ ] }),
2482
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
2483
+ /* @__PURE__ */ jsx34("label", { className: "sr-only", htmlFor: `${fieldId}-hex`, children: "Hex colour" }),
2484
+ /* @__PURE__ */ jsx34(
2485
+ Input,
2486
+ {
2487
+ id: `${fieldId}-hex`,
2488
+ className: "font-mono",
2489
+ value: draftHex ?? rendered,
2490
+ onChange: (event) => {
2491
+ const text = event.target.value;
2492
+ setDraftHex(text);
2493
+ const parsed = parseHex(text);
2494
+ if (parsed) {
2495
+ setHsva(hsvaFrom(parsed, parsed.alpha, hsva.h));
2496
+ onColorChange(toHex(parsed, showAlpha ? parsed.alpha : 1));
2497
+ }
2498
+ },
2499
+ onBlur: () => setDraftHex(null)
2500
+ }
2501
+ ),
2502
+ canPickFromScreen && /* @__PURE__ */ jsx34(
2503
+ Button,
2504
+ {
2505
+ type: "button",
2506
+ variant: "outline",
2507
+ size: "icon",
2508
+ "aria-label": "Pick a colour from the screen",
2509
+ onClick: () => void pickFromScreen(),
2510
+ children: /* @__PURE__ */ jsx34(Pipette, { className: "size-4" })
2511
+ }
2512
+ )
2513
+ ] }),
2514
+ swatches.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
2515
+ /* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Presets" }),
2516
+ /* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: swatches.map((swatch) => /* @__PURE__ */ jsx34(
2517
+ "button",
2518
+ {
2519
+ type: "button",
2520
+ title: swatch.label,
2521
+ "aria-label": swatch.label,
2522
+ className: "size-6 rounded border shadow-sm",
2523
+ style: { backgroundColor: swatch.color },
2524
+ onClick: () => onSwatchSelect?.(swatch)
2525
+ },
2526
+ swatch.id
2527
+ )) })
2528
+ ] }),
2529
+ recentColors.length > 0 && /* @__PURE__ */ jsxs13("div", { children: [
2530
+ /* @__PURE__ */ jsx34("p", { className: "text-muted-foreground mb-1 text-xs", children: "Recent" }),
2531
+ /* @__PURE__ */ jsx34("div", { className: "flex flex-wrap gap-1", children: recentColors.map((recent) => /* @__PURE__ */ jsx34(
2532
+ "button",
2533
+ {
2534
+ type: "button",
2535
+ title: recent,
2536
+ "aria-label": recent,
2537
+ className: "size-6 rounded border shadow-sm",
2538
+ style: { backgroundColor: recent },
2539
+ onClick: () => {
2540
+ const parsed = parseHex(recent);
2541
+ if (parsed) commit(hsvaFrom(parsed, parsed.alpha, hsva.h));
2542
+ }
2543
+ },
2544
+ recent
2545
+ )) })
2546
+ ] })
2547
+ ] });
2548
+ }
2549
+
2139
2550
  // src/components/context-menu.tsx
2140
2551
  import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
2141
2552
  import { Check as Check4, ChevronRight as ChevronRight2, Circle as Circle2 } from "lucide-react";
2142
- import * as React9 from "react";
2143
- import { jsx as jsx34, jsxs as jsxs13 } from "react/jsx-runtime";
2553
+ import * as React10 from "react";
2554
+ import { jsx as jsx35, jsxs as jsxs14 } from "react/jsx-runtime";
2144
2555
  var menuItemBase2 = "cursor-pointer transition-colors data-[highlighted]:bg-muted data-[highlighted]:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
2145
2556
  var menuSurface = "z-50 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 origin-[--radix-context-menu-content-transform-origin]";
2146
2557
  var ContextMenu = ContextMenuPrimitive.Root;
@@ -2148,7 +2559,7 @@ var ContextMenuTrigger = ContextMenuPrimitive.Trigger;
2148
2559
  var ContextMenuGroup = ContextMenuPrimitive.Group;
2149
2560
  var ContextMenuSub = ContextMenuPrimitive.Sub;
2150
2561
  var ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
2151
- var ContextMenuSubTrigger = React9.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs13(
2562
+ var ContextMenuSubTrigger = React10.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
2152
2563
  ContextMenuPrimitive.SubTrigger,
2153
2564
  {
2154
2565
  ref,
@@ -2161,14 +2572,14 @@ var ContextMenuSubTrigger = React9.forwardRef(({ className, inset, children, ...
2161
2572
  ...props,
2162
2573
  children: [
2163
2574
  children,
2164
- /* @__PURE__ */ jsx34(ChevronRight2, { className: "ml-auto" })
2575
+ /* @__PURE__ */ jsx35(ChevronRight2, { className: "ml-auto" })
2165
2576
  ]
2166
2577
  }
2167
2578
  ));
2168
2579
  ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
2169
- var ContextMenuSubContent = React9.forwardRef(({ className, ...props }, ref) => {
2580
+ var ContextMenuSubContent = React10.forwardRef(({ className, ...props }, ref) => {
2170
2581
  const portalContainer = usePortalContainer();
2171
- return /* @__PURE__ */ jsx34(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx34(
2582
+ return /* @__PURE__ */ jsx35(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx35(
2172
2583
  ContextMenuPrimitive.SubContent,
2173
2584
  {
2174
2585
  ref,
@@ -2178,9 +2589,9 @@ var ContextMenuSubContent = React9.forwardRef(({ className, ...props }, ref) =>
2178
2589
  ) });
2179
2590
  });
2180
2591
  ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
2181
- var ContextMenuContent = React9.forwardRef(({ className, ...props }, ref) => {
2592
+ var ContextMenuContent = React10.forwardRef(({ className, ...props }, ref) => {
2182
2593
  const portalContainer = usePortalContainer();
2183
- return /* @__PURE__ */ jsx34(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx34(
2594
+ return /* @__PURE__ */ jsx35(ContextMenuPrimitive.Portal, { container: portalContainer, children: /* @__PURE__ */ jsx35(
2184
2595
  ContextMenuPrimitive.Content,
2185
2596
  {
2186
2597
  ref,
@@ -2190,7 +2601,7 @@ var ContextMenuContent = React9.forwardRef(({ className, ...props }, ref) => {
2190
2601
  ) });
2191
2602
  });
2192
2603
  ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
2193
- var ContextMenuItem = React9.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx34(
2604
+ var ContextMenuItem = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx35(
2194
2605
  ContextMenuPrimitive.Item,
2195
2606
  {
2196
2607
  ref,
@@ -2204,7 +2615,7 @@ var ContextMenuItem = React9.forwardRef(({ className, inset, ...props }, ref) =>
2204
2615
  }
2205
2616
  ));
2206
2617
  ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
2207
- var ContextMenuCheckboxItem = React9.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs13(
2618
+ var ContextMenuCheckboxItem = React10.forwardRef(({ className, children, checked, ...props }, ref) => /* @__PURE__ */ jsxs14(
2208
2619
  ContextMenuPrimitive.CheckboxItem,
2209
2620
  {
2210
2621
  ref,
@@ -2216,13 +2627,13 @@ var ContextMenuCheckboxItem = React9.forwardRef(({ className, children, checked,
2216
2627
  checked,
2217
2628
  ...props,
2218
2629
  children: [
2219
- /* @__PURE__ */ jsx34("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx34(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx34(Check4, { className: "h-4 w-4" }) }) }),
2630
+ /* @__PURE__ */ jsx35("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx35(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx35(Check4, { className: "h-4 w-4" }) }) }),
2220
2631
  children
2221
2632
  ]
2222
2633
  }
2223
2634
  ));
2224
2635
  ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
2225
- var ContextMenuRadioItem = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs13(
2636
+ var ContextMenuRadioItem = React10.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs14(
2226
2637
  ContextMenuPrimitive.RadioItem,
2227
2638
  {
2228
2639
  ref,
@@ -2233,13 +2644,13 @@ var ContextMenuRadioItem = React9.forwardRef(({ className, children, ...props },
2233
2644
  ),
2234
2645
  ...props,
2235
2646
  children: [
2236
- /* @__PURE__ */ jsx34("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx34(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx34(Circle2, { className: "h-2 w-2 fill-current" }) }) }),
2647
+ /* @__PURE__ */ jsx35("span", { className: "absolute left-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx35(ContextMenuPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx35(Circle2, { className: "h-2 w-2 fill-current" }) }) }),
2237
2648
  children
2238
2649
  ]
2239
2650
  }
2240
2651
  ));
2241
2652
  ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
2242
- var ContextMenuLabel = React9.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx34(
2653
+ var ContextMenuLabel = React10.forwardRef(({ className, inset, ...props }, ref) => /* @__PURE__ */ jsx35(
2243
2654
  ContextMenuPrimitive.Label,
2244
2655
  {
2245
2656
  ref,
@@ -2252,7 +2663,7 @@ var ContextMenuLabel = React9.forwardRef(({ className, inset, ...props }, ref) =
2252
2663
  }
2253
2664
  ));
2254
2665
  ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
2255
- var ContextMenuSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx34(
2666
+ var ContextMenuSeparator = React10.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx35(
2256
2667
  ContextMenuPrimitive.Separator,
2257
2668
  {
2258
2669
  ref,
@@ -2264,7 +2675,7 @@ ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
2264
2675
  var ContextMenuShortcut = ({
2265
2676
  className,
2266
2677
  ...props
2267
- }) => /* @__PURE__ */ jsx34(
2678
+ }) => /* @__PURE__ */ jsx35(
2268
2679
  "span",
2269
2680
  {
2270
2681
  className: cn(
@@ -2279,11 +2690,11 @@ ContextMenuShortcut.displayName = "ContextMenuShortcut";
2279
2690
  // src/components/resizable.tsx
2280
2691
  import { GripVertical } from "lucide-react";
2281
2692
  import * as ResizablePrimitive from "react-resizable-panels";
2282
- import { jsx as jsx35, jsxs as jsxs14 } from "react/jsx-runtime";
2693
+ import { jsx as jsx36, jsxs as jsxs15 } from "react/jsx-runtime";
2283
2694
  var ResizablePanelGroup = ({
2284
2695
  className,
2285
2696
  ...props
2286
- }) => /* @__PURE__ */ jsx35(
2697
+ }) => /* @__PURE__ */ jsx36(
2287
2698
  ResizablePrimitive.Group,
2288
2699
  {
2289
2700
  className: cn("h-full w-full", className),
@@ -2296,7 +2707,7 @@ var ResizableHandle = ({
2296
2707
  className,
2297
2708
  children,
2298
2709
  ...props
2299
- }) => /* @__PURE__ */ jsxs14(
2710
+ }) => /* @__PURE__ */ jsxs15(
2300
2711
  ResizablePrimitive.Separator,
2301
2712
  {
2302
2713
  className: cn(
@@ -2316,7 +2727,7 @@ var ResizableHandle = ({
2316
2727
  ),
2317
2728
  ...props,
2318
2729
  children: [
2319
- withGrip ? /* @__PURE__ */ jsx35("div", { className: "z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-border", children: /* @__PURE__ */ jsx35(GripVertical, { className: "h-2.5 w-2.5 text-muted-foreground" }) }) : null,
2730
+ withGrip ? /* @__PURE__ */ jsx36("div", { className: "z-10 flex h-4 w-3 items-center justify-center rounded-sm border border-border bg-border", children: /* @__PURE__ */ jsx36(GripVertical, { className: "h-2.5 w-2.5 text-muted-foreground" }) }) : null,
2320
2731
  children
2321
2732
  ]
2322
2733
  }
@@ -2325,8 +2736,8 @@ var ResizableHandle = ({
2325
2736
  // src/components/tree-view.tsx
2326
2737
  import { useVirtualizer } from "@tanstack/react-virtual";
2327
2738
  import { ChevronRight as ChevronRight3 } from "lucide-react";
2328
- import * as React10 from "react";
2329
- import { jsx as jsx36, jsxs as jsxs15 } from "react/jsx-runtime";
2739
+ import * as React11 from "react";
2740
+ import { jsx as jsx37, jsxs as jsxs16 } from "react/jsx-runtime";
2330
2741
  var ROW_HEIGHT = 28;
2331
2742
  var INDENT_PER_LEVEL = 12;
2332
2743
  function textOf(node) {
@@ -2367,13 +2778,13 @@ function flatten(nodes, expanded) {
2367
2778
  return rows;
2368
2779
  }
2369
2780
  function useControllable(controlled, fallback) {
2370
- const [uncontrolled, setUncontrolled] = React10.useState(fallback);
2781
+ const [uncontrolled, setUncontrolled] = React11.useState(fallback);
2371
2782
  return [
2372
2783
  controlled === void 0 ? uncontrolled : controlled,
2373
2784
  setUncontrolled
2374
2785
  ];
2375
2786
  }
2376
- var TreeView = React10.forwardRef(
2787
+ var TreeView = React11.forwardRef(
2377
2788
  ({
2378
2789
  nodes,
2379
2790
  expandedIds,
@@ -2388,8 +2799,8 @@ var TreeView = React10.forwardRef(
2388
2799
  "aria-describedby": ariaDescribedBy,
2389
2800
  ...props
2390
2801
  }, forwardedRef) => {
2391
- const scrollRef = React10.useRef(null);
2392
- const attachScroll = React10.useCallback(
2802
+ const scrollRef = React11.useRef(null);
2803
+ const attachScroll = React11.useCallback(
2393
2804
  (node) => {
2394
2805
  scrollRef.current = node;
2395
2806
  if (typeof forwardedRef === "function") forwardedRef(node);
@@ -2403,7 +2814,7 @@ var TreeView = React10.forwardRef(
2403
2814
  expandedIds === void 0 ? void 0 : [...expandedIds],
2404
2815
  [...defaultExpandedIds ?? []]
2405
2816
  );
2406
- const expanded = React10.useMemo(
2817
+ const expanded = React11.useMemo(
2407
2818
  () => new Set(expandedIds ?? expandedState),
2408
2819
  [expandedIds, expandedState]
2409
2820
  );
@@ -2411,11 +2822,11 @@ var TreeView = React10.forwardRef(
2411
2822
  selectedId === void 0 ? void 0 : selectedId,
2412
2823
  defaultSelectedId ?? null
2413
2824
  );
2414
- const rows = React10.useMemo(
2825
+ const rows = React11.useMemo(
2415
2826
  () => flatten(nodes, expanded),
2416
2827
  [nodes, expanded]
2417
2828
  );
2418
- const [activeId, setActiveId] = React10.useState(null);
2829
+ const [activeId, setActiveId] = React11.useState(null);
2419
2830
  const activeIndex = Math.max(
2420
2831
  0,
2421
2832
  rows.findIndex((row) => row.node.id === (activeId ?? selected))
@@ -2459,7 +2870,7 @@ var TreeView = React10.forwardRef(
2459
2870
  }
2460
2871
  return from;
2461
2872
  };
2462
- const typeahead = React10.useRef({ query: "", at: 0 });
2873
+ const typeahead = React11.useRef({ query: "", at: 0 });
2463
2874
  const onKeyDown = (event) => {
2464
2875
  const index = activeIndex;
2465
2876
  const row = rows[index];
@@ -2556,13 +2967,13 @@ var TreeView = React10.forwardRef(
2556
2967
  const virtualItems = virtualizer.getVirtualItems();
2557
2968
  const usable = (index) => rows[index]?.node.disabled !== true;
2558
2969
  const tabStopIndex = virtualItems.some((item) => item.index === activeIndex) && usable(activeIndex) ? activeIndex : virtualItems.find((item) => usable(item.index))?.index ?? -1;
2559
- return /* @__PURE__ */ jsx36(
2970
+ return /* @__PURE__ */ jsx37(
2560
2971
  "div",
2561
2972
  {
2562
2973
  ref: attachScroll,
2563
2974
  className: cn("overflow-auto", className),
2564
2975
  ...props,
2565
- children: /* @__PURE__ */ jsx36(
2976
+ children: /* @__PURE__ */ jsx37(
2566
2977
  "div",
2567
2978
  {
2568
2979
  role: "tree",
@@ -2575,7 +2986,7 @@ var TreeView = React10.forwardRef(
2575
2986
  const row = rows[item.index];
2576
2987
  if (row === void 0) return null;
2577
2988
  const isSelected = selected === row.node.id;
2578
- return /* @__PURE__ */ jsxs15(
2989
+ return /* @__PURE__ */ jsxs16(
2579
2990
  "div",
2580
2991
  {
2581
2992
  "data-tree-index": item.index,
@@ -2605,7 +3016,7 @@ var TreeView = React10.forwardRef(
2605
3016
  paddingLeft: 4 + row.level * INDENT_PER_LEVEL
2606
3017
  },
2607
3018
  children: [
2608
- /* @__PURE__ */ jsx36(
3019
+ /* @__PURE__ */ jsx37(
2609
3020
  "span",
2610
3021
  {
2611
3022
  "aria-hidden": "true",
@@ -2615,7 +3026,7 @@ var TreeView = React10.forwardRef(
2615
3026
  event.stopPropagation();
2616
3027
  setExpansion(row.node.id, !expanded.has(row.node.id));
2617
3028
  },
2618
- children: row.hasChildren ? /* @__PURE__ */ jsx36(
3029
+ children: row.hasChildren ? /* @__PURE__ */ jsx37(
2619
3030
  ChevronRight3,
2620
3031
  {
2621
3032
  className: cn(
@@ -2626,8 +3037,8 @@ var TreeView = React10.forwardRef(
2626
3037
  ) : null
2627
3038
  }
2628
3039
  ),
2629
- row.node.icon !== void 0 ? /* @__PURE__ */ jsx36("span", { className: "flex size-4 shrink-0 items-center justify-center text-muted-foreground", children: row.node.icon }) : null,
2630
- /* @__PURE__ */ jsx36("span", { className: "truncate", children: row.node.label })
3040
+ row.node.icon !== void 0 ? /* @__PURE__ */ jsx37("span", { className: "flex size-4 shrink-0 items-center justify-center text-muted-foreground", children: row.node.icon }) : null,
3041
+ /* @__PURE__ */ jsx37("span", { className: "truncate", children: row.node.label })
2631
3042
  ]
2632
3043
  },
2633
3044
  row.node.id
@@ -2643,7 +3054,7 @@ TreeView.displayName = "TreeView";
2643
3054
 
2644
3055
  // src/components/slider.tsx
2645
3056
  import * as SliderPrimitive from "@radix-ui/react-slider";
2646
- import * as React11 from "react";
3057
+ import * as React12 from "react";
2647
3058
 
2648
3059
  // src/lib/dev-warn.ts
2649
3060
  var emitted = /* @__PURE__ */ new Set();
@@ -2662,14 +3073,14 @@ function devWarnOnce(condition, message) {
2662
3073
  }
2663
3074
 
2664
3075
  // src/components/slider.tsx
2665
- import { jsx as jsx37, jsxs as jsxs16 } from "react/jsx-runtime";
3076
+ import { jsx as jsx38, jsxs as jsxs17 } from "react/jsx-runtime";
2666
3077
  function thumbCount(value, defaultValue) {
2667
3078
  return Math.max(1, value?.length ?? defaultValue?.length ?? 1);
2668
3079
  }
2669
3080
  function hasAccessibleName(value) {
2670
3081
  return value !== void 0 && value.trim() !== "";
2671
3082
  }
2672
- var Slider = React11.forwardRef(
3083
+ var Slider = React12.forwardRef(
2673
3084
  ({
2674
3085
  className,
2675
3086
  value,
@@ -2680,7 +3091,7 @@ var Slider = React11.forwardRef(
2680
3091
  "aria-labelledby": ariaLabelledBy,
2681
3092
  ...props
2682
3093
  }, ref) => {
2683
- const initialUncontrolledCount = React11.useRef(
3094
+ const initialUncontrolledCount = React12.useRef(
2684
3095
  thumbCount(void 0, defaultValue)
2685
3096
  ).current;
2686
3097
  const count = value?.length ?? initialUncontrolledCount;
@@ -2725,7 +3136,7 @@ var Slider = React11.forwardRef(
2725
3136
  // `aria-label`/`aria-labelledby` are destructured out above rather than
2726
3137
  // spread here: left on the root they would be a second, roleless copy
2727
3138
  // of a name only the thumb is read for.
2728
- /* @__PURE__ */ jsxs16(
3139
+ /* @__PURE__ */ jsxs17(
2729
3140
  SliderPrimitive.Root,
2730
3141
  {
2731
3142
  ref,
@@ -2753,14 +3164,14 @@ var Slider = React11.forwardRef(
2753
3164
  defaultValue: isEmptyDefault ? void 0 : defaultValue,
2754
3165
  ...props,
2755
3166
  children: [
2756
- /* @__PURE__ */ jsx37(
3167
+ /* @__PURE__ */ jsx38(
2757
3168
  SliderPrimitive.Track,
2758
3169
  {
2759
3170
  className: cn(
2760
3171
  "bg-secondary relative grow overflow-hidden rounded-full",
2761
3172
  isVertical ? "h-full w-1.5" : "h-1.5 w-full"
2762
3173
  ),
2763
- children: /* @__PURE__ */ jsx37(
3174
+ children: /* @__PURE__ */ jsx38(
2764
3175
  SliderPrimitive.Range,
2765
3176
  {
2766
3177
  className: cn(
@@ -2771,7 +3182,7 @@ var Slider = React11.forwardRef(
2771
3182
  )
2772
3183
  }
2773
3184
  ),
2774
- Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx37(
3185
+ Array.from({ length: count }, (_, i) => /* @__PURE__ */ jsx38(
2775
3186
  SliderPrimitive.Thumb,
2776
3187
  {
2777
3188
  ...ariaFor(i),
@@ -2794,7 +3205,7 @@ var Slider = React11.forwardRef(
2794
3205
  Slider.displayName = SliderPrimitive.Root.displayName;
2795
3206
 
2796
3207
  // src/lib/shortcuts/react.tsx
2797
- import * as React12 from "react";
3208
+ import * as React13 from "react";
2798
3209
 
2799
3210
  // src/lib/shortcuts/key-spec.ts
2800
3211
  function normalizeKey(key) {
@@ -2980,7 +3391,7 @@ function createShortcutManager(options = {}) {
2980
3391
  let pendingKey = null;
2981
3392
  function layerShape(bindings, options2) {
2982
3393
  const keys = bindings.map((b) => b.binding.keys).join("\0");
2983
- return `${keys}${options2.depth}${options2.blocking === true}${options2.enabled !== false}`;
3394
+ return `${keys}${options2.depth}${options2.priority ?? 0}${options2.blocking === true}${options2.enabled !== false}`;
2984
3395
  }
2985
3396
  function blocking() {
2986
3397
  return ordered().some((layer) => layer.options.blocking === true);
@@ -2999,7 +3410,7 @@ function createShortcutManager(options = {}) {
2999
3410
  }
3000
3411
  function ordered() {
3001
3412
  return [...layers].filter((layer) => layer.options.enabled !== false).sort(
3002
- (a, b) => b.options.depth - a.options.depth || b.sequence - a.sequence
3413
+ (a, b) => (b.options.priority ?? 0) - (a.options.priority ?? 0) || b.options.depth - a.options.depth || b.sequence - a.sequence
3003
3414
  );
3004
3415
  }
3005
3416
  function matchDepth(prepared, pressed) {
@@ -3128,6 +3539,7 @@ function createShortcutManager(options = {}) {
3128
3539
  }
3129
3540
  }
3130
3541
  function handle(event) {
3542
+ if (typeof event.key !== "string") return false;
3131
3543
  if (event.defaultPrevented) {
3132
3544
  abandonSequence();
3133
3545
  return true;
@@ -3321,10 +3733,10 @@ var FIELD_KEYS = /* @__PURE__ */ new Set([
3321
3733
  ]);
3322
3734
 
3323
3735
  // src/lib/shortcuts/react.tsx
3324
- import { jsx as jsx38 } from "react/jsx-runtime";
3325
- var ShortcutContext = React12.createContext(null);
3736
+ import { jsx as jsx39 } from "react/jsx-runtime";
3737
+ var ShortcutContext = React13.createContext(null);
3326
3738
  var ownersByTarget = /* @__PURE__ */ new WeakMap();
3327
- var useIsomorphicLayoutEffect = typeof document === "undefined" ? React12.useEffect : React12.useLayoutEffect;
3739
+ var useIsomorphicLayoutEffect = typeof document === "undefined" ? React13.useEffect : React13.useLayoutEffect;
3328
3740
  function optionsFingerprint(options) {
3329
3741
  return [
3330
3742
  options.isApple ?? "auto",
@@ -3337,13 +3749,13 @@ function ShortcutProvider({
3337
3749
  target,
3338
3750
  ...managerOptions
3339
3751
  }) {
3340
- const parent = React12.useContext(ShortcutContext);
3752
+ const parent = React13.useContext(ShortcutContext);
3341
3753
  const resolvedTarget = target === null ? null : target ?? (typeof document === "undefined" ? null : document);
3342
3754
  const nestedOnSameTarget = parent !== null && parent.target === resolvedTarget;
3343
- const optionsRef = React12.useRef(managerOptions);
3344
- const ownManagers = React12.useRef(/* @__PURE__ */ new WeakMap());
3345
- const ownDetached = React12.useRef(null);
3346
- const detached = React12.useMemo(() => {
3755
+ const optionsRef = React13.useRef(managerOptions);
3756
+ const ownManagers = React13.useRef(/* @__PURE__ */ new WeakMap());
3757
+ const ownDetached = React13.useRef(null);
3758
+ const detached = React13.useMemo(() => {
3347
3759
  if (resolvedTarget === null) {
3348
3760
  ownDetached.current ??= createShortcutManager(optionsRef.current);
3349
3761
  return ownDetached.current;
@@ -3399,20 +3811,20 @@ function ShortcutProvider({
3399
3811
  };
3400
3812
  }, [resolvedTarget, manager]);
3401
3813
  const depth = nestedOnSameTarget && parent ? parent.depth : 0;
3402
- const value = React12.useMemo(
3814
+ const value = React13.useMemo(
3403
3815
  () => ({ manager, depth, target: resolvedTarget, options: fingerprint }),
3404
3816
  [manager, depth, resolvedTarget, fingerprint]
3405
3817
  );
3406
- return /* @__PURE__ */ jsx38(ShortcutContext.Provider, { value, children });
3818
+ return /* @__PURE__ */ jsx39(ShortcutContext.Provider, { value, children });
3407
3819
  }
3408
3820
  function ShortcutScope({
3409
3821
  children
3410
3822
  }) {
3411
- const parent = React12.useContext(ShortcutContext);
3823
+ const parent = React13.useContext(ShortcutContext);
3412
3824
  if (!parent) {
3413
3825
  throw new Error("ShortcutScope must be rendered inside a ShortcutProvider");
3414
3826
  }
3415
- const value = React12.useMemo(
3827
+ const value = React13.useMemo(
3416
3828
  () => ({
3417
3829
  manager: parent.manager,
3418
3830
  depth: parent.depth + 1,
@@ -3423,16 +3835,16 @@ function ShortcutScope({
3423
3835
  }),
3424
3836
  [parent.manager, parent.depth, parent.target, parent.options]
3425
3837
  );
3426
- return /* @__PURE__ */ jsx38(ShortcutContext.Provider, { value, children });
3838
+ return /* @__PURE__ */ jsx39(ShortcutContext.Provider, { value, children });
3427
3839
  }
3428
3840
  function useShortcuts(bindings, options) {
3429
- const context = React12.useContext(ShortcutContext);
3841
+ const context = React13.useContext(ShortcutContext);
3430
3842
  if (!context) {
3431
3843
  throw new Error("useShortcuts must be called inside a ShortcutProvider");
3432
3844
  }
3433
3845
  const { manager, depth } = context;
3434
- const registration = React12.useRef(null);
3435
- const latest = React12.useRef({ bindings, options });
3846
+ const registration = React13.useRef(null);
3847
+ const latest = React13.useRef({ bindings, options });
3436
3848
  useIsomorphicLayoutEffect(() => {
3437
3849
  registration.current = manager.register([], {
3438
3850
  name: latest.current.options.name,
@@ -3449,12 +3861,13 @@ function useShortcuts(bindings, options) {
3449
3861
  name: options.name,
3450
3862
  depth,
3451
3863
  enabled: options.enabled,
3452
- blocking: options.blocking
3864
+ blocking: options.blocking,
3865
+ priority: options.priority
3453
3866
  });
3454
3867
  });
3455
3868
  }
3456
3869
  function useShortcutManager() {
3457
- const context = React12.useContext(ShortcutContext);
3870
+ const context = React13.useContext(ShortcutContext);
3458
3871
  if (!context) {
3459
3872
  throw new Error(
3460
3873
  "useShortcutManager must be called inside a ShortcutProvider"
@@ -3464,7 +3877,7 @@ function useShortcutManager() {
3464
3877
  }
3465
3878
  function useActiveShortcuts() {
3466
3879
  const manager = useShortcutManager();
3467
- return React12.useSyncExternalStore(
3880
+ return React13.useSyncExternalStore(
3468
3881
  manager.subscribe,
3469
3882
  manager.activeBindings,
3470
3883
  manager.activeBindings
@@ -3505,6 +3918,7 @@ export {
3505
3918
  Collapsible,
3506
3919
  CollapsibleContent2 as CollapsibleContent,
3507
3920
  CollapsibleTrigger2 as CollapsibleTrigger,
3921
+ ColorPicker,
3508
3922
  Command,
3509
3923
  CommandDialog,
3510
3924
  CommandEmpty,
@@ -3626,6 +4040,7 @@ export {
3626
4040
  badgeVariants,
3627
4041
  buttonVariants,
3628
4042
  cardVariants,
4043
+ commandDefaultFilter,
3629
4044
  createShortcutManager,
3630
4045
  dialogContentVariants,
3631
4046
  inputVariants,