@campfire-interactive/ui 0.1.0 → 0.2.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.
package/dist/index.d.ts CHANGED
@@ -494,6 +494,71 @@ interface SelectProps<T extends string = string> {
494
494
  */
495
495
  declare function Select<T extends string = string>({ options, value, onValueChange, defaultValue, placeholder, size, invalid, disabled, required, name, id, className, fullWidth, emptyLabel, onOpenChange, onBlur, ...aria }: SelectProps<T>): react.JSX.Element;
496
496
 
497
+ interface CreatableSelectProps<T extends string = string> extends SelectProps<T> {
498
+ /**
499
+ * Creates a new option from the typed label and returns it. The returned
500
+ * option is selected immediately, so the caller does not have to wait for
501
+ * its own list query to refetch before the field reads correctly.
502
+ *
503
+ * Reject to keep the dialog open with the message showing and the text
504
+ * intact — a name that collides server-side is the common case, and losing
505
+ * what they typed to learn that is the wrong trade.
506
+ *
507
+ * Omit it and this is a plain `Select`; the "+" does not render at all.
508
+ */
509
+ onCreate?: (label: string) => Promise<SelectOption<T>> | SelectOption<T>;
510
+ /**
511
+ * Whether this viewer may add to the list. False HIDES the "+" rather than
512
+ * disabling it: the lists behind these pickers are tenant configuration, and
513
+ * a disabled button advertises an action most people on a program will never
514
+ * be allowed to take.
515
+ */
516
+ canCreate?: boolean;
517
+ className?: string;
518
+ /** Accessible name and tooltip on the "+". */
519
+ addLabel?: string;
520
+ createTitle?: string;
521
+ createDescription?: React.ReactNode;
522
+ createFieldLabel?: string;
523
+ createPlaceholder?: string;
524
+ createSubmitLabel?: string;
525
+ createPendingLabel?: string;
526
+ createCancelLabel?: string;
527
+ /** Shown while the typed name already matches an option. */
528
+ duplicateHint?: string;
529
+ }
530
+ /**
531
+ * A select whose list can be extended without leaving the page.
532
+ *
533
+ * Every one of these lists is tenant configuration maintained on a Settings
534
+ * screen — work categories, health categories, process types, gate types,
535
+ * team roles. The cost of that is paid by the person filling in a form, who
536
+ * finds the value they need is not there yet and has to abandon what they are
537
+ * doing, navigate to Settings, add it, come back and start again. In practice
538
+ * they do not: they pick the closest wrong option, or the field gets widened
539
+ * to free text and the list stops meaning anything. pm's team-member role was
540
+ * free text for exactly that reason and grew "Tool Engineer", "tool eng" and
541
+ * "Tooling Eng" as three separate roles.
542
+ *
543
+ * So the "+" is not a convenience. It is what lets a constrained list stay
544
+ * constrained.
545
+ *
546
+ * Two behaviors are deliberate and easy to lose in a reimplementation:
547
+ *
548
+ * - A name that already exists selects the existing option instead of
549
+ * creating a second one. The duplicate is what the picker exists to
550
+ * prevent, and the person typing it wants that value either way.
551
+ * - The created option is held locally and merged into `options` until the
552
+ * caller's own list catches up. Without that, an optimistic close lands on
553
+ * an empty field for as long as the refetch takes, which reads as a failed
554
+ * save.
555
+ *
556
+ * Wraps `Select`, so the list is the short, known kind. Reach for `Combobox`
557
+ * when it needs searching; a creatable combobox can follow the first caller
558
+ * that actually needs one.
559
+ */
560
+ declare function CreatableSelect<T extends string = string>({ onCreate, canCreate, className, addLabel, createTitle, createDescription, createFieldLabel, createPlaceholder, createSubmitLabel, createPendingLabel, createCancelLabel, duplicateHint, options, onValueChange, disabled, ...select }: CreatableSelectProps<T>): react.JSX.Element;
561
+
497
562
  interface ComboboxOption<T extends string = string> {
498
563
  value: T;
499
564
  label: string;
@@ -1221,4 +1286,4 @@ declare function formatNumber(value: number | null | undefined, decimals?: numbe
1221
1286
  */
1222
1287
  declare function formatPercent(value: number | null | undefined, decimals?: number): string;
1223
1288
 
1224
- export { Accordion, AccordionContent, AccordionItem, type AccordionProps, AccordionRoot, type AccordionSection, AccordionTrigger, type AccordionTriggerProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardBody, CardDescription, CardFooter, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, Checkbox, type CheckboxProps, type ClassValue, Combobox, type ComboboxOption, type ComboboxProps, ComingSoon, type ComingSoonProps, ConfirmDialog, type ConfirmDialogProps, CountBadge, type CountBadgeProps, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, DialogFooter, DialogHeader, DialogPortal, DialogRoot, type DialogSize, DialogTitle, DialogTrigger, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, Field, type FieldProps, Fieldset, type FieldsetProps, IconButton, type IconButtonProps, Input, type InputProps, type InputSize, Label, type LabelProps, LoadingState, type LoadingStateProps, Menu, type MenuAction, MenuCheckboxItem, MenuContent, MenuGroup, MenuItem, type MenuItemProps, MenuLabel, type MenuProps, MenuRadioGroup, MenuRadioItem, MenuRoot, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Modal, type ModalProps, type MoneyOptions, Pagination, type PaginationProps, Popover, PopoverAnchor, PopoverClose, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverRoot, PopoverTrigger, Progress, type ProgressProps, ScrollArea, type ScrollAreaProps, SearchInput, type SearchInputProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, type SelectOption, type SelectProps, SelectRoot, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, type SeparatorProps, Sheet, SheetBody, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetPortal, SheetTitle, SheetTrigger, SideModal, Skeleton, type SkeletonProps, Slider, type SliderProps, type SortDirection, type SortState, Switch, type SwitchProps, type TabDefinition, TabSet, type TabSetProps, Table, TableBody, TableCaption, TableCell, type TableCellProps, TableEmpty, TableFoot, TableFooter, TableHead, type TableHeadProps, TableHeader, type TableProps, TableRow, type TableRowProps, TableScroller, Tabs, TabsContent, TabsList, type TabsListProps, TabsRoot, TabsTrigger, type TabsTriggerProps, Textarea, type TextareaProps, type ToastOptions, ToastProvider, type ToastProviderProps, type ToastTone, ToggleGroup, type ToggleGroupProps, type ToggleOption, Tooltip, TooltipContent, type TooltipContentProps, type TooltipProps, TooltipProvider, TooltipRoot, TooltipTrigger, type UseSortStateResult, cn, formatDate, formatDateTime, formatMoney, formatNumber, formatPercent, useFieldControl, useSortState, useToast };
1289
+ export { Accordion, AccordionContent, AccordionItem, type AccordionProps, AccordionRoot, type AccordionSection, AccordionTrigger, type AccordionTriggerProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardBody, CardDescription, CardFooter, CardHeader, type CardHeaderProps, type CardProps, CardTitle, type CardTitleProps, Checkbox, type CheckboxProps, type ClassValue, Combobox, type ComboboxOption, type ComboboxProps, ComingSoon, type ComingSoonProps, ConfirmDialog, type ConfirmDialogProps, CountBadge, type CountBadgeProps, CreatableSelect, type CreatableSelectProps, Dialog, DialogBody, DialogClose, DialogContent, type DialogContentProps, DialogDescription, DialogFooter, DialogHeader, DialogPortal, DialogRoot, type DialogSize, DialogTitle, DialogTrigger, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, Field, type FieldProps, Fieldset, type FieldsetProps, IconButton, type IconButtonProps, Input, type InputProps, type InputSize, Label, type LabelProps, LoadingState, type LoadingStateProps, Menu, type MenuAction, MenuCheckboxItem, MenuContent, MenuGroup, MenuItem, type MenuItemProps, MenuLabel, type MenuProps, MenuRadioGroup, MenuRadioItem, MenuRoot, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Modal, type ModalProps, type MoneyOptions, Pagination, type PaginationProps, Popover, PopoverAnchor, PopoverClose, PopoverContent, type PopoverContentProps, type PopoverProps, PopoverRoot, PopoverTrigger, Progress, type ProgressProps, ScrollArea, type ScrollAreaProps, SearchInput, type SearchInputProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, type SelectOption, type SelectProps, SelectRoot, SelectSeparator, SelectTrigger, type SelectTriggerProps, SelectValue, Separator, type SeparatorProps, Sheet, SheetBody, SheetClose, SheetContent, type SheetContentProps, SheetDescription, SheetFooter, SheetHeader, SheetPortal, SheetTitle, SheetTrigger, SideModal, Skeleton, type SkeletonProps, Slider, type SliderProps, type SortDirection, type SortState, Switch, type SwitchProps, type TabDefinition, TabSet, type TabSetProps, Table, TableBody, TableCaption, TableCell, type TableCellProps, TableEmpty, TableFoot, TableFooter, TableHead, type TableHeadProps, TableHeader, type TableProps, TableRow, type TableRowProps, TableScroller, Tabs, TabsContent, TabsList, type TabsListProps, TabsRoot, TabsTrigger, type TabsTriggerProps, Textarea, type TextareaProps, type ToastOptions, ToastProvider, type ToastProviderProps, type ToastTone, ToggleGroup, type ToggleGroupProps, type ToggleOption, Tooltip, TooltipContent, type TooltipContentProps, type TooltipProps, TooltipProvider, TooltipRoot, TooltipTrigger, type UseSortStateResult, cn, formatDate, formatDateTime, formatMoney, formatNumber, formatPercent, useFieldControl, useSortState, useToast };
package/dist/index.js CHANGED
@@ -724,15 +724,162 @@ function Select({
724
724
  );
725
725
  }
726
726
 
727
+ // src/CreatableSelect.tsx
728
+ import { useMemo, useState } from "react";
729
+ import { Plus } from "lucide-react";
730
+
731
+ // src/CreatableSelect.css
732
+ styleInject("@layer components {\n :where(.cfi-creatable) {\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-sm);\n width: 100%;\n }\n :where(.cfi-creatable__select) {\n flex: 1 1 auto;\n min-width: 0;\n }\n :where(.cfi-creatable) > :where(button) {\n flex: 0 0 auto;\n }\n}\n");
733
+
734
+ // src/CreatableSelect.tsx
735
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
736
+ function normalize(value) {
737
+ return value.trim().toLowerCase();
738
+ }
739
+ function labelText(option) {
740
+ return typeof option.label === "string" ? option.label : null;
741
+ }
742
+ function CreatableSelect({
743
+ onCreate,
744
+ canCreate = true,
745
+ className,
746
+ addLabel = "Add to list",
747
+ createTitle = "Add to list",
748
+ createDescription,
749
+ createFieldLabel = "Name",
750
+ createPlaceholder,
751
+ createSubmitLabel = "Add",
752
+ createPendingLabel = "Adding...",
753
+ createCancelLabel = "Cancel",
754
+ duplicateHint = "Already in the list \u2014 this will select the existing one.",
755
+ options,
756
+ onValueChange,
757
+ disabled,
758
+ ...select
759
+ }) {
760
+ const [open, setOpen] = useState(false);
761
+ const [draft, setDraft] = useState("");
762
+ const [pending, setPending] = useState(false);
763
+ const [error, setError] = useState(null);
764
+ const [created, setCreated] = useState([]);
765
+ const merged = useMemo(() => {
766
+ const seen = new Set(options.map((o) => o.value));
767
+ return [...options, ...created.filter((o) => !seen.has(o.value))];
768
+ }, [options, created]);
769
+ const match = useMemo(() => {
770
+ const wanted = normalize(draft);
771
+ if (wanted === "") return null;
772
+ return merged.find((o) => {
773
+ const text = labelText(o);
774
+ return text !== null && normalize(text) === wanted;
775
+ }) ?? null;
776
+ }, [draft, merged]);
777
+ const showAdd = Boolean(onCreate) && canCreate && !disabled;
778
+ function close() {
779
+ setOpen(false);
780
+ setDraft("");
781
+ setError(null);
782
+ setPending(false);
783
+ }
784
+ async function submit() {
785
+ const name = draft.trim();
786
+ if (name === "" || pending || !onCreate) return;
787
+ if (match) {
788
+ onValueChange?.(match.value);
789
+ close();
790
+ return;
791
+ }
792
+ setPending(true);
793
+ setError(null);
794
+ try {
795
+ const option = await onCreate(name);
796
+ setCreated((prev) => [...prev, option]);
797
+ onValueChange?.(option.value);
798
+ close();
799
+ } catch (cause) {
800
+ setError(cause instanceof Error ? cause.message : String(cause));
801
+ setPending(false);
802
+ }
803
+ }
804
+ return /* @__PURE__ */ jsxs11("div", { className: cn("cfi-creatable", className), children: [
805
+ /* @__PURE__ */ jsx11("div", { className: "cfi-creatable__select", children: /* @__PURE__ */ jsx11(Select, { ...select, options: merged, onValueChange, disabled }) }),
806
+ showAdd && /* @__PURE__ */ jsx11(
807
+ IconButton,
808
+ {
809
+ type: "button",
810
+ variant: "secondary",
811
+ size: select.size ?? "md",
812
+ icon: /* @__PURE__ */ jsx11(Plus, { "aria-hidden": "true" }),
813
+ label: addLabel,
814
+ onClick: () => setOpen(true)
815
+ }
816
+ ),
817
+ /* @__PURE__ */ jsx11(
818
+ Modal,
819
+ {
820
+ open,
821
+ onOpenChange: (next) => next ? setOpen(true) : close(),
822
+ title: createTitle,
823
+ description: createDescription,
824
+ size: "sm",
825
+ footer: /* @__PURE__ */ jsxs11(ButtonGroup, { children: [
826
+ /* @__PURE__ */ jsx11(Button, { type: "button", variant: "secondary", onClick: close, disabled: pending, children: createCancelLabel }),
827
+ /* @__PURE__ */ jsx11(
828
+ Button,
829
+ {
830
+ type: "button",
831
+ loading: pending,
832
+ onClick: () => void submit(),
833
+ disabled: pending || draft.trim() === "",
834
+ children: pending ? createPendingLabel : createSubmitLabel
835
+ }
836
+ )
837
+ ] }),
838
+ children: /* @__PURE__ */ jsxs11(
839
+ "form",
840
+ {
841
+ onSubmit: (event) => {
842
+ event.preventDefault();
843
+ void submit();
844
+ },
845
+ children: [
846
+ /* @__PURE__ */ jsx11(
847
+ Field,
848
+ {
849
+ label: createFieldLabel,
850
+ required: true,
851
+ error,
852
+ hint: match ? duplicateHint : void 0,
853
+ children: /* @__PURE__ */ jsx11(
854
+ Input,
855
+ {
856
+ value: draft,
857
+ onChange: (event) => setDraft(event.target.value),
858
+ placeholder: createPlaceholder,
859
+ disabled: pending,
860
+ autoFocus: true
861
+ }
862
+ )
863
+ }
864
+ ),
865
+ /* @__PURE__ */ jsx11("button", { type: "submit", hidden: true, "aria-hidden": "true", tabIndex: -1 })
866
+ ]
867
+ }
868
+ )
869
+ }
870
+ )
871
+ ] });
872
+ }
873
+
727
874
  // src/Combobox.tsx
728
- import { useEffect, useId as useId2, useMemo, useRef, useState } from "react";
875
+ import { useEffect, useId as useId2, useMemo as useMemo2, useRef, useState as useState2 } from "react";
729
876
  import { Check as Check4, ChevronDown as ChevronDown2, Search, X as X2 } from "lucide-react";
730
877
 
731
878
  // src/Combobox.css
732
879
  styleInject("@layer components {\n .cfi-ui-combobox {\n position: relative;\n display: inline-flex;\n align-items: center;\n }\n .cfi-ui-combobox--full {\n display: flex;\n width: 100%;\n }\n :where(.cfi-ui-combobox__trigger) {\n display: inline-flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--cfi-ui-space-sm);\n width: 100%;\n height: var(--cfi-ui-control-height-md);\n padding-inline: 0.625rem;\n background: var(--cfi-ui-surface);\n color: var(--cfi-ui-content);\n border: 1px solid var(--cfi-ui-border-strong);\n border-radius: var(--cfi-ui-radius-md);\n font-family: inherit;\n font-size: var(--cfi-ui-text-sm);\n line-height: normal;\n cursor: pointer;\n transition: border-color var(--cfi-ui-transition-fast);\n }\n .cfi-ui-combobox__trigger:hover:not(:disabled) {\n border-color: var(--cfi-ui-content-subtle);\n }\n .cfi-ui-combobox__trigger:disabled {\n background: var(--cfi-ui-surface-disabled);\n color: var(--cfi-ui-content-disabled);\n cursor: not-allowed;\n }\n .cfi-ui-combobox__trigger[data-invalid] {\n border-color: var(--cfi-ui-error);\n }\n .cfi-ui-combobox__trigger[data-size=sm] {\n height: var(--cfi-ui-control-height-sm);\n padding-inline: 0.5rem;\n font-size: var(--cfi-ui-text-xs);\n }\n .cfi-ui-combobox__trigger[data-size=lg] {\n height: var(--cfi-ui-control-height-lg);\n padding-inline: 0.875rem;\n font-size: var(--cfi-ui-text-base);\n }\n .cfi-ui-combobox__trigger[data-placeholder] .cfi-ui-combobox__value {\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-combobox__value {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n }\n .cfi-ui-combobox__chevron {\n display: inline-flex;\n flex: none;\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-combobox__chevron > svg,\n .cfi-ui-combobox__clear > svg {\n width: 0.875rem;\n height: 0.875rem;\n display: block;\n }\n .cfi-ui-combobox__clear {\n position: absolute;\n right: 1.75rem;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n padding: 0;\n border: 0;\n border-radius: var(--cfi-ui-radius-sm);\n background: transparent;\n color: var(--cfi-ui-content-muted);\n cursor: pointer;\n }\n .cfi-ui-combobox__clear:hover {\n background: var(--cfi-ui-surface-active);\n color: var(--cfi-ui-content);\n }\n .cfi-ui-combobox__panel {\n display: flex;\n flex-direction: column;\n overflow: hidden;\n max-height: min(22rem, var(--radix-popover-content-available-height, 22rem));\n }\n .cfi-ui-combobox__search {\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-sm);\n padding: var(--cfi-ui-space-sm);\n border-bottom: 1px solid var(--cfi-ui-border);\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-combobox__search > svg {\n width: 0.875rem;\n height: 0.875rem;\n flex: none;\n }\n .cfi-ui-combobox__search input {\n flex: 1 1 auto;\n min-width: 0;\n border: 0;\n background: transparent;\n color: var(--cfi-ui-content);\n font-family: inherit;\n font-size: var(--cfi-ui-text-sm);\n outline: none;\n }\n .cfi-ui-combobox__search input::placeholder {\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-combobox__list {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n padding: var(--cfi-ui-space-xs);\n }\n .cfi-ui-combobox__option {\n align-items: flex-start;\n }\n .cfi-ui-combobox__option > .cfi-ui-select-item__indicator {\n padding-top: 0.125rem;\n }\n .cfi-ui-combobox__option-text {\n display: grid;\n gap: var(--cfi-ui-space-3xs);\n min-width: 0;\n }\n .cfi-ui-combobox__option-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .cfi-ui-combobox__option-hint {\n font-size: var(--cfi-ui-text-xs);\n color: var(--cfi-ui-content-muted);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n}\n");
733
880
 
734
881
  // src/Combobox.tsx
735
- import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
882
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
736
883
  function Combobox({
737
884
  options,
738
885
  value,
@@ -754,13 +901,13 @@ function Combobox({
754
901
  fullWidth = true,
755
902
  ...aria
756
903
  }) {
757
- const [open, setOpen] = useState(false);
758
- const [search, setSearch] = useState("");
759
- const [highlighted, setHighlighted] = useState(0);
904
+ const [open, setOpen] = useState2(false);
905
+ const [search, setSearch] = useState2("");
906
+ const [highlighted, setHighlighted] = useState2(0);
760
907
  const listId = useId2();
761
908
  const searchRef = useRef(null);
762
909
  const listRef = useRef(null);
763
- const filtered = useMemo(() => {
910
+ const filtered = useMemo2(() => {
764
911
  if (onSearchChange) return options;
765
912
  const q = search.trim().toLowerCase();
766
913
  if (!q) return options;
@@ -814,14 +961,14 @@ function Combobox({
814
961
  setHighlighted(0);
815
962
  onSearchChange?.(next);
816
963
  }
817
- return /* @__PURE__ */ jsxs11(PopoverRoot, { open, onOpenChange: setOpen, children: [
818
- /* @__PURE__ */ jsx11(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs11(
964
+ return /* @__PURE__ */ jsxs12(PopoverRoot, { open, onOpenChange: setOpen, children: [
965
+ /* @__PURE__ */ jsx12(PopoverAnchor, { asChild: true, children: /* @__PURE__ */ jsxs12(
819
966
  "div",
820
967
  {
821
968
  style,
822
969
  className: cn("cfi-ui", "cfi-ui-combobox", fullWidth && "cfi-ui-combobox--full", className),
823
970
  children: [
824
- /* @__PURE__ */ jsxs11(
971
+ /* @__PURE__ */ jsxs12(
825
972
  "button",
826
973
  {
827
974
  type: "button",
@@ -838,12 +985,12 @@ function Combobox({
838
985
  onClick: () => setOpen((o) => !o),
839
986
  ...aria,
840
987
  children: [
841
- /* @__PURE__ */ jsx11("span", { className: "cfi-ui-combobox__value", children: selected ? selected.label : placeholder }),
842
- /* @__PURE__ */ jsx11("span", { className: "cfi-ui-combobox__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx11(ChevronDown2, {}) })
988
+ /* @__PURE__ */ jsx12("span", { className: "cfi-ui-combobox__value", children: selected ? selected.label : placeholder }),
989
+ /* @__PURE__ */ jsx12("span", { className: "cfi-ui-combobox__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx12(ChevronDown2, {}) })
843
990
  ]
844
991
  }
845
992
  ),
846
- clearable && selected && !disabled && /* @__PURE__ */ jsx11(
993
+ clearable && selected && !disabled && /* @__PURE__ */ jsx12(
847
994
  "button",
848
995
  {
849
996
  type: "button",
@@ -851,14 +998,14 @@ function Combobox({
851
998
  "aria-label": `Clear ${selected.label}`,
852
999
  title: "Clear",
853
1000
  onClick: () => onValueChange(null),
854
- children: /* @__PURE__ */ jsx11(X2, { "aria-hidden": "true" })
1001
+ children: /* @__PURE__ */ jsx12(X2, { "aria-hidden": "true" })
855
1002
  }
856
1003
  ),
857
- name && /* @__PURE__ */ jsx11("input", { type: "hidden", name, value: value ?? "" })
1004
+ name && /* @__PURE__ */ jsx12("input", { type: "hidden", name, value: value ?? "" })
858
1005
  ]
859
1006
  }
860
1007
  ) }),
861
- /* @__PURE__ */ jsxs11(
1008
+ /* @__PURE__ */ jsxs12(
862
1009
  PopoverContent,
863
1010
  {
864
1011
  flush: true,
@@ -870,9 +1017,9 @@ function Combobox({
870
1017
  },
871
1018
  style: { width: "var(--radix-popover-trigger-width)" },
872
1019
  children: [
873
- /* @__PURE__ */ jsxs11("div", { className: "cfi-ui-combobox__search", children: [
874
- /* @__PURE__ */ jsx11(Search, { "aria-hidden": "true" }),
875
- /* @__PURE__ */ jsx11(
1020
+ /* @__PURE__ */ jsxs12("div", { className: "cfi-ui-combobox__search", children: [
1021
+ /* @__PURE__ */ jsx12(Search, { "aria-hidden": "true" }),
1022
+ /* @__PURE__ */ jsx12(
876
1023
  "input",
877
1024
  {
878
1025
  ref: searchRef,
@@ -888,7 +1035,7 @@ function Combobox({
888
1035
  }
889
1036
  )
890
1037
  ] }),
891
- /* @__PURE__ */ jsx11(
1038
+ /* @__PURE__ */ jsx12(
892
1039
  "div",
893
1040
  {
894
1041
  ref: listRef,
@@ -896,10 +1043,10 @@ function Combobox({
896
1043
  role: "listbox",
897
1044
  "aria-busy": loading || void 0,
898
1045
  className: "cfi-ui-combobox__list",
899
- children: loading ? /* @__PURE__ */ jsx11("p", { className: "cfi-ui-select-empty", children: loadingLabel }) : filtered.length === 0 ? /* @__PURE__ */ jsx11("p", { className: "cfi-ui-select-empty", children: emptyLabel }) : filtered.map((option) => {
1046
+ children: loading ? /* @__PURE__ */ jsx12("p", { className: "cfi-ui-select-empty", children: loadingLabel }) : filtered.length === 0 ? /* @__PURE__ */ jsx12("p", { className: "cfi-ui-select-empty", children: emptyLabel }) : filtered.map((option) => {
900
1047
  const index = selectable.indexOf(option);
901
1048
  const isHighlighted = index !== -1 && index === highlighted;
902
- return /* @__PURE__ */ jsxs11(
1049
+ return /* @__PURE__ */ jsxs12(
903
1050
  "div",
904
1051
  {
905
1052
  id: `${listId}-${option.value}`,
@@ -912,10 +1059,10 @@ function Combobox({
912
1059
  onClick: () => !option.disabled && commit(option),
913
1060
  onPointerMove: () => index !== -1 && setHighlighted(index),
914
1061
  children: [
915
- /* @__PURE__ */ jsx11("span", { className: "cfi-ui-select-item__indicator", children: option.value === value && /* @__PURE__ */ jsx11(Check4, { "aria-hidden": "true" }) }),
916
- /* @__PURE__ */ jsxs11("span", { className: "cfi-ui-combobox__option-text", children: [
917
- /* @__PURE__ */ jsx11("span", { className: "cfi-ui-combobox__option-label", children: option.label }),
918
- option.hint && /* @__PURE__ */ jsx11("span", { className: "cfi-ui-combobox__option-hint", children: option.hint })
1062
+ /* @__PURE__ */ jsx12("span", { className: "cfi-ui-select-item__indicator", children: option.value === value && /* @__PURE__ */ jsx12(Check4, { "aria-hidden": "true" }) }),
1063
+ /* @__PURE__ */ jsxs12("span", { className: "cfi-ui-combobox__option-text", children: [
1064
+ /* @__PURE__ */ jsx12("span", { className: "cfi-ui-combobox__option-label", children: option.label }),
1065
+ option.hint && /* @__PURE__ */ jsx12("span", { className: "cfi-ui-combobox__option-hint", children: option.hint })
919
1066
  ] })
920
1067
  ]
921
1068
  },
@@ -933,12 +1080,12 @@ function Combobox({
933
1080
  // src/Tooltip.tsx
934
1081
  import { forwardRef as forwardRef10 } from "react";
935
1082
  import * as RadixTooltip from "@radix-ui/react-tooltip";
936
- import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
1083
+ import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
937
1084
  var TooltipProvider = RadixTooltip.Provider;
938
1085
  var TooltipRoot = RadixTooltip.Root;
939
1086
  var TooltipTrigger = RadixTooltip.Trigger;
940
1087
  var TooltipContent = forwardRef10(function TooltipContent2({ className, children, sideOffset = 5, ...rest }, ref) {
941
- return /* @__PURE__ */ jsx12(RadixTooltip.Portal, { children: /* @__PURE__ */ jsxs12(
1088
+ return /* @__PURE__ */ jsx13(RadixTooltip.Portal, { children: /* @__PURE__ */ jsxs13(
942
1089
  RadixTooltip.Content,
943
1090
  {
944
1091
  ref,
@@ -949,28 +1096,28 @@ var TooltipContent = forwardRef10(function TooltipContent2({ className, children
949
1096
  ...rest,
950
1097
  children: [
951
1098
  children,
952
- /* @__PURE__ */ jsx12(RadixTooltip.Arrow, { className: "cfi-ui-tooltip__arrow", width: 10, height: 4 })
1099
+ /* @__PURE__ */ jsx13(RadixTooltip.Arrow, { className: "cfi-ui-tooltip__arrow", width: 10, height: 4 })
953
1100
  ]
954
1101
  }
955
1102
  ) });
956
1103
  });
957
1104
  function Tooltip({ content, side = "top", align = "center", delay = 300, disabled, children }) {
958
- if (disabled || content == null || content === "") return /* @__PURE__ */ jsx12(Fragment3, { children });
959
- return /* @__PURE__ */ jsx12(RadixTooltip.Provider, { delayDuration: delay, children: /* @__PURE__ */ jsxs12(TooltipRoot, { children: [
960
- /* @__PURE__ */ jsx12(TooltipTrigger, { asChild: true, children }),
961
- /* @__PURE__ */ jsx12(TooltipContent, { side, align, children: content })
1105
+ if (disabled || content == null || content === "") return /* @__PURE__ */ jsx13(Fragment3, { children });
1106
+ return /* @__PURE__ */ jsx13(RadixTooltip.Provider, { delayDuration: delay, children: /* @__PURE__ */ jsxs13(TooltipRoot, { children: [
1107
+ /* @__PURE__ */ jsx13(TooltipTrigger, { asChild: true, children }),
1108
+ /* @__PURE__ */ jsx13(TooltipContent, { side, align, children: content })
962
1109
  ] }) });
963
1110
  }
964
1111
 
965
1112
  // src/Toast.tsx
966
- import { createContext as createContext2, useCallback, useContext as useContext2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
1113
+ import { createContext as createContext2, useCallback, useContext as useContext2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState as useState3 } from "react";
967
1114
  import { AlertTriangle, CheckCircle2, Info, X as X3, XCircle } from "lucide-react";
968
1115
 
969
1116
  // src/Toast.css
970
1117
  styleInject("@layer components {\n .cfi-ui-toast-viewport {\n position: fixed;\n z-index: var(--cfi-ui-z-toast);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-ui-space-sm);\n width: min(24rem, calc(100vw - 2 * var(--cfi-ui-space-md)));\n pointer-events: none;\n }\n .cfi-ui-toast-viewport[data-position=bottom-right] {\n right: var(--cfi-ui-space-md);\n bottom: var(--cfi-ui-space-md);\n }\n .cfi-ui-toast-viewport[data-position=top-right] {\n right: var(--cfi-ui-space-md);\n top: calc(var(--cfi-shell-header-height, 48px) + var(--cfi-ui-space-md));\n flex-direction: column-reverse;\n }\n .cfi-ui-toast-viewport[data-position=bottom-center] {\n left: 50%;\n bottom: var(--cfi-ui-space-md);\n transform: translateX(-50%);\n }\n .cfi-ui-toast-viewport[data-position=top-center] {\n left: 50%;\n top: calc(var(--cfi-shell-header-height, 48px) + var(--cfi-ui-space-md));\n transform: translateX(-50%);\n flex-direction: column-reverse;\n }\n .cfi-ui-toast {\n pointer-events: auto;\n display: grid;\n grid-template-columns: auto 1fr auto;\n gap: var(--cfi-ui-space-sm);\n align-items: start;\n padding: var(--cfi-ui-space-sm) var(--cfi-ui-space-sm) var(--cfi-ui-space-sm) var(--cfi-ui-space-md);\n background: var(--cfi-ui-surface-raised);\n color: var(--cfi-ui-content);\n border: 1px solid var(--cfi-ui-border);\n border-left: 3px solid var(--cfi-ui-border-strong);\n border-radius: var(--cfi-ui-radius-md);\n box-shadow: var(--cfi-ui-shadow-lg);\n font-family: var(--cfi-ui-font);\n animation: cfi-ui-zoom-in var(--cfi-ui-transition-base);\n }\n .cfi-ui-toast[data-tone=success] {\n border-left-color: var(--cfi-ui-success);\n }\n .cfi-ui-toast[data-tone=warning] {\n border-left-color: var(--cfi-ui-warning);\n }\n .cfi-ui-toast[data-tone=error] {\n border-left-color: var(--cfi-ui-error);\n }\n .cfi-ui-toast[data-tone=info] {\n border-left-color: var(--cfi-ui-info);\n }\n .cfi-ui-toast__icon {\n display: inline-flex;\n flex: none;\n padding-top: 0.0625rem;\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-toast[data-tone=success] .cfi-ui-toast__icon {\n color: var(--cfi-ui-success-text);\n }\n .cfi-ui-toast[data-tone=warning] .cfi-ui-toast__icon {\n color: var(--cfi-ui-warning-text);\n }\n .cfi-ui-toast[data-tone=error] .cfi-ui-toast__icon {\n color: var(--cfi-ui-error-text);\n }\n .cfi-ui-toast[data-tone=info] .cfi-ui-toast__icon {\n color: var(--cfi-ui-info-text);\n }\n .cfi-ui-toast__icon > svg {\n width: 1rem;\n height: 1rem;\n display: block;\n }\n .cfi-ui-toast__text {\n display: grid;\n gap: var(--cfi-ui-space-3xs);\n min-width: 0;\n }\n .cfi-ui-toast__title {\n margin: 0;\n font-size: var(--cfi-ui-text-sm);\n font-weight: var(--cfi-ui-weight-medium);\n line-height: var(--cfi-ui-leading-normal);\n }\n .cfi-ui-toast__description {\n margin: 0;\n font-size: var(--cfi-ui-text-xs);\n line-height: var(--cfi-ui-leading-normal);\n color: var(--cfi-ui-content-muted);\n overflow-wrap: anywhere;\n }\n .cfi-ui-toast__action {\n justify-self: start;\n margin-top: var(--cfi-ui-space-xs);\n padding: 0;\n border: 0;\n background: none;\n color: var(--cfi-ui-content-link);\n font-family: inherit;\n font-size: var(--cfi-ui-text-xs);\n font-weight: var(--cfi-ui-weight-medium);\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n }\n .cfi-ui-toast__close {\n flex: none;\n color: var(--cfi-ui-content-muted);\n }\n}\n");
971
1118
 
972
1119
  // src/Toast.tsx
973
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
1120
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
974
1121
  var ToastContext = createContext2(null);
975
1122
  function useToast() {
976
1123
  const api = useContext2(ToastContext);
@@ -983,7 +1130,7 @@ function ToastProvider({
983
1130
  max = 4,
984
1131
  position = "bottom-right"
985
1132
  }) {
986
- const [items, setItems] = useState2([]);
1133
+ const [items, setItems] = useState3([]);
987
1134
  const nextId = useRef2(1);
988
1135
  const timers = useRef2(/* @__PURE__ */ new Map());
989
1136
  const dismiss = useCallback((id) => {
@@ -1017,7 +1164,7 @@ function ToastProvider({
1017
1164
  pending.clear();
1018
1165
  };
1019
1166
  }, []);
1020
- const api = useMemo2(
1167
+ const api = useMemo3(
1021
1168
  () => ({
1022
1169
  toast,
1023
1170
  dismiss,
@@ -1028,24 +1175,24 @@ function ToastProvider({
1028
1175
  }),
1029
1176
  [toast, dismiss]
1030
1177
  );
1031
- return /* @__PURE__ */ jsxs13(ToastContext.Provider, { value: api, children: [
1178
+ return /* @__PURE__ */ jsxs14(ToastContext.Provider, { value: api, children: [
1032
1179
  children,
1033
- /* @__PURE__ */ jsx13(ToastViewport, { items, onDismiss: dismiss, position })
1180
+ /* @__PURE__ */ jsx14(ToastViewport, { items, onDismiss: dismiss, position })
1034
1181
  ] });
1035
1182
  }
1036
1183
  var TONE_ICON = {
1037
- neutral: /* @__PURE__ */ jsx13(Info, {}),
1038
- info: /* @__PURE__ */ jsx13(Info, {}),
1039
- success: /* @__PURE__ */ jsx13(CheckCircle2, {}),
1040
- warning: /* @__PURE__ */ jsx13(AlertTriangle, {}),
1041
- error: /* @__PURE__ */ jsx13(XCircle, {})
1184
+ neutral: /* @__PURE__ */ jsx14(Info, {}),
1185
+ info: /* @__PURE__ */ jsx14(Info, {}),
1186
+ success: /* @__PURE__ */ jsx14(CheckCircle2, {}),
1187
+ warning: /* @__PURE__ */ jsx14(AlertTriangle, {}),
1188
+ error: /* @__PURE__ */ jsx14(XCircle, {})
1042
1189
  };
1043
1190
  function ToastViewport({
1044
1191
  items,
1045
1192
  onDismiss,
1046
1193
  position
1047
1194
  }) {
1048
- return /* @__PURE__ */ jsx13(
1195
+ return /* @__PURE__ */ jsx14(
1049
1196
  "div",
1050
1197
  {
1051
1198
  role: "region",
@@ -1054,12 +1201,12 @@ function ToastViewport({
1054
1201
  "data-position": position,
1055
1202
  "data-cfi-ui-portal": "",
1056
1203
  className: cn("cfi-ui", "cfi-ui-toast-viewport"),
1057
- children: items.map((item) => /* @__PURE__ */ jsxs13("div", { "data-tone": item.tone, className: "cfi-ui-toast", children: [
1058
- /* @__PURE__ */ jsx13("span", { className: "cfi-ui-toast__icon", "aria-hidden": "true", children: TONE_ICON[item.tone ?? "neutral"] }),
1059
- /* @__PURE__ */ jsxs13("div", { className: "cfi-ui-toast__text", children: [
1060
- /* @__PURE__ */ jsx13("p", { className: "cfi-ui-toast__title", children: item.title }),
1061
- item.description && /* @__PURE__ */ jsx13("p", { className: "cfi-ui-toast__description", children: item.description }),
1062
- item.action && /* @__PURE__ */ jsx13(
1204
+ children: items.map((item) => /* @__PURE__ */ jsxs14("div", { "data-tone": item.tone, className: "cfi-ui-toast", children: [
1205
+ /* @__PURE__ */ jsx14("span", { className: "cfi-ui-toast__icon", "aria-hidden": "true", children: TONE_ICON[item.tone ?? "neutral"] }),
1206
+ /* @__PURE__ */ jsxs14("div", { className: "cfi-ui-toast__text", children: [
1207
+ /* @__PURE__ */ jsx14("p", { className: "cfi-ui-toast__title", children: item.title }),
1208
+ item.description && /* @__PURE__ */ jsx14("p", { className: "cfi-ui-toast__description", children: item.description }),
1209
+ item.action && /* @__PURE__ */ jsx14(
1063
1210
  "button",
1064
1211
  {
1065
1212
  type: "button",
@@ -1072,12 +1219,12 @@ function ToastViewport({
1072
1219
  }
1073
1220
  )
1074
1221
  ] }),
1075
- /* @__PURE__ */ jsx13(
1222
+ /* @__PURE__ */ jsx14(
1076
1223
  IconButton,
1077
1224
  {
1078
1225
  variant: "ghost",
1079
1226
  size: "sm",
1080
- icon: /* @__PURE__ */ jsx13(X3, {}),
1227
+ icon: /* @__PURE__ */ jsx14(X3, {}),
1081
1228
  label: "Dismiss",
1082
1229
  className: "cfi-ui-toast__close",
1083
1230
  onClick: () => onDismiss(item.id)
@@ -1095,9 +1242,9 @@ import { forwardRef as forwardRef11 } from "react";
1095
1242
  styleInject("@layer components {\n :where(.cfi-ui-card) {\n display: flex;\n flex-direction: column;\n min-width: 0;\n background: var(--cfi-ui-surface);\n color: var(--cfi-ui-content);\n border: 1px solid var(--cfi-ui-border);\n border-radius: var(--cfi-ui-radius-xl);\n box-shadow: var(--cfi-ui-shadow-xs);\n font-size: var(--cfi-ui-text-sm);\n }\n .cfi-ui-card[data-variant=outline] {\n box-shadow: none;\n }\n .cfi-ui-card[data-variant=plain] {\n border-color: transparent;\n box-shadow: none;\n background: transparent;\n }\n .cfi-ui-card[data-interactive] {\n cursor: pointer;\n transition: border-color var(--cfi-ui-transition-fast), box-shadow var(--cfi-ui-transition-fast);\n }\n .cfi-ui-card[data-interactive]:hover {\n border-color: var(--cfi-ui-border-strong);\n box-shadow: var(--cfi-ui-shadow-md);\n }\n :where(.cfi-ui-card__header) {\n flex: none;\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: var(--cfi-ui-space-md);\n padding: var(--cfi-ui-space-md);\n border-bottom: 1px solid var(--cfi-ui-border);\n }\n .cfi-ui-card__heading {\n display: grid;\n gap: var(--cfi-ui-space-3xs);\n min-width: 0;\n }\n .cfi-ui-card__actions {\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-xs);\n flex: none;\n }\n :where(.cfi-ui-card__title) {\n margin: 0;\n font-size: var(--cfi-ui-text-sm);\n font-weight: var(--cfi-ui-weight-semibold);\n line-height: var(--cfi-ui-leading-snug);\n color: var(--cfi-ui-content);\n text-wrap: balance;\n }\n .cfi-ui-card__description {\n flex-basis: 100%;\n margin: 0;\n font-size: var(--cfi-ui-text-xs);\n line-height: var(--cfi-ui-leading-normal);\n color: var(--cfi-ui-content-muted);\n }\n :where(.cfi-ui-card__body) {\n flex: 1 1 auto;\n min-width: 0;\n padding: var(--cfi-ui-space-md);\n }\n .cfi-ui-card[data-flush] > .cfi-ui-card__body {\n padding: 0;\n }\n .cfi-ui-card[data-flush] > .cfi-ui-card__body:last-child {\n overflow: hidden;\n border-bottom-left-radius: var(--cfi-ui-radius-lg);\n border-bottom-right-radius: var(--cfi-ui-radius-lg);\n }\n :where(.cfi-ui-card__footer) {\n flex: none;\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-sm);\n padding: var(--cfi-ui-space-sm) var(--cfi-ui-space-md);\n border-top: 1px solid var(--cfi-ui-border);\n background: var(--cfi-ui-surface-sunken);\n border-bottom-left-radius: var(--cfi-ui-radius-lg);\n border-bottom-right-radius: var(--cfi-ui-radius-lg);\n font-size: var(--cfi-ui-text-xs);\n color: var(--cfi-ui-content-muted);\n }\n}\n");
1096
1243
 
1097
1244
  // src/Card.tsx
1098
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
1245
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1099
1246
  var Card = forwardRef11(function Card2({ variant = "default", flush = false, interactive = false, className, ...rest }, ref) {
1100
- return /* @__PURE__ */ jsx14(
1247
+ return /* @__PURE__ */ jsx15(
1101
1248
  "div",
1102
1249
  {
1103
1250
  ref,
@@ -1110,22 +1257,22 @@ var Card = forwardRef11(function Card2({ variant = "default", flush = false, int
1110
1257
  );
1111
1258
  });
1112
1259
  function CardHeader({ actions, className, children, ...rest }) {
1113
- return /* @__PURE__ */ jsxs14("div", { className: cn("cfi-ui-card__header", className), ...rest, children: [
1114
- actions ? /* @__PURE__ */ jsx14("div", { className: "cfi-ui-card__heading", children }) : children,
1115
- actions && /* @__PURE__ */ jsx14("div", { className: "cfi-ui-card__actions", children: actions })
1260
+ return /* @__PURE__ */ jsxs15("div", { className: cn("cfi-ui-card__header", className), ...rest, children: [
1261
+ actions ? /* @__PURE__ */ jsx15("div", { className: "cfi-ui-card__heading", children }) : children,
1262
+ actions && /* @__PURE__ */ jsx15("div", { className: "cfi-ui-card__actions", children: actions })
1116
1263
  ] });
1117
1264
  }
1118
1265
  function CardTitle({ as: Tag = "h3", className, ...rest }) {
1119
- return /* @__PURE__ */ jsx14(Tag, { className: cn("cfi-ui-card__title", className), ...rest });
1266
+ return /* @__PURE__ */ jsx15(Tag, { className: cn("cfi-ui-card__title", className), ...rest });
1120
1267
  }
1121
1268
  function CardDescription({ className, ...rest }) {
1122
- return /* @__PURE__ */ jsx14("p", { className: cn("cfi-ui-card__description", className), ...rest });
1269
+ return /* @__PURE__ */ jsx15("p", { className: cn("cfi-ui-card__description", className), ...rest });
1123
1270
  }
1124
1271
  function CardBody({ className, ...rest }) {
1125
- return /* @__PURE__ */ jsx14("div", { className: cn("cfi-ui-card__body", className), ...rest });
1272
+ return /* @__PURE__ */ jsx15("div", { className: cn("cfi-ui-card__body", className), ...rest });
1126
1273
  }
1127
1274
  function CardFooter({ className, ...rest }) {
1128
- return /* @__PURE__ */ jsx14("div", { className: cn("cfi-ui-card__footer", className), ...rest });
1275
+ return /* @__PURE__ */ jsx15("div", { className: cn("cfi-ui-card__footer", className), ...rest });
1129
1276
  }
1130
1277
 
1131
1278
  // src/Badge.tsx
@@ -1135,9 +1282,9 @@ import { forwardRef as forwardRef12 } from "react";
1135
1282
  styleInject("@layer components {\n :where(.cfi-ui-badge) {\n display: inline-flex;\n align-items: center;\n gap: var(--cfi-ui-space-xs);\n padding: 0.125rem 0.5rem;\n border: 1px solid transparent;\n border-radius: var(--cfi-ui-radius-full);\n font-size: var(--cfi-ui-text-xs);\n font-weight: var(--cfi-ui-weight-medium);\n line-height: 1.4;\n white-space: nowrap;\n vertical-align: middle;\n }\n .cfi-ui-badge[data-size=sm] {\n padding: 0 0.375rem;\n font-size: 0.6875rem;\n }\n .cfi-ui-badge__dot {\n flex: none;\n width: 0.375rem;\n height: 0.375rem;\n border-radius: var(--cfi-ui-radius-full);\n background: currentColor;\n }\n .cfi-ui-badge__icon {\n display: inline-flex;\n flex: none;\n }\n .cfi-ui-badge__icon > svg {\n width: 0.75rem;\n height: 0.75rem;\n display: block;\n }\n .cfi-ui-badge--count {\n justify-content: center;\n min-width: 1.25rem;\n padding-inline: 0.375rem;\n font-variant-numeric: tabular-nums;\n }\n .cfi-ui-badge[data-variant=soft][data-tone=neutral] {\n background: var(--cfi-ui-neutral-soft);\n color: var(--cfi-ui-neutral-text);\n }\n .cfi-ui-badge[data-variant=soft][data-tone=success] {\n background: var(--cfi-ui-success-soft);\n color: var(--cfi-ui-success-text);\n }\n .cfi-ui-badge[data-variant=soft][data-tone=warning] {\n background: var(--cfi-ui-warning-soft);\n color: var(--cfi-ui-warning-text);\n }\n .cfi-ui-badge[data-variant=soft][data-tone=error] {\n background: var(--cfi-ui-error-soft);\n color: var(--cfi-ui-error-text);\n }\n .cfi-ui-badge[data-variant=soft][data-tone=info] {\n background: var(--cfi-ui-info-soft);\n color: var(--cfi-ui-info-text);\n }\n .cfi-ui-badge[data-variant=soft][data-tone=accent] {\n background: var(--cfi-ui-accent-soft);\n color: var(--cfi-ui-accent-hover);\n }\n .cfi-ui-badge[data-variant=solid] {\n color: var(--cfi-ui-content-inverse);\n }\n .cfi-ui-badge[data-variant=solid][data-tone=neutral] {\n background: var(--cfi-ui-content-muted);\n }\n .cfi-ui-badge[data-variant=solid][data-tone=success] {\n background: var(--cfi-ui-success-text);\n }\n .cfi-ui-badge[data-variant=solid][data-tone=warning] {\n background: var(--cfi-ui-warning-text);\n }\n .cfi-ui-badge[data-variant=solid][data-tone=error] {\n background: var(--cfi-ui-error-text);\n }\n .cfi-ui-badge[data-variant=solid][data-tone=info] {\n background: var(--cfi-ui-info-text);\n }\n .cfi-ui-badge[data-variant=solid][data-tone=accent] {\n background: var(--cfi-ui-accent);\n color: var(--cfi-ui-accent-fg);\n }\n .cfi-ui-badge[data-variant=outline] {\n background: transparent;\n }\n .cfi-ui-badge[data-variant=outline][data-tone=neutral] {\n border-color: var(--cfi-ui-neutral-border);\n color: var(--cfi-ui-neutral-text);\n }\n .cfi-ui-badge[data-variant=outline][data-tone=success] {\n border-color: var(--cfi-ui-success-border);\n color: var(--cfi-ui-success-text);\n }\n .cfi-ui-badge[data-variant=outline][data-tone=warning] {\n border-color: var(--cfi-ui-warning-border);\n color: var(--cfi-ui-warning-text);\n }\n .cfi-ui-badge[data-variant=outline][data-tone=error] {\n border-color: var(--cfi-ui-error-border);\n color: var(--cfi-ui-error-text);\n }\n .cfi-ui-badge[data-variant=outline][data-tone=info] {\n border-color: var(--cfi-ui-info-border);\n color: var(--cfi-ui-info-text);\n }\n .cfi-ui-badge[data-variant=outline][data-tone=accent] {\n border-color: var(--cfi-ui-accent);\n color: var(--cfi-ui-accent-hover);\n }\n}\n");
1136
1283
 
1137
1284
  // src/Badge.tsx
1138
- import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
1285
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
1139
1286
  var Badge = forwardRef12(function Badge2({ tone = "neutral", variant = "soft", size = "md", dot = false, icon, className, children, ...rest }, ref) {
1140
- return /* @__PURE__ */ jsxs15(
1287
+ return /* @__PURE__ */ jsxs16(
1141
1288
  "span",
1142
1289
  {
1143
1290
  ref,
@@ -1147,7 +1294,7 @@ var Badge = forwardRef12(function Badge2({ tone = "neutral", variant = "soft", s
1147
1294
  className: cn("cfi-ui", "cfi-ui-badge", className),
1148
1295
  ...rest,
1149
1296
  children: [
1150
- icon ? /* @__PURE__ */ jsx15("span", { className: "cfi-ui-badge__icon", children: icon }) : dot && /* @__PURE__ */ jsx15("span", { className: "cfi-ui-badge__dot", "aria-hidden": "true" }),
1297
+ icon ? /* @__PURE__ */ jsx16("span", { className: "cfi-ui-badge__icon", children: icon }) : dot && /* @__PURE__ */ jsx16("span", { className: "cfi-ui-badge__dot", "aria-hidden": "true" }),
1151
1298
  children
1152
1299
  ]
1153
1300
  }
@@ -1155,7 +1302,7 @@ var Badge = forwardRef12(function Badge2({ tone = "neutral", variant = "soft", s
1155
1302
  });
1156
1303
  var CountBadge = forwardRef12(function CountBadge2({ count, max = 99, hideZero = true, className, ...rest }, ref) {
1157
1304
  if (count === 0 && hideZero) return null;
1158
- return /* @__PURE__ */ jsx15(Badge, { ref, className: cn("cfi-ui-badge--count", className), ...rest, children: count > max ? `${max}+` : count });
1305
+ return /* @__PURE__ */ jsx16(Badge, { ref, className: cn("cfi-ui-badge--count", className), ...rest, children: count > max ? `${max}+` : count });
1159
1306
  });
1160
1307
 
1161
1308
  // src/Table.tsx
@@ -1166,9 +1313,9 @@ import { ArrowDown, ArrowUp, ChevronsUpDown } from "lucide-react";
1166
1313
  styleInject("@layer components {\n :where(.cfi-ui-table-scroller) {\n width: 100%;\n overflow-x: auto;\n position: relative;\n }\n :where(.cfi-ui-table) {\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n font-family: var(--cfi-ui-font);\n font-size: var(--cfi-ui-text-sm);\n color: var(--cfi-ui-content);\n text-align: left;\n }\n :where(.cfi-ui-table__th) {\n height: 2.75rem;\n padding: 0.5rem 0.75rem;\n border-bottom: 1px solid var(--cfi-ui-border);\n background: transparent;\n font-size: var(--cfi-ui-text-sm);\n font-weight: var(--cfi-ui-weight-medium);\n color: var(--cfi-ui-content);\n white-space: nowrap;\n text-align: left;\n vertical-align: middle;\n }\n .cfi-ui-table[data-density=compact] .cfi-ui-table__th {\n background: var(--cfi-ui-surface-sunken);\n font-size: var(--cfi-ui-text-xs);\n font-weight: var(--cfi-ui-weight-semibold);\n color: var(--cfi-ui-content-muted);\n border-bottom-color: var(--cfi-ui-border-strong);\n }\n .cfi-ui-table[data-sticky] .cfi-ui-table__th {\n position: sticky;\n top: 0;\n z-index: var(--cfi-ui-z-raised, 10);\n }\n .cfi-ui-table__sort {\n display: inline-flex;\n align-items: center;\n gap: var(--cfi-ui-space-xs);\n margin: -0.125rem -0.25rem;\n padding: 0.125rem 0.25rem;\n border: 0;\n border-radius: var(--cfi-ui-radius-sm);\n background: none;\n color: inherit;\n font: inherit;\n cursor: pointer;\n }\n .cfi-ui-table__sort:hover {\n color: var(--cfi-ui-content);\n background: var(--cfi-ui-surface-active);\n }\n .cfi-ui-table__sort-icon {\n display: inline-flex;\n flex: none;\n opacity: 0.55;\n }\n .cfi-ui-table__th[aria-sort=ascending] .cfi-ui-table__sort-icon,\n .cfi-ui-table__th[aria-sort=descending] .cfi-ui-table__sort-icon {\n opacity: 1;\n color: var(--cfi-ui-accent);\n }\n .cfi-ui-table__sort-icon > svg {\n width: 0.75rem;\n height: 0.75rem;\n display: block;\n }\n :where(.cfi-ui-table__td) {\n padding: 0.5rem 0.75rem;\n border-bottom: 1px solid var(--cfi-ui-border-subtle);\n vertical-align: middle;\n }\n .cfi-ui-table[data-density=compact] .cfi-ui-table__td,\n .cfi-ui-table[data-density=compact] .cfi-ui-table__th {\n padding: 0.3125rem 0.625rem;\n }\n .cfi-ui-table__row[data-interactive] {\n cursor: pointer;\n }\n .cfi-ui-table__row[data-interactive]:hover .cfi-ui-table__td {\n background: var(--cfi-ui-surface-hover);\n }\n .cfi-ui-table__row[data-selected] .cfi-ui-table__td {\n background: var(--cfi-ui-surface-selected);\n }\n .cfi-ui-table__body .cfi-ui-table__row:last-child .cfi-ui-table__td {\n border-bottom: 0;\n }\n .cfi-ui-table__th[data-numeric],\n .cfi-ui-table__td[data-numeric] {\n text-align: right;\n font-variant-numeric: tabular-nums;\n }\n .cfi-ui-table__td[data-truncate] {\n max-width: 18rem;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .cfi-ui-table__foot .cfi-ui-table__td {\n border-top: 1px solid var(--cfi-ui-border-strong);\n border-bottom: 0;\n background: var(--cfi-ui-surface-sunken);\n font-weight: var(--cfi-ui-weight-semibold);\n }\n .cfi-ui-table__empty {\n padding: var(--cfi-ui-space-xl) var(--cfi-ui-space-md);\n border-bottom: 0;\n color: var(--cfi-ui-content-muted);\n text-align: center;\n }\n .cfi-ui-table__caption {\n padding: var(--cfi-ui-space-sm) 0;\n caption-side: bottom;\n font-size: var(--cfi-ui-text-xs);\n color: var(--cfi-ui-content-muted);\n text-align: left;\n }\n}\n");
1167
1314
 
1168
1315
  // src/Table.tsx
1169
- import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
1316
+ import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
1170
1317
  var Table = forwardRef13(function Table2({ density = "comfortable", stickyHeader = false, className, ...rest }, ref) {
1171
- return /* @__PURE__ */ jsx16(
1318
+ return /* @__PURE__ */ jsx17(
1172
1319
  "table",
1173
1320
  {
1174
1321
  ref,
@@ -1180,20 +1327,20 @@ var Table = forwardRef13(function Table2({ density = "comfortable", stickyHeader
1180
1327
  );
1181
1328
  });
1182
1329
  function TableScroller({ className, ...rest }) {
1183
- return /* @__PURE__ */ jsx16("div", { className: cn("cfi-ui", "cfi-ui-table-scroller", className), ...rest });
1330
+ return /* @__PURE__ */ jsx17("div", { className: cn("cfi-ui", "cfi-ui-table-scroller", className), ...rest });
1184
1331
  }
1185
1332
  function TableHeader({ className, ...rest }) {
1186
- return /* @__PURE__ */ jsx16("thead", { className: cn("cfi-ui-table__head", className), ...rest });
1333
+ return /* @__PURE__ */ jsx17("thead", { className: cn("cfi-ui-table__head", className), ...rest });
1187
1334
  }
1188
1335
  function TableBody({ className, ...rest }) {
1189
- return /* @__PURE__ */ jsx16("tbody", { className: cn("cfi-ui-table__body", className), ...rest });
1336
+ return /* @__PURE__ */ jsx17("tbody", { className: cn("cfi-ui-table__body", className), ...rest });
1190
1337
  }
1191
1338
  function TableFooter({ className, ...rest }) {
1192
- return /* @__PURE__ */ jsx16("tfoot", { className: cn("cfi-ui-table__foot", className), ...rest });
1339
+ return /* @__PURE__ */ jsx17("tfoot", { className: cn("cfi-ui-table__foot", className), ...rest });
1193
1340
  }
1194
1341
  var TableFoot = TableFooter;
1195
1342
  function TableRow({ selected, interactive, className, ...rest }) {
1196
- return /* @__PURE__ */ jsx16(
1343
+ return /* @__PURE__ */ jsx17(
1197
1344
  "tr",
1198
1345
  {
1199
1346
  "data-selected": selected || void 0,
@@ -1216,7 +1363,7 @@ function TableHead({
1216
1363
  ...rest
1217
1364
  }) {
1218
1365
  const ariaSort = sortable ? sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : "none" : void 0;
1219
- return /* @__PURE__ */ jsx16(
1366
+ return /* @__PURE__ */ jsx17(
1220
1367
  "th",
1221
1368
  {
1222
1369
  scope: "col",
@@ -1225,15 +1372,15 @@ function TableHead({
1225
1372
  style: { width, ...style },
1226
1373
  className: cn("cfi-ui-table__th", className),
1227
1374
  ...rest,
1228
- children: sortable ? /* @__PURE__ */ jsxs16("button", { type: "button", className: "cfi-ui-table__sort", onClick: onSort, children: [
1229
- /* @__PURE__ */ jsx16("span", { children }),
1230
- /* @__PURE__ */ jsx16("span", { className: "cfi-ui-table__sort-icon", "aria-hidden": "true", children: sortDirection === "asc" ? /* @__PURE__ */ jsx16(ArrowUp, {}) : sortDirection === "desc" ? /* @__PURE__ */ jsx16(ArrowDown, {}) : /* @__PURE__ */ jsx16(ChevronsUpDown, {}) })
1375
+ children: sortable ? /* @__PURE__ */ jsxs17("button", { type: "button", className: "cfi-ui-table__sort", onClick: onSort, children: [
1376
+ /* @__PURE__ */ jsx17("span", { children }),
1377
+ /* @__PURE__ */ jsx17("span", { className: "cfi-ui-table__sort-icon", "aria-hidden": "true", children: sortDirection === "asc" ? /* @__PURE__ */ jsx17(ArrowUp, {}) : sortDirection === "desc" ? /* @__PURE__ */ jsx17(ArrowDown, {}) : /* @__PURE__ */ jsx17(ChevronsUpDown, {}) })
1231
1378
  ] }) : children
1232
1379
  }
1233
1380
  );
1234
1381
  }
1235
1382
  function TableCell({ numeric, truncate, className, ...rest }) {
1236
- return /* @__PURE__ */ jsx16(
1383
+ return /* @__PURE__ */ jsx17(
1237
1384
  "td",
1238
1385
  {
1239
1386
  "data-numeric": numeric || void 0,
@@ -1244,10 +1391,10 @@ function TableCell({ numeric, truncate, className, ...rest }) {
1244
1391
  );
1245
1392
  }
1246
1393
  function TableEmpty({ colSpan, children }) {
1247
- return /* @__PURE__ */ jsx16("tr", { className: "cfi-ui-table__row", children: /* @__PURE__ */ jsx16("td", { colSpan, className: "cfi-ui-table__empty", children }) });
1394
+ return /* @__PURE__ */ jsx17("tr", { className: "cfi-ui-table__row", children: /* @__PURE__ */ jsx17("td", { colSpan, className: "cfi-ui-table__empty", children }) });
1248
1395
  }
1249
1396
  function TableCaption({ className, ...rest }) {
1250
- return /* @__PURE__ */ jsx16("caption", { className: cn("cfi-ui-table__caption", className), ...rest });
1397
+ return /* @__PURE__ */ jsx17("caption", { className: cn("cfi-ui-table__caption", className), ...rest });
1251
1398
  }
1252
1399
 
1253
1400
  // src/Tabs.tsx
@@ -1258,12 +1405,12 @@ import * as RadixTabs from "@radix-ui/react-tabs";
1258
1405
  styleInject("@layer components {\n .cfi-ui-tabs {\n display: flex;\n flex-direction: column;\n min-width: 0;\n }\n :where(.cfi-ui-tabs__list) {\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-xs);\n overflow-x: auto;\n scrollbar-width: none;\n }\n .cfi-ui-tabs__list::-webkit-scrollbar {\n display: none;\n }\n :where(.cfi-ui-tabs__trigger) {\n display: inline-flex;\n align-items: center;\n gap: var(--cfi-ui-space-xs);\n flex: none;\n border: 0;\n background: none;\n color: var(--cfi-ui-content-muted);\n font-family: var(--cfi-ui-font);\n font-size: var(--cfi-ui-text-sm);\n font-weight: var(--cfi-ui-weight-medium);\n cursor: pointer;\n transition:\n color var(--cfi-ui-transition-fast),\n background-color var(--cfi-ui-transition-fast),\n border-color var(--cfi-ui-transition-fast);\n }\n .cfi-ui-tabs__trigger:disabled {\n color: var(--cfi-ui-content-disabled);\n cursor: not-allowed;\n }\n .cfi-ui-tabs__icon {\n display: inline-flex;\n flex: none;\n }\n .cfi-ui-tabs__icon > svg {\n width: 0.875rem;\n height: 0.875rem;\n display: block;\n }\n .cfi-ui-tabs__list[data-variant=underline] {\n gap: var(--cfi-ui-space-md);\n border-bottom: 1px solid var(--cfi-ui-border);\n }\n .cfi-ui-tabs__list[data-variant=underline] .cfi-ui-tabs__trigger {\n padding: 0.5rem 0.125rem;\n border-bottom: 2px solid transparent;\n margin-bottom: -1px;\n }\n .cfi-ui-tabs__list[data-variant=underline] .cfi-ui-tabs__trigger:hover:not(:disabled) {\n color: var(--cfi-ui-content);\n }\n .cfi-ui-tabs__list[data-variant=underline] .cfi-ui-tabs__trigger[data-state=active] {\n color: var(--cfi-ui-content);\n border-bottom-color: var(--cfi-ui-accent);\n }\n .cfi-ui-tabs__list[data-variant=pill] {\n gap: 0;\n padding: 0.1875rem;\n background: var(--cfi-ui-surface-muted);\n border: 0;\n border-radius: 14px;\n align-self: flex-start;\n }\n .cfi-ui-tabs__list[data-variant=pill] .cfi-ui-tabs__trigger {\n padding: 0.25rem 0.75rem;\n border-radius: 14px;\n color: var(--cfi-ui-content);\n }\n .cfi-ui-tabs__list[data-variant=pill] .cfi-ui-tabs__trigger:hover:not(:disabled) {\n color: var(--cfi-ui-content);\n }\n .cfi-ui-tabs__list[data-variant=pill] .cfi-ui-tabs__trigger[data-state=active] {\n background: var(--cfi-ui-surface);\n color: var(--cfi-ui-content);\n box-shadow: var(--cfi-ui-shadow-xs);\n }\n :where(.cfi-ui-tabs__content) {\n min-width: 0;\n padding-top: var(--cfi-ui-space-md);\n }\n .cfi-ui-tabs__content:focus-visible {\n outline: none;\n }\n}\n");
1259
1406
 
1260
1407
  // src/Tabs.tsx
1261
- import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
1408
+ import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
1262
1409
  var Tabs = RadixTabs.Root;
1263
1410
  var TabsRoot = RadixTabs.Root;
1264
1411
  var TabsList = forwardRef14(
1265
1412
  function TabsList2({ variant = "pill", className, ...rest }, ref) {
1266
- return /* @__PURE__ */ jsx17(
1413
+ return /* @__PURE__ */ jsx18(
1267
1414
  RadixTabs.List,
1268
1415
  {
1269
1416
  ref,
@@ -1276,18 +1423,18 @@ var TabsList = forwardRef14(
1276
1423
  );
1277
1424
  var TabsTrigger = forwardRef14(
1278
1425
  function TabsTrigger2({ icon, count, className, children, ...rest }, ref) {
1279
- return /* @__PURE__ */ jsxs17(RadixTabs.Trigger, { ref, className: cn("cfi-ui-tabs__trigger", className), ...rest, children: [
1280
- icon && /* @__PURE__ */ jsx17("span", { className: "cfi-ui-tabs__icon", children: icon }),
1281
- /* @__PURE__ */ jsx17("span", { children }),
1282
- count !== void 0 && /* @__PURE__ */ jsx17(CountBadge, { count, size: "sm" })
1426
+ return /* @__PURE__ */ jsxs18(RadixTabs.Trigger, { ref, className: cn("cfi-ui-tabs__trigger", className), ...rest, children: [
1427
+ icon && /* @__PURE__ */ jsx18("span", { className: "cfi-ui-tabs__icon", children: icon }),
1428
+ /* @__PURE__ */ jsx18("span", { children }),
1429
+ count !== void 0 && /* @__PURE__ */ jsx18(CountBadge, { count, size: "sm" })
1283
1430
  ] });
1284
1431
  }
1285
1432
  );
1286
1433
  var TabsContent = forwardRef14(function TabsContent2({ className, ...rest }, ref) {
1287
- return /* @__PURE__ */ jsx17(RadixTabs.Content, { ref, className: cn("cfi-ui-tabs__content", className), ...rest });
1434
+ return /* @__PURE__ */ jsx18(RadixTabs.Content, { ref, className: cn("cfi-ui-tabs__content", className), ...rest });
1288
1435
  });
1289
1436
  function TabSet({ tabs, value, onValueChange, defaultValue, variant, className }) {
1290
- return /* @__PURE__ */ jsxs17(
1437
+ return /* @__PURE__ */ jsxs18(
1291
1438
  Tabs,
1292
1439
  {
1293
1440
  value,
@@ -1295,7 +1442,7 @@ function TabSet({ tabs, value, onValueChange, defaultValue, variant, className }
1295
1442
  defaultValue: defaultValue ?? tabs[0]?.value,
1296
1443
  className: cn("cfi-ui", "cfi-ui-tabs", className),
1297
1444
  children: [
1298
- /* @__PURE__ */ jsx17(TabsList, { variant, children: tabs.map((tab) => /* @__PURE__ */ jsx17(
1445
+ /* @__PURE__ */ jsx18(TabsList, { variant, children: tabs.map((tab) => /* @__PURE__ */ jsx18(
1299
1446
  TabsTrigger,
1300
1447
  {
1301
1448
  value: tab.value,
@@ -1306,7 +1453,7 @@ function TabSet({ tabs, value, onValueChange, defaultValue, variant, className }
1306
1453
  },
1307
1454
  tab.value
1308
1455
  )) }),
1309
- tabs.map((tab) => /* @__PURE__ */ jsx17(TabsContent, { value: tab.value, children: tab.content }, tab.value))
1456
+ tabs.map((tab) => /* @__PURE__ */ jsx18(TabsContent, { value: tab.value, children: tab.content }, tab.value))
1310
1457
  ]
1311
1458
  }
1312
1459
  );
@@ -1319,12 +1466,12 @@ import { forwardRef as forwardRef15 } from "react";
1319
1466
  styleInject('@layer components {\n :where(.cfi-ui-separator) {\n flex: none;\n background: var(--cfi-ui-border);\n }\n .cfi-ui-separator[data-orientation=horizontal] {\n width: 100%;\n height: 1px;\n }\n .cfi-ui-separator[data-orientation=vertical] {\n width: 1px;\n align-self: stretch;\n min-height: 1rem;\n }\n .cfi-ui-separator-labeled {\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-sm);\n width: 100%;\n color: var(--cfi-ui-content-muted);\n font-size: var(--cfi-ui-text-xs);\n }\n .cfi-ui-separator-labeled::before,\n .cfi-ui-separator-labeled::after {\n content: "";\n flex: 1 1 auto;\n height: 1px;\n background: var(--cfi-ui-border);\n }\n .cfi-ui-separator-labeled__label {\n flex: none;\n white-space: nowrap;\n }\n .cfi-ui-progress-wrap {\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-sm);\n width: 100%;\n }\n .cfi-ui-progress {\n position: relative;\n flex: 1 1 auto;\n height: 0.5rem;\n overflow: hidden;\n border-radius: var(--cfi-ui-radius-full);\n background: var(--cfi-ui-surface-active);\n }\n .cfi-ui-progress[data-size=sm] {\n height: 0.25rem;\n }\n .cfi-ui-progress__fill {\n height: 100%;\n border-radius: var(--cfi-ui-radius-full);\n background: var(--cfi-ui-accent);\n transition: width var(--cfi-ui-transition-base);\n }\n .cfi-ui-progress[data-tone=success] .cfi-ui-progress__fill {\n background: var(--cfi-ui-success);\n }\n .cfi-ui-progress[data-tone=warning] .cfi-ui-progress__fill {\n background: var(--cfi-ui-warning);\n }\n .cfi-ui-progress[data-tone=error] .cfi-ui-progress__fill {\n background: var(--cfi-ui-error);\n }\n .cfi-ui-progress[data-indeterminate] .cfi-ui-progress__fill {\n width: 35%;\n animation: cfi-ui-progress-slide 1.2s ease-in-out infinite;\n transition: none;\n }\n @keyframes cfi-ui-progress-slide {\n 0% {\n transform: translateX(-100%);\n }\n 100% {\n transform: translateX(300%);\n }\n }\n .cfi-ui-progress__value {\n flex: none;\n min-width: 3ch;\n font-size: var(--cfi-ui-text-xs);\n font-variant-numeric: tabular-nums;\n color: var(--cfi-ui-content-muted);\n text-align: right;\n }\n :where(.cfi-ui-skeleton) {\n background: var(--cfi-ui-surface-active);\n border-radius: var(--cfi-ui-radius-sm);\n animation: cfi-ui-pulse 1.6s ease-in-out infinite;\n }\n .cfi-ui-skeleton[data-shape=text] {\n height: 0.875em;\n margin-block: 0.25em;\n border-radius: var(--cfi-ui-radius-sm);\n }\n .cfi-ui-skeleton[data-shape=circle] {\n border-radius: var(--cfi-ui-radius-full);\n aspect-ratio: 1;\n }\n .cfi-ui-skeleton-stack {\n display: grid;\n gap: 0;\n }\n :where(.cfi-ui-avatar) {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n overflow: hidden;\n width: 2rem;\n height: 2rem;\n border-radius: var(--cfi-ui-radius-full);\n background: var(--cfi-ui-surface-active);\n color: var(--cfi-ui-content-muted);\n font-family: var(--cfi-ui-font);\n font-size: var(--cfi-ui-text-xs);\n font-weight: var(--cfi-ui-weight-semibold);\n letter-spacing: 0.02em;\n user-select: none;\n }\n .cfi-ui-avatar[data-size=xs] {\n width: 1.25rem;\n height: 1.25rem;\n font-size: 0.5625rem;\n }\n .cfi-ui-avatar[data-size=sm] {\n width: 1.5rem;\n height: 1.5rem;\n font-size: 0.625rem;\n }\n .cfi-ui-avatar[data-size=lg] {\n width: 2.5rem;\n height: 2.5rem;\n font-size: var(--cfi-ui-text-sm);\n }\n .cfi-ui-avatar__image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n .cfi-ui-avatar-group {\n display: inline-flex;\n align-items: center;\n }\n .cfi-ui-avatar-group > .cfi-ui-avatar {\n box-shadow: 0 0 0 2px var(--cfi-ui-surface);\n }\n .cfi-ui-avatar-group > .cfi-ui-avatar + .cfi-ui-avatar {\n margin-left: -0.5rem;\n }\n .cfi-ui-avatar--overflow {\n background: var(--cfi-ui-surface-sunken);\n color: var(--cfi-ui-content-muted);\n font-variant-numeric: tabular-nums;\n }\n :where(.cfi-ui-scroll-area) {\n min-width: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--cfi-ui-border-strong) transparent;\n overscroll-behavior: contain;\n }\n .cfi-ui-scroll-area[data-orientation=vertical] {\n overflow-y: auto;\n overflow-x: hidden;\n }\n .cfi-ui-scroll-area[data-orientation=horizontal] {\n overflow-x: auto;\n overflow-y: hidden;\n }\n .cfi-ui-scroll-area[data-orientation=both] {\n overflow: auto;\n }\n .cfi-ui-scroll-area::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n }\n .cfi-ui-scroll-area::-webkit-scrollbar-track {\n background: transparent;\n }\n .cfi-ui-scroll-area::-webkit-scrollbar-thumb {\n background: var(--cfi-ui-border-strong);\n border-radius: var(--cfi-ui-radius-full);\n border: 3px solid transparent;\n background-clip: content-box;\n }\n .cfi-ui-scroll-area::-webkit-scrollbar-thumb:hover {\n background: var(--cfi-ui-content-subtle);\n background-clip: content-box;\n }\n}\n');
1320
1467
 
1321
1468
  // src/Display.tsx
1322
- import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
1469
+ import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
1323
1470
  function Separator3({ orientation = "horizontal", label, className, ...rest }) {
1324
1471
  if (label) {
1325
- return /* @__PURE__ */ jsx18("div", { className: cn("cfi-ui", "cfi-ui-separator-labeled", className), ...rest, children: /* @__PURE__ */ jsx18("span", { className: "cfi-ui-separator-labeled__label", children: label }) });
1472
+ return /* @__PURE__ */ jsx19("div", { className: cn("cfi-ui", "cfi-ui-separator-labeled", className), ...rest, children: /* @__PURE__ */ jsx19("span", { className: "cfi-ui-separator-labeled__label", children: label }) });
1326
1473
  }
1327
- return /* @__PURE__ */ jsx18(
1474
+ return /* @__PURE__ */ jsx19(
1328
1475
  "div",
1329
1476
  {
1330
1477
  role: "separator",
@@ -1345,8 +1492,8 @@ function Progress({
1345
1492
  ...rest
1346
1493
  }) {
1347
1494
  const clamped = value == null ? null : Math.max(0, Math.min(100, value));
1348
- return /* @__PURE__ */ jsxs18("div", { className: cn("cfi-ui", "cfi-ui-progress-wrap", className), ...rest, children: [
1349
- /* @__PURE__ */ jsx18(
1495
+ return /* @__PURE__ */ jsxs19("div", { className: cn("cfi-ui", "cfi-ui-progress-wrap", className), ...rest, children: [
1496
+ /* @__PURE__ */ jsx19(
1350
1497
  "div",
1351
1498
  {
1352
1499
  role: "progressbar",
@@ -1358,7 +1505,7 @@ function Progress({
1358
1505
  "data-size": size,
1359
1506
  "data-indeterminate": clamped == null || void 0,
1360
1507
  className: "cfi-ui-progress",
1361
- children: /* @__PURE__ */ jsx18(
1508
+ children: /* @__PURE__ */ jsx19(
1362
1509
  "div",
1363
1510
  {
1364
1511
  className: "cfi-ui-progress__fill",
@@ -1367,7 +1514,7 @@ function Progress({
1367
1514
  )
1368
1515
  }
1369
1516
  ),
1370
- showValue && clamped != null && /* @__PURE__ */ jsxs18("span", { className: "cfi-ui-progress__value", children: [
1517
+ showValue && clamped != null && /* @__PURE__ */ jsxs19("span", { className: "cfi-ui-progress__value", children: [
1371
1518
  Math.round(clamped),
1372
1519
  "%"
1373
1520
  ] })
@@ -1375,7 +1522,7 @@ function Progress({
1375
1522
  }
1376
1523
  function Skeleton({ shape = "block", width, height, lines = 1, className, style, ...rest }) {
1377
1524
  if (shape === "text" && lines > 1) {
1378
- return /* @__PURE__ */ jsx18("div", { className: cn("cfi-ui", "cfi-ui-skeleton-stack", className), "aria-hidden": "true", ...rest, children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx18(
1525
+ return /* @__PURE__ */ jsx19("div", { className: cn("cfi-ui", "cfi-ui-skeleton-stack", className), "aria-hidden": "true", ...rest, children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx19(
1379
1526
  "div",
1380
1527
  {
1381
1528
  "data-shape": "text",
@@ -1385,7 +1532,7 @@ function Skeleton({ shape = "block", width, height, lines = 1, className, style,
1385
1532
  i
1386
1533
  )) });
1387
1534
  }
1388
- return /* @__PURE__ */ jsx18(
1535
+ return /* @__PURE__ */ jsx19(
1389
1536
  "div",
1390
1537
  {
1391
1538
  "aria-hidden": "true",
@@ -1399,18 +1546,18 @@ function Skeleton({ shape = "block", width, height, lines = 1, className, style,
1399
1546
  var Avatar = forwardRef15(function Avatar2({ name, src, size = "md", className, ...rest }, ref) {
1400
1547
  const parts = name.trim().split(/\s+/).filter(Boolean);
1401
1548
  const initials = parts.length === 0 ? "?" : parts.length === 1 ? parts[0].slice(0, 2).toUpperCase() : `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
1402
- return /* @__PURE__ */ jsxs18("span", { ref, "data-size": size, className: cn("cfi-ui", "cfi-ui-avatar", className), ...rest, children: [
1403
- src ? /* @__PURE__ */ jsx18("img", { src, alt: name, className: "cfi-ui-avatar__image" }) : /* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: initials }),
1404
- !src && /* @__PURE__ */ jsx18("span", { className: "cfi-ui-sr-only", children: name })
1549
+ return /* @__PURE__ */ jsxs19("span", { ref, "data-size": size, className: cn("cfi-ui", "cfi-ui-avatar", className), ...rest, children: [
1550
+ src ? /* @__PURE__ */ jsx19("img", { src, alt: name, className: "cfi-ui-avatar__image" }) : /* @__PURE__ */ jsx19("span", { "aria-hidden": "true", children: initials }),
1551
+ !src && /* @__PURE__ */ jsx19("span", { className: "cfi-ui-sr-only", children: name })
1405
1552
  ] });
1406
1553
  });
1407
1554
  function AvatarGroup({ max, className, children, ...rest }) {
1408
1555
  const items = Array.isArray(children) ? children : [children];
1409
1556
  const shown = max ? items.slice(0, max) : items;
1410
1557
  const hidden = items.length - shown.length;
1411
- return /* @__PURE__ */ jsxs18("div", { className: cn("cfi-ui", "cfi-ui-avatar-group", className), ...rest, children: [
1558
+ return /* @__PURE__ */ jsxs19("div", { className: cn("cfi-ui", "cfi-ui-avatar-group", className), ...rest, children: [
1412
1559
  shown,
1413
- hidden > 0 && /* @__PURE__ */ jsxs18("span", { className: "cfi-ui-avatar cfi-ui-avatar--overflow", children: [
1560
+ hidden > 0 && /* @__PURE__ */ jsxs19("span", { className: "cfi-ui-avatar cfi-ui-avatar--overflow", children: [
1414
1561
  "+",
1415
1562
  hidden
1416
1563
  ] })
@@ -1423,7 +1570,7 @@ function ScrollArea({
1423
1570
  style,
1424
1571
  ...rest
1425
1572
  }) {
1426
- return /* @__PURE__ */ jsx18(
1573
+ return /* @__PURE__ */ jsx19(
1427
1574
  "div",
1428
1575
  {
1429
1576
  "data-orientation": orientation,
@@ -1444,20 +1591,20 @@ import { ChevronDown as ChevronDown3 } from "lucide-react";
1444
1591
  styleInject("@layer components {\n :where(.cfi-ui-accordion) {\n display: flex;\n flex-direction: column;\n min-width: 0;\n border: 1px solid var(--cfi-ui-border);\n border-radius: var(--cfi-ui-radius-lg);\n background: var(--cfi-ui-surface);\n overflow: hidden;\n }\n .cfi-ui-accordion__item + .cfi-ui-accordion__item {\n border-top: 1px solid var(--cfi-ui-border);\n }\n .cfi-ui-accordion__header {\n margin: 0;\n }\n .cfi-ui-accordion__trigger {\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-sm);\n width: 100%;\n padding: 0.625rem var(--cfi-ui-space-md);\n border: 0;\n background: none;\n color: var(--cfi-ui-content);\n font-family: var(--cfi-ui-font);\n font-size: var(--cfi-ui-text-sm);\n font-weight: var(--cfi-ui-weight-medium);\n text-align: left;\n cursor: pointer;\n transition: background-color var(--cfi-ui-transition-fast);\n }\n .cfi-ui-accordion__trigger:hover:not(:disabled) {\n background: var(--cfi-ui-surface-hover);\n }\n .cfi-ui-accordion__trigger:disabled {\n color: var(--cfi-ui-content-disabled);\n cursor: not-allowed;\n }\n .cfi-ui-accordion__chevron {\n display: inline-flex;\n flex: none;\n color: var(--cfi-ui-content-muted);\n transition: transform var(--cfi-ui-transition-fast);\n }\n .cfi-ui-accordion__trigger[data-state=open] .cfi-ui-accordion__chevron {\n transform: rotate(180deg);\n }\n .cfi-ui-accordion__chevron > svg {\n width: 0.875rem;\n height: 0.875rem;\n display: block;\n }\n .cfi-ui-accordion__label {\n flex: 1 1 auto;\n min-width: 0;\n }\n .cfi-ui-accordion__meta {\n flex: none;\n font-size: var(--cfi-ui-text-xs);\n font-weight: var(--cfi-ui-weight-normal);\n font-variant-numeric: tabular-nums;\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-accordion__content {\n overflow: hidden;\n }\n .cfi-ui-accordion__content[data-state=open] {\n animation: cfi-ui-accordion-open var(--cfi-ui-transition-base);\n }\n .cfi-ui-accordion__content[data-state=closed] {\n animation: cfi-ui-accordion-close var(--cfi-ui-transition-base);\n }\n @keyframes cfi-ui-accordion-open {\n from {\n height: 0;\n }\n to {\n height: var(--radix-accordion-content-height);\n }\n }\n @keyframes cfi-ui-accordion-close {\n from {\n height: var(--radix-accordion-content-height);\n }\n to {\n height: 0;\n }\n }\n .cfi-ui-accordion__inner {\n padding: 0 var(--cfi-ui-space-md) var(--cfi-ui-space-md);\n }\n :where(.cfi-ui-toggle-group) {\n display: inline-flex;\n align-items: center;\n gap: var(--cfi-ui-space-3xs);\n padding: var(--cfi-ui-space-3xs);\n background: var(--cfi-ui-surface-sunken);\n border: 1px solid var(--cfi-ui-border);\n border-radius: var(--cfi-ui-radius-md);\n }\n :where(.cfi-ui-toggle-group__item) {\n display: inline-flex;\n align-items: center;\n gap: var(--cfi-ui-space-xs);\n height: 1.625rem;\n padding-inline: 0.5rem;\n border: 0;\n border-radius: var(--cfi-ui-radius-sm);\n background: transparent;\n color: var(--cfi-ui-content-muted);\n font-family: var(--cfi-ui-font);\n font-size: var(--cfi-ui-text-xs);\n font-weight: var(--cfi-ui-weight-medium);\n white-space: nowrap;\n cursor: pointer;\n transition: background-color var(--cfi-ui-transition-fast), color var(--cfi-ui-transition-fast);\n }\n .cfi-ui-toggle-group[data-size=md] .cfi-ui-toggle-group__item {\n height: 1.875rem;\n padding-inline: 0.625rem;\n font-size: var(--cfi-ui-text-sm);\n }\n .cfi-ui-toggle-group__item:hover:not(:disabled) {\n color: var(--cfi-ui-content);\n }\n .cfi-ui-toggle-group__item[data-state=on] {\n background: var(--cfi-ui-surface);\n color: var(--cfi-ui-content);\n box-shadow: var(--cfi-ui-shadow-xs);\n }\n .cfi-ui-toggle-group__item:disabled {\n color: var(--cfi-ui-content-disabled);\n cursor: not-allowed;\n }\n .cfi-ui-toggle-group__icon {\n display: inline-flex;\n flex: none;\n }\n .cfi-ui-toggle-group__icon > svg {\n width: 0.875rem;\n height: 0.875rem;\n display: block;\n }\n}\n");
1445
1592
 
1446
1593
  // src/Accordion.tsx
1447
- import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
1594
+ import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
1448
1595
  var AccordionRoot = RadixAccordion.Root;
1449
1596
  var AccordionItem = forwardRef16(function AccordionItem2({ className, ...rest }, ref) {
1450
- return /* @__PURE__ */ jsx19(RadixAccordion.Item, { ref, className: cn("cfi-ui-accordion__item", className), ...rest });
1597
+ return /* @__PURE__ */ jsx20(RadixAccordion.Item, { ref, className: cn("cfi-ui-accordion__item", className), ...rest });
1451
1598
  });
1452
1599
  var AccordionTrigger = forwardRef16(function AccordionTrigger2({ meta, className, children, ...rest }, ref) {
1453
- return /* @__PURE__ */ jsx19(RadixAccordion.Header, { className: "cfi-ui-accordion__header", children: /* @__PURE__ */ jsxs19(RadixAccordion.Trigger, { ref, className: cn("cfi-ui-accordion__trigger", className), ...rest, children: [
1454
- /* @__PURE__ */ jsx19("span", { className: "cfi-ui-accordion__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx19(ChevronDown3, {}) }),
1455
- /* @__PURE__ */ jsx19("span", { className: "cfi-ui-accordion__label", children }),
1456
- meta && /* @__PURE__ */ jsx19("span", { className: "cfi-ui-accordion__meta", children: meta })
1600
+ return /* @__PURE__ */ jsx20(RadixAccordion.Header, { className: "cfi-ui-accordion__header", children: /* @__PURE__ */ jsxs20(RadixAccordion.Trigger, { ref, className: cn("cfi-ui-accordion__trigger", className), ...rest, children: [
1601
+ /* @__PURE__ */ jsx20("span", { className: "cfi-ui-accordion__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx20(ChevronDown3, {}) }),
1602
+ /* @__PURE__ */ jsx20("span", { className: "cfi-ui-accordion__label", children }),
1603
+ meta && /* @__PURE__ */ jsx20("span", { className: "cfi-ui-accordion__meta", children: meta })
1457
1604
  ] }) });
1458
1605
  });
1459
1606
  var AccordionContent = forwardRef16(function AccordionContent2({ className, children, ...rest }, ref) {
1460
- return /* @__PURE__ */ jsx19(RadixAccordion.Content, { ref, className: cn("cfi-ui-accordion__content", className), ...rest, children: /* @__PURE__ */ jsx19("div", { className: "cfi-ui-accordion__inner", children }) });
1607
+ return /* @__PURE__ */ jsx20(RadixAccordion.Content, { ref, className: cn("cfi-ui-accordion__content", className), ...rest, children: /* @__PURE__ */ jsx20("div", { className: "cfi-ui-accordion__inner", children }) });
1461
1608
  });
1462
1609
  function Accordion({
1463
1610
  sections,
@@ -1474,9 +1621,9 @@ function Accordion({
1474
1621
  onValueChange,
1475
1622
  className: cn("cfi-ui", "cfi-ui-accordion", className)
1476
1623
  };
1477
- return /* @__PURE__ */ jsx19(AccordionRoot, { ...rootProps, children: sections.map((section) => /* @__PURE__ */ jsxs19(AccordionItem, { value: section.value, disabled: section.disabled, children: [
1478
- /* @__PURE__ */ jsx19(AccordionTrigger, { meta: section.meta, children: section.label }),
1479
- /* @__PURE__ */ jsx19(AccordionContent, { children: section.content })
1624
+ return /* @__PURE__ */ jsx20(AccordionRoot, { ...rootProps, children: sections.map((section) => /* @__PURE__ */ jsxs20(AccordionItem, { value: section.value, disabled: section.disabled, children: [
1625
+ /* @__PURE__ */ jsx20(AccordionTrigger, { meta: section.meta, children: section.label }),
1626
+ /* @__PURE__ */ jsx20(AccordionContent, { children: section.content })
1480
1627
  ] }, section.value)) });
1481
1628
  }
1482
1629
  function ToggleGroup({
@@ -1488,7 +1635,7 @@ function ToggleGroup({
1488
1635
  className,
1489
1636
  ...aria
1490
1637
  }) {
1491
- return /* @__PURE__ */ jsx19(
1638
+ return /* @__PURE__ */ jsx20(
1492
1639
  RadixToggleGroup.Root,
1493
1640
  {
1494
1641
  type: "single",
@@ -1500,7 +1647,7 @@ function ToggleGroup({
1500
1647
  "data-size": size,
1501
1648
  className: cn("cfi-ui", "cfi-ui-toggle-group", className),
1502
1649
  ...aria,
1503
- children: options.map((option) => /* @__PURE__ */ jsxs19(
1650
+ children: options.map((option) => /* @__PURE__ */ jsxs20(
1504
1651
  RadixToggleGroup.Item,
1505
1652
  {
1506
1653
  value: option.value,
@@ -1509,7 +1656,7 @@ function ToggleGroup({
1509
1656
  title: option.ariaLabel,
1510
1657
  className: "cfi-ui-toggle-group__item",
1511
1658
  children: [
1512
- option.icon && /* @__PURE__ */ jsx19("span", { className: "cfi-ui-toggle-group__icon", children: option.icon }),
1659
+ option.icon && /* @__PURE__ */ jsx20("span", { className: "cfi-ui-toggle-group__icon", children: option.icon }),
1513
1660
  option.label
1514
1661
  ]
1515
1662
  },
@@ -1526,9 +1673,9 @@ import { AlertCircle, Loader2 } from "lucide-react";
1526
1673
  styleInject("@layer components {\n :where(.cfi-ui-pagestate) {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--cfi-ui-space-sm);\n padding-block: var(--cfi-ui-space-2xl, 4rem);\n text-align: center;\n color: var(--cfi-ui-content);\n font-family: var(--cfi-ui-font);\n font-size: var(--cfi-ui-text-sm);\n }\n .cfi-ui-pagestate[data-size=inline] {\n padding-block: var(--cfi-ui-space-md);\n gap: var(--cfi-ui-space-xs);\n }\n .cfi-ui-pagestate:has(> .cfi-ui-pagestate__spinner) {\n flex-direction: row;\n }\n .cfi-ui-pagestate__spinner {\n width: 1rem;\n height: 1rem;\n flex: none;\n color: var(--cfi-ui-content-muted);\n animation: cfi-ui-pagestate-spin 1s linear infinite;\n }\n @media (prefers-reduced-motion: reduce) {\n .cfi-ui-pagestate__spinner {\n animation-duration: 2.4s;\n }\n }\n .cfi-ui-pagestate__icon {\n display: inline-flex;\n color: var(--cfi-ui-content-subtle);\n }\n .cfi-ui-pagestate__icon > svg {\n width: 1.5rem;\n height: 1.5rem;\n }\n .cfi-ui-pagestate__icon[data-tone=error] {\n width: 1.5rem;\n height: 1.5rem;\n color: var(--cfi-ui-error-strong);\n }\n .cfi-ui-pagestate__title {\n margin: 0;\n font-weight: var(--cfi-ui-weight-medium);\n color: var(--cfi-ui-content);\n }\n .cfi-ui-pagestate__muted {\n margin: 0;\n max-width: 34rem;\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-pagestate__title + .cfi-ui-pagestate__muted {\n margin-top: var(--cfi-ui-space-3xs);\n }\n .cfi-ui-pagestate__action {\n margin-top: var(--cfi-ui-space-xs);\n }\n .cfi-ui-pagestate__retry {\n height: var(--cfi-ui-control-height-sm);\n padding-inline: var(--cfi-ui-space-sm);\n background: var(--cfi-ui-surface);\n color: var(--cfi-ui-content);\n border: 1px solid var(--cfi-ui-border-strong);\n border-radius: var(--cfi-ui-radius-md);\n font-family: inherit;\n font-size: var(--cfi-ui-text-sm);\n line-height: normal;\n cursor: pointer;\n }\n .cfi-ui-pagestate__retry:hover {\n background: var(--cfi-ui-surface-hover);\n }\n .cfi-ui-pagestate__retry:focus-visible {\n outline: var(--cfi-ui-focus-width) solid var(--cfi-ui-focus-color);\n outline-offset: var(--cfi-ui-focus-offset);\n }\n}\n@keyframes cfi-ui-pagestate-spin {\n to {\n transform: rotate(360deg);\n }\n}\n");
1527
1674
 
1528
1675
  // src/PageState.tsx
1529
- import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
1676
+ import { jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
1530
1677
  function LoadingState({ label = "Loading\u2026", size = "block", className }) {
1531
- return /* @__PURE__ */ jsxs20(
1678
+ return /* @__PURE__ */ jsxs21(
1532
1679
  "div",
1533
1680
  {
1534
1681
  className: cn("cfi-ui", "cfi-ui-pagestate", className),
@@ -1536,8 +1683,8 @@ function LoadingState({ label = "Loading\u2026", size = "block", className }) {
1536
1683
  role: "status",
1537
1684
  "aria-live": "polite",
1538
1685
  children: [
1539
- /* @__PURE__ */ jsx20(Loader2, { className: "cfi-ui-pagestate__spinner", "aria-hidden": "true" }),
1540
- /* @__PURE__ */ jsx20("span", { className: "cfi-ui-pagestate__muted", children: label })
1686
+ /* @__PURE__ */ jsx21(Loader2, { className: "cfi-ui-pagestate__spinner", "aria-hidden": "true" }),
1687
+ /* @__PURE__ */ jsx21("span", { className: "cfi-ui-pagestate__muted", children: label })
1541
1688
  ]
1542
1689
  }
1543
1690
  );
@@ -1551,13 +1698,13 @@ function ErrorState({
1551
1698
  className
1552
1699
  }) {
1553
1700
  const message = error instanceof Error ? error.message : error == null ? "" : String(error);
1554
- return /* @__PURE__ */ jsxs20("div", { className: cn("cfi-ui", "cfi-ui-pagestate", className), "data-size": size, role: "alert", children: [
1555
- /* @__PURE__ */ jsx20(AlertCircle, { className: "cfi-ui-pagestate__icon", "data-tone": "error", "aria-hidden": "true" }),
1556
- /* @__PURE__ */ jsxs20("div", { children: [
1557
- /* @__PURE__ */ jsx20("p", { className: "cfi-ui-pagestate__title", children: title }),
1558
- message && /* @__PURE__ */ jsx20("p", { className: "cfi-ui-pagestate__muted", children: message })
1701
+ return /* @__PURE__ */ jsxs21("div", { className: cn("cfi-ui", "cfi-ui-pagestate", className), "data-size": size, role: "alert", children: [
1702
+ /* @__PURE__ */ jsx21(AlertCircle, { className: "cfi-ui-pagestate__icon", "data-tone": "error", "aria-hidden": "true" }),
1703
+ /* @__PURE__ */ jsxs21("div", { children: [
1704
+ /* @__PURE__ */ jsx21("p", { className: "cfi-ui-pagestate__title", children: title }),
1705
+ message && /* @__PURE__ */ jsx21("p", { className: "cfi-ui-pagestate__muted", children: message })
1559
1706
  ] }),
1560
- onRetry && /* @__PURE__ */ jsx20("button", { type: "button", className: "cfi-ui-pagestate__retry", onClick: onRetry, children: retryLabel })
1707
+ onRetry && /* @__PURE__ */ jsx21("button", { type: "button", className: "cfi-ui-pagestate__retry", onClick: onRetry, children: retryLabel })
1561
1708
  ] });
1562
1709
  }
1563
1710
  function EmptyState({
@@ -1568,17 +1715,17 @@ function EmptyState({
1568
1715
  size = "block",
1569
1716
  className
1570
1717
  }) {
1571
- return /* @__PURE__ */ jsxs20("div", { className: cn("cfi-ui", "cfi-ui-pagestate", className), "data-size": size, children: [
1572
- icon && /* @__PURE__ */ jsx20("span", { className: "cfi-ui-pagestate__icon", children: icon }),
1573
- /* @__PURE__ */ jsxs20("div", { children: [
1574
- /* @__PURE__ */ jsx20("p", { className: "cfi-ui-pagestate__title", children: title }),
1575
- description && /* @__PURE__ */ jsx20("p", { className: "cfi-ui-pagestate__muted", children: description })
1718
+ return /* @__PURE__ */ jsxs21("div", { className: cn("cfi-ui", "cfi-ui-pagestate", className), "data-size": size, children: [
1719
+ icon && /* @__PURE__ */ jsx21("span", { className: "cfi-ui-pagestate__icon", children: icon }),
1720
+ /* @__PURE__ */ jsxs21("div", { children: [
1721
+ /* @__PURE__ */ jsx21("p", { className: "cfi-ui-pagestate__title", children: title }),
1722
+ description && /* @__PURE__ */ jsx21("p", { className: "cfi-ui-pagestate__muted", children: description })
1576
1723
  ] }),
1577
- action && /* @__PURE__ */ jsx20("div", { className: "cfi-ui-pagestate__action", children: action })
1724
+ action && /* @__PURE__ */ jsx21("div", { className: "cfi-ui-pagestate__action", children: action })
1578
1725
  ] });
1579
1726
  }
1580
1727
  function ComingSoon({ title, detail, className }) {
1581
- return /* @__PURE__ */ jsx20(
1728
+ return /* @__PURE__ */ jsx21(
1582
1729
  EmptyState,
1583
1730
  {
1584
1731
  title,
@@ -1589,9 +1736,9 @@ function ComingSoon({ title, detail, className }) {
1589
1736
  }
1590
1737
 
1591
1738
  // src/useSortState.ts
1592
- import { useCallback as useCallback2, useMemo as useMemo3, useState as useState3 } from "react";
1739
+ import { useCallback as useCallback2, useMemo as useMemo4, useState as useState4 } from "react";
1593
1740
  function useSortState(initialKey, initialDirection = "asc") {
1594
- const [sort, setSort] = useState3({ key: initialKey, direction: initialDirection });
1741
+ const [sort, setSort] = useState4({ key: initialKey, direction: initialDirection });
1595
1742
  const toggle = useCallback2((key) => {
1596
1743
  setSort(
1597
1744
  (current) => current.key === key ? { key, direction: current.direction === "asc" ? "desc" : "asc" } : { key, direction: "asc" }
@@ -1621,23 +1768,23 @@ function useSortState(initialKey, initialDirection = "asc") {
1621
1768
  },
1622
1769
  [sort]
1623
1770
  );
1624
- return useMemo3(
1771
+ return useMemo4(
1625
1772
  () => ({ sort, toggle, setSort, sortProps, sortBy }),
1626
1773
  [sort, toggle, sortProps, sortBy]
1627
1774
  );
1628
1775
  }
1629
1776
 
1630
1777
  // src/SearchInput.tsx
1631
- import { forwardRef as forwardRef17, useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
1778
+ import { forwardRef as forwardRef17, useEffect as useEffect3, useRef as useRef3, useState as useState5 } from "react";
1632
1779
  import { Search as Search2, X as X4 } from "lucide-react";
1633
1780
 
1634
1781
  // src/SearchInput.css
1635
1782
  styleInject("@layer components {\n .cfi-ui-search__clear {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n background: none;\n border: none;\n color: var(--cfi-ui-content-muted);\n cursor: pointer;\n border-radius: var(--cfi-ui-radius-sm);\n }\n .cfi-ui-search__clear > svg {\n width: 0.875rem;\n height: 0.875rem;\n }\n .cfi-ui-search__clear:hover {\n color: var(--cfi-ui-content);\n }\n .cfi-ui-search__clear:focus-visible {\n outline: var(--cfi-ui-focus-width) solid var(--cfi-ui-focus-color);\n outline-offset: 1px;\n }\n}\n");
1636
1783
 
1637
1784
  // src/SearchInput.tsx
1638
- import { jsx as jsx21 } from "react/jsx-runtime";
1785
+ import { jsx as jsx22 } from "react/jsx-runtime";
1639
1786
  var SearchInput = forwardRef17(function SearchInput2({ value, onChange, delay = 250, placeholder = "Search\u2026", clearLabel = "Clear search", ...rest }, ref) {
1640
- const [local, setLocal] = useState4(value);
1787
+ const [local, setLocal] = useState5(value);
1641
1788
  const timer = useRef3(void 0);
1642
1789
  const latest = useRef3(onChange);
1643
1790
  latest.current = onChange;
@@ -1654,7 +1801,7 @@ var SearchInput = forwardRef17(function SearchInput2({ value, onChange, delay =
1654
1801
  setLocal("");
1655
1802
  latest.current("");
1656
1803
  };
1657
- return /* @__PURE__ */ jsx21(
1804
+ return /* @__PURE__ */ jsx22(
1658
1805
  Input,
1659
1806
  {
1660
1807
  ...rest,
@@ -1663,8 +1810,8 @@ var SearchInput = forwardRef17(function SearchInput2({ value, onChange, delay =
1663
1810
  value: local,
1664
1811
  placeholder,
1665
1812
  onChange: (e) => push(e.target.value),
1666
- prefix: /* @__PURE__ */ jsx21(Search2, { "aria-hidden": "true" }),
1667
- suffix: local ? /* @__PURE__ */ jsx21("button", { type: "button", className: "cfi-ui-search__clear", onClick: clear, "aria-label": clearLabel, children: /* @__PURE__ */ jsx21(X4, { "aria-hidden": "true" }) }) : void 0
1813
+ prefix: /* @__PURE__ */ jsx22(Search2, { "aria-hidden": "true" }),
1814
+ suffix: local ? /* @__PURE__ */ jsx22("button", { type: "button", className: "cfi-ui-search__clear", onClick: clear, "aria-label": clearLabel, children: /* @__PURE__ */ jsx22(X4, { "aria-hidden": "true" }) }) : void 0
1668
1815
  }
1669
1816
  );
1670
1817
  });
@@ -1676,7 +1823,7 @@ import { ChevronLeft, ChevronRight } from "lucide-react";
1676
1823
  styleInject("@layer components {\n :where(.cfi-ui-pagination) {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--cfi-ui-space-md);\n padding-block: var(--cfi-ui-space-sm);\n font-family: var(--cfi-ui-font);\n font-size: var(--cfi-ui-text-sm);\n color: var(--cfi-ui-content-muted);\n }\n .cfi-ui-pagination__controls {\n display: flex;\n align-items: center;\n gap: var(--cfi-ui-space-xs);\n margin-left: auto;\n }\n .cfi-ui-pagination__page {\n font-variant-numeric: tabular-nums;\n color: var(--cfi-ui-content);\n }\n .cfi-ui-pagination__range {\n font-variant-numeric: tabular-nums;\n }\n .cfi-ui-pagination__btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--cfi-ui-control-height-sm);\n height: var(--cfi-ui-control-height-sm);\n padding: 0;\n background: var(--cfi-ui-surface);\n color: var(--cfi-ui-content);\n border: 1px solid var(--cfi-ui-border-strong);\n border-radius: var(--cfi-ui-radius-md);\n cursor: pointer;\n }\n .cfi-ui-pagination__btn > svg {\n width: 1rem;\n height: 1rem;\n }\n .cfi-ui-pagination__btn:hover:not(:disabled) {\n background: var(--cfi-ui-surface-hover);\n }\n .cfi-ui-pagination__btn:disabled {\n color: var(--cfi-ui-content-disabled);\n cursor: default;\n }\n .cfi-ui-pagination__btn:focus-visible {\n outline: var(--cfi-ui-focus-width) solid var(--cfi-ui-focus-color);\n outline-offset: var(--cfi-ui-focus-offset);\n }\n}\n");
1677
1824
 
1678
1825
  // src/Pagination.tsx
1679
- import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
1826
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
1680
1827
  function Pagination({
1681
1828
  page,
1682
1829
  pageSize,
@@ -1692,12 +1839,12 @@ function Pagination({
1692
1839
  const from = (current - 1) * pageSize + 1;
1693
1840
  const to = Math.min(current * pageSize, totalItems);
1694
1841
  const range = labels?.range?.(from, to, totalItems) ?? `${from}\u2013${to} of ${totalItems.toLocaleString()}`;
1695
- return /* @__PURE__ */ jsxs21("nav", { className: cn("cfi-ui", "cfi-ui-pagination", className), "aria-label": "Pagination", children: [
1842
+ return /* @__PURE__ */ jsxs22("nav", { className: cn("cfi-ui", "cfi-ui-pagination", className), "aria-label": "Pagination", children: [
1696
1843
  showRange && // aria-live so a screen-reader user hears where they landed; paging
1697
1844
  // otherwise moves focus nowhere and announces nothing.
1698
- /* @__PURE__ */ jsx22("span", { className: "cfi-ui-pagination__range", "aria-live": "polite", children: range }),
1699
- /* @__PURE__ */ jsxs21("div", { className: "cfi-ui-pagination__controls", children: [
1700
- /* @__PURE__ */ jsx22(
1845
+ /* @__PURE__ */ jsx23("span", { className: "cfi-ui-pagination__range", "aria-live": "polite", children: range }),
1846
+ /* @__PURE__ */ jsxs22("div", { className: "cfi-ui-pagination__controls", children: [
1847
+ /* @__PURE__ */ jsx23(
1701
1848
  "button",
1702
1849
  {
1703
1850
  type: "button",
@@ -1705,15 +1852,15 @@ function Pagination({
1705
1852
  onClick: () => onPageChange(current - 1),
1706
1853
  disabled: current <= 1,
1707
1854
  "aria-label": labels?.previous ?? "Previous page",
1708
- children: /* @__PURE__ */ jsx22(ChevronLeft, { "aria-hidden": "true" })
1855
+ children: /* @__PURE__ */ jsx23(ChevronLeft, { "aria-hidden": "true" })
1709
1856
  }
1710
1857
  ),
1711
- /* @__PURE__ */ jsxs21("span", { className: "cfi-ui-pagination__page", children: [
1858
+ /* @__PURE__ */ jsxs22("span", { className: "cfi-ui-pagination__page", children: [
1712
1859
  current,
1713
1860
  " / ",
1714
1861
  pageCount
1715
1862
  ] }),
1716
- /* @__PURE__ */ jsx22(
1863
+ /* @__PURE__ */ jsx23(
1717
1864
  "button",
1718
1865
  {
1719
1866
  type: "button",
@@ -1721,7 +1868,7 @@ function Pagination({
1721
1868
  onClick: () => onPageChange(current + 1),
1722
1869
  disabled: current >= pageCount,
1723
1870
  "aria-label": labels?.next ?? "Next page",
1724
- children: /* @__PURE__ */ jsx22(ChevronRight, { "aria-hidden": "true" })
1871
+ children: /* @__PURE__ */ jsx23(ChevronRight, { "aria-hidden": "true" })
1725
1872
  }
1726
1873
  )
1727
1874
  ] })
@@ -1789,6 +1936,7 @@ export {
1789
1936
  ComingSoon,
1790
1937
  ConfirmDialog,
1791
1938
  CountBadge,
1939
+ CreatableSelect,
1792
1940
  Dialog,
1793
1941
  DialogBody,
1794
1942
  DialogClose,
package/package.json CHANGED
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "name": "@campfire-interactive/ui",
3
- "version": "0.1.0",
4
- "_notReady": "NOT READY FOR APP ADOPTIONsee docs/plans/2026-09-09-ui-package-and-showcase.md. private:true blocks npm publish until the components are vetted.",
5
- "description": "UNVETTED, DO NOT ADOPT YET — Shared UI primitives for the Campfire Suite — Radix behaviour, plain CSS styled entirely from the design tokens, no Tailwind required",
3
+ "version": "0.2.0",
4
+ "description": "Shared UI primitives for the Campfire Suite Radix behavior, plain CSS styled entirely from the design tokens, no Tailwind required",
6
5
  "type": "module",
7
6
  "main": "dist/index.js",
8
7
  "types": "dist/index.d.ts",