@proteos/ui 0.45.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/index.cjs +720 -70
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +191 -8
  4. package/dist/index.d.ts +191 -8
  5. package/dist/index.js +715 -74
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/components/attribute-type-icon/attribute-type-icon.tsx +5 -0
  9. package/src/components/avatar/avatar.stories.tsx +37 -1
  10. package/src/components/avatar/avatar.test.tsx +42 -0
  11. package/src/components/avatar/avatar.tsx +39 -4
  12. package/src/components/avatar-group/avatar-group.test.tsx +19 -0
  13. package/src/components/avatar-group/avatar-group.tsx +18 -3
  14. package/src/components/badge/badge.stories.tsx +27 -1
  15. package/src/components/badge/badge.test.tsx +26 -0
  16. package/src/components/badge/badge.tsx +48 -4
  17. package/src/components/badge-multi-select/badge-multi-select.stories.tsx +24 -0
  18. package/src/components/badge-multi-select/badge-multi-select.tsx +25 -4
  19. package/src/components/checkbox/checkbox.tsx +8 -1
  20. package/src/components/color-input/color-input.stories.tsx +72 -0
  21. package/src/components/color-input/color-input.test.tsx +95 -0
  22. package/src/components/color-input/color-input.tsx +208 -0
  23. package/src/components/color-input/index.ts +2 -0
  24. package/src/components/data-table/data-table.test.tsx +112 -0
  25. package/src/components/data-table/data-table.tsx +135 -11
  26. package/src/components/data-table/index.ts +1 -1
  27. package/src/components/draft-message-composer/draft-message-composer.stories.tsx +1 -1
  28. package/src/components/icon-picker/icon-picker.stories.tsx +77 -0
  29. package/src/components/icon-picker/icon-picker.test.tsx +88 -0
  30. package/src/components/icon-picker/icon-picker.tsx +336 -0
  31. package/src/components/icon-picker/index.ts +2 -0
  32. package/src/components/record-filter/chip-value.tsx +10 -3
  33. package/src/components/record-filter/filter-value-input.tsx +12 -2
  34. package/src/components/record-filter/operators.ts +6 -6
  35. package/src/components/record-filter/record-filter.stories.tsx +1 -1
  36. package/src/components/record-filter/types.ts +4 -0
  37. package/src/components/table/table.stories.tsx +12 -13
  38. package/src/components/toast/index.ts +9 -0
  39. package/src/components/toast/toast.stories.tsx +58 -0
  40. package/src/components/toast/toast.test.tsx +34 -0
  41. package/src/components/toast/toast.tsx +121 -0
  42. package/src/index.ts +3 -0
  43. package/src/test/setup.ts +30 -0
package/dist/index.cjs CHANGED
@@ -356,6 +356,7 @@ var AttributeType = {
356
356
  Object: "object",
357
357
  Relation: "relation",
358
358
  User: "user",
359
+ Principal: "principal",
359
360
  Currency: "currency",
360
361
  KnowledgeText: "knowledge-text",
361
362
  File: "file"
@@ -372,6 +373,7 @@ var ATTRIBUTE_TYPE_ICONS = {
372
373
  [AttributeType.Object]: lucideReact.Braces,
373
374
  [AttributeType.Relation]: lucideReact.Link2,
374
375
  [AttributeType.User]: lucideReact.User,
376
+ [AttributeType.Principal]: lucideReact.UsersRound,
375
377
  [AttributeType.Currency]: lucideReact.Banknote,
376
378
  [AttributeType.KnowledgeText]: lucideReact.BookText,
377
379
  [AttributeType.File]: lucideReact.Paperclip
@@ -398,7 +400,7 @@ function AttributeTypeIcon({
398
400
  }
399
401
  var avatarStyles = tailwindVariants.tv({
400
402
  base: [
401
- "inline-grid place-items-center shrink-0 select-none",
403
+ "inline-grid place-items-center shrink-0 select-none overflow-hidden",
402
404
  "rounded-full border",
403
405
  "font-mono font-medium tracking-[-0.005em]"
404
406
  ],
@@ -406,7 +408,8 @@ var avatarStyles = tailwindVariants.tv({
406
408
  size: {
407
409
  sm: "size-[22px] text-[10px]",
408
410
  md: "size-7 text-[12px]",
409
- lg: "size-9 text-[13px]"
411
+ lg: "size-9 text-[13px]",
412
+ xl: "size-[120px] text-[34px]"
410
413
  },
411
414
  tone: {
412
415
  paper: "bg-surface-3 text-ink border-rule",
@@ -418,8 +421,27 @@ var avatarStyles = tailwindVariants.tv({
418
421
  },
419
422
  defaultVariants: { size: "md", tone: "paper" }
420
423
  });
421
- function Avatar({ size, tone, initials, className, children, ...props }) {
422
- return /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, className: chunkMWAXK66H_cjs.cn(avatarStyles({ size, tone }), className), children: children ?? initials });
424
+ function Avatar({
425
+ size,
426
+ tone,
427
+ initials,
428
+ src,
429
+ alt = "",
430
+ className,
431
+ children,
432
+ ...props
433
+ }) {
434
+ const [failedSrc, setFailedSrc] = react.useState(null);
435
+ const showsImage = Boolean(src) && failedSrc !== src;
436
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, className: chunkMWAXK66H_cjs.cn(avatarStyles({ size, tone }), className), children: showsImage ? /* @__PURE__ */ jsxRuntime.jsx(
437
+ "img",
438
+ {
439
+ src: src ?? void 0,
440
+ alt,
441
+ className: "size-full object-cover",
442
+ onError: () => setFailedSrc(src ?? null)
443
+ }
444
+ ) : children ?? initials });
423
445
  }
424
446
  var avatarGroupStyles = tailwindVariants.tv({
425
447
  base: "flex items-center",
@@ -432,53 +454,29 @@ var avatarGroupStyles = tailwindVariants.tv({
432
454
  },
433
455
  defaultVariants: { size: "md" }
434
456
  });
435
- function AvatarGroup({ avatars, max = 3, size = "md", className, ...props }) {
457
+ function AvatarGroup({
458
+ avatars,
459
+ max = 3,
460
+ size = "md",
461
+ className,
462
+ ...props
463
+ }) {
436
464
  const shown = avatars.slice(0, max);
437
465
  const overflow = avatars.length - shown.length;
438
466
  return /* @__PURE__ */ jsxRuntime.jsxs("span", { ...props, className: chunkMWAXK66H_cjs.cn(avatarGroupStyles({ size }), className), children: [
439
- shown.map((avatar, index) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full ring-[1.5px] ring-surface", children: /* @__PURE__ */ jsxRuntime.jsx(Avatar, { size, tone: avatar.tone ?? "paper", initials: avatar.initials }) }, avatar.key ?? index)),
467
+ shown.map((avatar, index) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full ring-[1.5px] ring-surface", children: /* @__PURE__ */ jsxRuntime.jsx(
468
+ Avatar,
469
+ {
470
+ size,
471
+ tone: avatar.tone ?? "paper",
472
+ initials: avatar.initials,
473
+ src: avatar.src ?? null,
474
+ alt: avatar.alt ?? ""
475
+ }
476
+ ) }, avatar.key ?? index)),
440
477
  overflow > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-full ring-[1.5px] ring-surface", children: /* @__PURE__ */ jsxRuntime.jsx(Avatar, { size, tone: "paper", initials: `+${overflow}` }) })
441
478
  ] });
442
479
  }
443
- var badgeStyles = tailwindVariants.tv({
444
- base: [
445
- "inline-flex items-center gap-1.5",
446
- "font-mono text-[11.5px] tracking-[-0.005em]",
447
- "px-2.5 py-0.5 rounded-pill border",
448
- // Leading dot
449
- 'before:content-[""] before:block before:size-1.5 before:rounded-full'
450
- ],
451
- variants: {
452
- variant: {
453
- default: "border-rule bg-surface text-ink-3 before:bg-ink-4",
454
- neutral: "border-rule bg-surface-3 text-ink-2 before:bg-ink-3",
455
- active: [
456
- "text-accent-ink before:bg-accent",
457
- "border-[color-mix(in_oklab,var(--color-accent)_35%,var(--color-rule))]",
458
- "bg-[color-mix(in_oklab,var(--color-accent)_14%,var(--color-surface))]"
459
- ],
460
- success: [
461
- "text-success before:bg-success",
462
- "border-[color-mix(in_oklab,var(--color-success)_35%,var(--color-rule))]",
463
- "bg-[color-mix(in_oklab,var(--color-success)_12%,var(--color-surface))]"
464
- ],
465
- warning: [
466
- "text-warning before:bg-warning",
467
- "border-[color-mix(in_oklab,var(--color-warning)_35%,var(--color-rule))]",
468
- "bg-[color-mix(in_oklab,var(--color-warning)_14%,var(--color-surface))]"
469
- ],
470
- danger: [
471
- "text-danger before:bg-danger",
472
- "border-[color-mix(in_oklab,var(--color-danger)_40%,var(--color-rule))]",
473
- "bg-[color-mix(in_oklab,var(--color-danger)_12%,var(--color-surface))]"
474
- ]
475
- }
476
- },
477
- defaultVariants: { variant: "default" }
478
- });
479
- function Badge({ variant, className, ...props }) {
480
- return /* @__PURE__ */ jsxRuntime.jsx("span", { ...props, className: chunkMWAXK66H_cjs.cn(badgeStyles({ variant }), className) });
481
- }
482
480
  var fieldControlStyles = tailwindVariants.tv({
483
481
  slots: {
484
482
  box: [
@@ -571,6 +569,318 @@ function FieldCaret() {
571
569
  }
572
570
  ) });
573
571
  }
572
+ var ICON_NAMES = Object.keys(lucideReact.icons);
573
+ var BY_NORMALIZED = new Map(
574
+ ICON_NAMES.map((name) => [normalize(name), name])
575
+ );
576
+ function normalize(name) {
577
+ return name.toLowerCase().replace(/[^a-z0-9]/g, "");
578
+ }
579
+ function resolveLucideIcon(name) {
580
+ const canonical = resolveLucideIconName(name);
581
+ return canonical ? lucideReact.icons[canonical] : null;
582
+ }
583
+ function resolveLucideIconName(name) {
584
+ if (!name) return null;
585
+ return BY_NORMALIZED.get(normalize(name)) ?? null;
586
+ }
587
+ var GRID_PAGE = 120;
588
+ var COMPACT_SIZE = {
589
+ sm: "size-8",
590
+ md: "size-[42px]"
591
+ };
592
+ function IconPicker({
593
+ label,
594
+ description,
595
+ errorMessage,
596
+ placeholder = "Choose an icon\u2026",
597
+ value,
598
+ onChange,
599
+ isDisabled = false,
600
+ isInvalid = false,
601
+ allowClear = true,
602
+ size = "md",
603
+ appearance,
604
+ compact = false,
605
+ "aria-label": ariaLabel,
606
+ className
607
+ }) {
608
+ const [isOpen, setIsOpen] = react.useState(false);
609
+ const [query, setQuery] = react.useState("");
610
+ const [limit, setLimit] = react.useState(GRID_PAGE);
611
+ const triggerRef = react.useRef(null);
612
+ const styles3 = fieldControlStyles({ size, invalid: isInvalid, appearance });
613
+ const selectedName = resolveLucideIconName(value);
614
+ const SelectedIcon = selectedName ? lucideReact.icons[selectedName] : null;
615
+ const matches2 = react.useMemo(() => {
616
+ const q = normalize(query);
617
+ return q ? ICON_NAMES.filter((name) => normalize(name).includes(q)) : ICON_NAMES;
618
+ }, [query]);
619
+ const visible = matches2.slice(0, limit);
620
+ const hiddenCount = matches2.length - visible.length;
621
+ const open = (next) => {
622
+ setIsOpen(next);
623
+ if (!next) {
624
+ setQuery("");
625
+ setLimit(GRID_PAGE);
626
+ }
627
+ };
628
+ const search = (next) => {
629
+ setQuery(next);
630
+ setLimit(GRID_PAGE);
631
+ };
632
+ const onGridScroll = (element) => {
633
+ if (hiddenCount === 0) return;
634
+ const remaining = element.scrollHeight - element.scrollTop - element.clientHeight;
635
+ if (remaining < 120) setLimit((current) => current + GRID_PAGE);
636
+ };
637
+ const pick = (name) => {
638
+ onChange(name);
639
+ open(false);
640
+ triggerRef.current?.focus();
641
+ };
642
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkMWAXK66H_cjs.cn("grid grid-cols-1 gap-1.5", className), children: [
643
+ label ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Label, { className: fieldLabelStyles, children: label }) : null,
644
+ compact ? /* @__PURE__ */ jsxRuntime.jsx(
645
+ "button",
646
+ {
647
+ ref: triggerRef,
648
+ type: "button",
649
+ "aria-haspopup": "dialog",
650
+ "aria-expanded": isOpen,
651
+ "aria-label": ariaLabel ?? (typeof label === "string" ? label : "Icon"),
652
+ title: selectedName ?? placeholder,
653
+ disabled: isDisabled,
654
+ onClick: () => open(!isOpen),
655
+ "data-invalid": isInvalid || void 0,
656
+ className: chunkMWAXK66H_cjs.cn(
657
+ styles3.box(),
658
+ "flex shrink-0 items-center justify-center cursor-pointer",
659
+ appearance === "cell" ? "size-[29px]" : COMPACT_SIZE[size],
660
+ "disabled:cursor-not-allowed disabled:opacity-45"
661
+ ),
662
+ children: SelectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(SelectedIcon, { "aria-hidden": true, className: "size-4 text-ink-2" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Shapes, { "aria-hidden": true, className: "size-4 text-ink-4" })
663
+ }
664
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
665
+ "button",
666
+ {
667
+ ref: triggerRef,
668
+ type: "button",
669
+ "aria-haspopup": "dialog",
670
+ "aria-expanded": isOpen,
671
+ "aria-label": ariaLabel ?? (typeof label === "string" ? label : "Icon"),
672
+ disabled: isDisabled,
673
+ onClick: () => open(!isOpen),
674
+ "data-invalid": isInvalid || void 0,
675
+ className: chunkMWAXK66H_cjs.cn(
676
+ // box carries no padding by contract — content is what gives a
677
+ // single-element control its interior (padding, font, text-size).
678
+ styles3.box(),
679
+ styles3.content(),
680
+ "flex w-full items-center gap-2 text-left cursor-pointer",
681
+ "disabled:cursor-not-allowed disabled:opacity-45"
682
+ ),
683
+ children: [
684
+ SelectedIcon ? /* @__PURE__ */ jsxRuntime.jsx(SelectedIcon, { "aria-hidden": true, className: "size-4 shrink-0 text-ink-2" }) : null,
685
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: chunkMWAXK66H_cjs.cn("min-w-0 flex-1 truncate", selectedName ? "text-ink" : "text-ink-4"), children: selectedName ?? placeholder }),
686
+ /* @__PURE__ */ jsxRuntime.jsx(FieldCaret, {})
687
+ ]
688
+ }
689
+ ),
690
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: fieldHintStyles, children: description }) : null,
691
+ errorMessage && appearance !== "cell" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: fieldErrorStyles, children: errorMessage }) : null,
692
+ /* @__PURE__ */ jsxRuntime.jsxs(
693
+ reactAriaComponents.Popover,
694
+ {
695
+ isOpen,
696
+ onOpenChange: open,
697
+ triggerRef,
698
+ offset: 6,
699
+ placement: "bottom start",
700
+ className: chunkMWAXK66H_cjs.cn(
701
+ "w-[316px] rounded-md border border-rule bg-surface p-2",
702
+ "shadow-[var(--shadow-raised)]",
703
+ "entering:animate-in entering:fade-in-0 entering:slide-in-from-top-1",
704
+ "exiting:animate-out exiting:fade-out-0 exiting:slide-out-to-top-1"
705
+ ),
706
+ children: [
707
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 pb-2", children: [
708
+ /* @__PURE__ */ jsxRuntime.jsxs(
709
+ "div",
710
+ {
711
+ className: chunkMWAXK66H_cjs.cn(
712
+ fieldControlStyles({ size: "sm" }).box(),
713
+ "flex min-w-0 flex-1 items-center gap-1.5 px-2.5 py-1.5",
714
+ "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]"
715
+ ),
716
+ children: [
717
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { "aria-hidden": true, className: "size-3.5 shrink-0 text-ink-4" }),
718
+ /* @__PURE__ */ jsxRuntime.jsx(
719
+ reactAriaComponents.Input,
720
+ {
721
+ autoFocus: true,
722
+ "aria-label": "Search icons",
723
+ value: query,
724
+ onChange: (event) => search(event.target.value),
725
+ placeholder: "Search icons\u2026",
726
+ className: chunkMWAXK66H_cjs.cn(
727
+ "min-w-0 flex-1 bg-transparent font-sans outline-none",
728
+ "text-ink placeholder:text-ink-4",
729
+ fieldTextStyles.sm
730
+ )
731
+ }
732
+ )
733
+ ]
734
+ }
735
+ ),
736
+ allowClear && selectedName ? /* @__PURE__ */ jsxRuntime.jsxs(
737
+ "button",
738
+ {
739
+ type: "button",
740
+ onClick: () => pick(null),
741
+ className: chunkMWAXK66H_cjs.cn(
742
+ "flex shrink-0 items-center gap-1 rounded-[6px] px-2 py-1.5 cursor-pointer",
743
+ "font-sans text-[12px] text-ink-3 transition-colors",
744
+ "hover:bg-surface-2 hover:text-ink",
745
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-accent)]"
746
+ ),
747
+ children: [
748
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": true, className: "size-3" }),
749
+ "Clear"
750
+ ]
751
+ }
752
+ ) : null
753
+ ] }),
754
+ /* @__PURE__ */ jsxRuntime.jsx(
755
+ "div",
756
+ {
757
+ className: "max-h-64 overflow-y-auto",
758
+ onScroll: (event) => onGridScroll(event.currentTarget),
759
+ children: /* @__PURE__ */ jsxRuntime.jsx(
760
+ reactAriaComponents.ListBox,
761
+ {
762
+ "aria-label": "Icons",
763
+ layout: "grid",
764
+ selectionMode: "single",
765
+ selectedKeys: selectedName ? /* @__PURE__ */ new Set([selectedName]) : /* @__PURE__ */ new Set(),
766
+ onSelectionChange: (keys) => {
767
+ if (keys === "all") return;
768
+ const next = [...keys][0];
769
+ if (next !== void 0) pick(next);
770
+ },
771
+ className: "grid grid-cols-8 gap-0.5 outline-none",
772
+ renderEmptyState: () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkMWAXK66H_cjs.cn("col-span-8 px-2 py-3 text-center", fieldHintStyles), children: "No icons match" }),
773
+ children: visible.map((name) => {
774
+ const Icon = lucideReact.icons[name];
775
+ return /* @__PURE__ */ jsxRuntime.jsx(
776
+ reactAriaComponents.ListBoxItem,
777
+ {
778
+ id: name,
779
+ textValue: name,
780
+ "aria-label": name,
781
+ className: chunkMWAXK66H_cjs.cn(
782
+ "flex size-[34px] items-center justify-center rounded-[6px]",
783
+ "cursor-pointer outline-none",
784
+ "data-[hovered]:bg-surface-2 data-[focused]:bg-surface-2",
785
+ "data-[focus-visible]:ring-2 data-[focus-visible]:ring-[var(--color-accent)]",
786
+ "data-[selected]:bg-[color-mix(in_oklab,var(--color-accent)_12%,var(--color-surface))]",
787
+ "data-[selected]:text-accent text-ink-2"
788
+ ),
789
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { "aria-hidden": true, className: "size-4" })
790
+ },
791
+ name
792
+ );
793
+ })
794
+ }
795
+ )
796
+ }
797
+ ),
798
+ hiddenCount > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("p", { className: chunkMWAXK66H_cjs.cn("px-1 pt-2", fieldHintStyles), children: [
799
+ hiddenCount.toLocaleString(),
800
+ " more \u2014 keep scrolling, or search."
801
+ ] }) : null
802
+ ]
803
+ }
804
+ )
805
+ ] });
806
+ }
807
+ var badgeStyles = tailwindVariants.tv({
808
+ base: [
809
+ "inline-flex items-center gap-1.5",
810
+ "font-mono text-[11.5px] tracking-[-0.005em]",
811
+ "px-2.5 py-0.5 rounded-pill border",
812
+ // Leading dot
813
+ 'before:content-[""] before:block before:size-1.5 before:rounded-full'
814
+ ],
815
+ variants: {
816
+ variant: {
817
+ default: "border-rule bg-surface text-ink-3 before:bg-ink-4",
818
+ neutral: "border-rule bg-surface-3 text-ink-2 before:bg-ink-3",
819
+ active: [
820
+ "text-accent-ink before:bg-accent",
821
+ "border-[color-mix(in_oklab,var(--color-accent)_35%,var(--color-rule))]",
822
+ "bg-[color-mix(in_oklab,var(--color-accent)_14%,var(--color-surface))]"
823
+ ],
824
+ success: [
825
+ "text-success before:bg-success",
826
+ "border-[color-mix(in_oklab,var(--color-success)_35%,var(--color-rule))]",
827
+ "bg-[color-mix(in_oklab,var(--color-success)_12%,var(--color-surface))]"
828
+ ],
829
+ warning: [
830
+ "text-warning before:bg-warning",
831
+ "border-[color-mix(in_oklab,var(--color-warning)_35%,var(--color-rule))]",
832
+ "bg-[color-mix(in_oklab,var(--color-warning)_14%,var(--color-surface))]"
833
+ ],
834
+ danger: [
835
+ "text-danger before:bg-danger",
836
+ "border-[color-mix(in_oklab,var(--color-danger)_40%,var(--color-rule))]",
837
+ "bg-[color-mix(in_oklab,var(--color-danger)_12%,var(--color-surface))]"
838
+ ],
839
+ // Driven by the `--badge-color` custom property (set from the `color`
840
+ // prop). Chrome only — text stays ink so contrast never depends on the
841
+ // picked color.
842
+ custom: [
843
+ "text-ink-2 before:bg-[var(--badge-color)]",
844
+ "border-[color-mix(in_oklab,var(--badge-color)_35%,var(--color-rule))]",
845
+ "bg-[color-mix(in_oklab,var(--badge-color)_12%,var(--color-surface))]"
846
+ ]
847
+ }
848
+ },
849
+ defaultVariants: { variant: "default" }
850
+ });
851
+ var ICON_TONE = {
852
+ default: "text-ink-4",
853
+ neutral: "text-ink-3",
854
+ active: "text-accent",
855
+ success: "text-success",
856
+ warning: "text-warning",
857
+ danger: "text-danger",
858
+ custom: "text-[var(--badge-color)]"
859
+ };
860
+ function Badge({ variant, color, icon, className, style, children, ...props }) {
861
+ const Icon = icon ? resolveLucideIcon(icon) : null;
862
+ const register2 = color ? "custom" : variant ?? "default";
863
+ const mergedStyle = color ? { ...style, "--badge-color": color } : style;
864
+ return /* @__PURE__ */ jsxRuntime.jsxs(
865
+ "span",
866
+ {
867
+ ...props,
868
+ style: mergedStyle,
869
+ className: chunkMWAXK66H_cjs.cn(badgeStyles({ variant: register2 }), Icon ? "before:hidden" : null, className),
870
+ children: [
871
+ Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { "aria-hidden": true, className: chunkMWAXK66H_cjs.cn("size-3 shrink-0", ICON_TONE[register2]) }) : null,
872
+ children
873
+ ]
874
+ }
875
+ );
876
+ }
877
+ function badgeChrome(option) {
878
+ return {
879
+ ...option.variant ? { variant: option.variant } : {},
880
+ ...option.color ? { color: option.color } : {},
881
+ ...option.icon ? { icon: option.icon } : {}
882
+ };
883
+ }
574
884
  function BadgeMultiSelect({
575
885
  label,
576
886
  description,
@@ -643,7 +953,7 @@ function BadgeMultiSelect({
643
953
  ) : selectedOptions.map((o) => /* @__PURE__ */ jsxRuntime.jsx(
644
954
  RemovableBadge,
645
955
  {
646
- variant: o.variant,
956
+ ...badgeChrome(o),
647
957
  onRemove: () => remove(o.id),
648
958
  isDisabled,
649
959
  children: o.label
@@ -701,7 +1011,7 @@ function BadgeMultiSelect({
701
1011
  "data-[selected]:bg-surface-3",
702
1012
  "data-[disabled]:opacity-45 data-[disabled]:cursor-not-allowed"
703
1013
  ),
704
- children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant: option.variant, children: option.label })
1014
+ children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { ...badgeChrome(option), children: option.label })
705
1015
  },
706
1016
  option.id
707
1017
  ))
@@ -714,10 +1024,12 @@ function BadgeMultiSelect({
714
1024
  function RemovableBadge({
715
1025
  children,
716
1026
  variant,
1027
+ color,
1028
+ icon,
717
1029
  onRemove,
718
1030
  isDisabled
719
1031
  }) {
720
- return /* @__PURE__ */ jsxRuntime.jsxs(Badge, { variant, children: [
1032
+ return /* @__PURE__ */ jsxRuntime.jsxs(Badge, { ...badgeChrome({ variant, color, icon }), children: [
721
1033
  /* @__PURE__ */ jsxRuntime.jsx("span", { children }),
722
1034
  /* @__PURE__ */ jsxRuntime.jsx(
723
1035
  "button",
@@ -953,7 +1265,14 @@ function Checkbox({ children, className, ...props }) {
953
1265
  {
954
1266
  ...props,
955
1267
  className: (renderProps) => chunkMWAXK66H_cjs.cn(
956
- "group inline-flex items-center gap-2.5 cursor-pointer",
1268
+ // `relative` so RAC's visually-hidden <input> — which is absolutely
1269
+ // positioned and is the element that actually receives focus — is
1270
+ // laid out against THIS checkbox. Without a positioned ancestor here
1271
+ // it resolves against a far-away container, ends up outside any
1272
+ // scroll clipping, and focusing it makes the browser scroll a
1273
+ // container the user cannot scroll back (the roles permission
1274
+ // matrix, where toggling a row threw the page off-screen).
1275
+ "group relative inline-flex items-center gap-2.5 cursor-pointer",
957
1276
  "font-sans text-[14px] text-ink-2 select-none",
958
1277
  "data-[disabled]:opacity-45 data-[disabled]:cursor-not-allowed",
959
1278
  typeof className === "function" ? className(renderProps) : className
@@ -1027,6 +1346,146 @@ function CheckboxGroup({
1027
1346
  }
1028
1347
  );
1029
1348
  }
1349
+ var HEX6 = /^#?([0-9a-f]{6})$/i;
1350
+ var HEX3 = /^#?([0-9a-f]{3})$/i;
1351
+ function normalizeHexColor(text) {
1352
+ const raw = (text ?? "").trim();
1353
+ if (raw === "") return null;
1354
+ const six = HEX6.exec(raw);
1355
+ if (six?.[1]) return `#${six[1].toLowerCase()}`;
1356
+ const three = HEX3.exec(raw);
1357
+ if (three?.[1]) {
1358
+ const [r, g, b] = three[1].toLowerCase();
1359
+ return `#${r}${r}${g}${g}${b}${b}`;
1360
+ }
1361
+ return null;
1362
+ }
1363
+ function ColorInput({
1364
+ label,
1365
+ description,
1366
+ errorMessage,
1367
+ placeholder = "#5b8def",
1368
+ value,
1369
+ onChange,
1370
+ isDisabled = false,
1371
+ isInvalid = false,
1372
+ size = "md",
1373
+ appearance,
1374
+ "aria-label": ariaLabel,
1375
+ className
1376
+ }) {
1377
+ const committed = normalizeHexColor(value);
1378
+ const [draft, setDraft] = react.useState(committed ?? "");
1379
+ const nativeRef = react.useRef(null);
1380
+ react.useEffect(() => {
1381
+ setDraft((current) => normalizeHexColor(current) === committed ? current : committed ?? "");
1382
+ }, [committed]);
1383
+ const isDraftInvalid = draft.trim() !== "" && normalizeHexColor(draft) === null;
1384
+ const invalid = isInvalid || isDraftInvalid;
1385
+ const styles3 = fieldControlStyles({ size, invalid, appearance });
1386
+ const focusWithin = appearance === "cell" ? "focus-within:border-accent focus-within:shadow-none" : "focus-within:border-accent focus-within:shadow-[var(--shadow-focus)]";
1387
+ const edit = (next) => {
1388
+ setDraft(next);
1389
+ if (next.trim() === "") {
1390
+ if (committed !== null) onChange(null);
1391
+ return;
1392
+ }
1393
+ if (!HEX6.test(next.trim())) return;
1394
+ const hex = normalizeHexColor(next);
1395
+ if (hex !== null && hex !== committed) onChange(hex);
1396
+ };
1397
+ const settle = () => {
1398
+ const hex = normalizeHexColor(draft);
1399
+ if (hex === null) return;
1400
+ setDraft(hex);
1401
+ if (hex !== committed) onChange(hex);
1402
+ };
1403
+ const pick = (next) => {
1404
+ const hex = normalizeHexColor(next);
1405
+ if (hex === null) return;
1406
+ setDraft(hex);
1407
+ if (hex !== committed) onChange(hex);
1408
+ };
1409
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1410
+ reactAriaComponents.TextField,
1411
+ {
1412
+ value: draft,
1413
+ onChange: edit,
1414
+ isDisabled,
1415
+ isInvalid: invalid,
1416
+ onBlur: settle,
1417
+ ...ariaLabel ? { "aria-label": ariaLabel } : {},
1418
+ className: chunkMWAXK66H_cjs.cn("grid grid-cols-1 gap-1.5", className),
1419
+ children: [
1420
+ label ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Label, { className: fieldLabelStyles, children: label }) : null,
1421
+ /* @__PURE__ */ jsxRuntime.jsxs(
1422
+ "div",
1423
+ {
1424
+ "data-disabled": isDisabled || void 0,
1425
+ className: chunkMWAXK66H_cjs.cn(
1426
+ styles3.box(),
1427
+ "flex items-center gap-2",
1428
+ size === "sm" ? "pl-2" : "pl-2.5",
1429
+ focusWithin
1430
+ ),
1431
+ children: [
1432
+ /* @__PURE__ */ jsxRuntime.jsxs(
1433
+ "button",
1434
+ {
1435
+ type: "button",
1436
+ "aria-label": "Pick color",
1437
+ disabled: isDisabled,
1438
+ onClick: () => nativeRef.current?.click(),
1439
+ className: chunkMWAXK66H_cjs.cn(
1440
+ "relative flex shrink-0 items-center justify-center rounded-sm border border-rule",
1441
+ "cursor-pointer outline-none",
1442
+ "focus-visible:ring-2 focus-visible:ring-[var(--color-accent)]",
1443
+ "disabled:cursor-not-allowed",
1444
+ size === "sm" ? "size-4" : "size-5",
1445
+ committed ? null : "text-ink-4"
1446
+ ),
1447
+ style: committed ? { backgroundColor: committed } : void 0,
1448
+ children: [
1449
+ committed ? null : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pipette, { "aria-hidden": true, className: "size-2.5" }),
1450
+ /* @__PURE__ */ jsxRuntime.jsx(
1451
+ "input",
1452
+ {
1453
+ ref: nativeRef,
1454
+ type: "color",
1455
+ tabIndex: -1,
1456
+ "aria-hidden": true,
1457
+ disabled: isDisabled,
1458
+ value: committed ?? "#000000",
1459
+ onChange: (event) => pick(event.target.value),
1460
+ className: "pointer-events-none absolute inset-0 size-full opacity-0"
1461
+ }
1462
+ )
1463
+ ]
1464
+ }
1465
+ ),
1466
+ /* @__PURE__ */ jsxRuntime.jsx(
1467
+ reactAriaComponents.Input,
1468
+ {
1469
+ placeholder,
1470
+ spellCheck: false,
1471
+ autoComplete: "off",
1472
+ className: chunkMWAXK66H_cjs.cn(
1473
+ styles3.content(),
1474
+ "min-w-0 flex-1 bg-transparent font-mono outline-none",
1475
+ "pl-0",
1476
+ fieldTextStyles[size]
1477
+ )
1478
+ }
1479
+ )
1480
+ ]
1481
+ }
1482
+ ),
1483
+ description ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Text, { slot: "description", className: fieldHintStyles, children: description }) : null,
1484
+ errorMessage && appearance !== "cell" ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.FieldError, { className: fieldErrorStyles, children: errorMessage }) : null
1485
+ ]
1486
+ }
1487
+ );
1488
+ }
1030
1489
  function Combobox({
1031
1490
  label,
1032
1491
  description,
@@ -2162,6 +2621,7 @@ function useInfiniteScrollSentinel({
2162
2621
  return ref;
2163
2622
  }
2164
2623
  var DEFAULT_ROW_HEIGHT = 32;
2624
+ var SELECTION_COLUMN_ID = "__select__";
2165
2625
  function DataTable({
2166
2626
  query,
2167
2627
  columns,
@@ -2186,6 +2646,9 @@ function DataTable({
2186
2646
  extraRows,
2187
2647
  bodyBefore,
2188
2648
  bodyAfter,
2649
+ selectionMode = "none",
2650
+ selectedIds,
2651
+ onSelectionChange,
2189
2652
  columnBorders = false
2190
2653
  }) {
2191
2654
  const rows = react.useMemo(() => {
@@ -2196,19 +2659,112 @@ function DataTable({
2196
2659
  if (startExtras.length === 0 && endExtras.length === 0) return dataRows;
2197
2660
  return [...startExtras, ...dataRows, ...endExtras];
2198
2661
  }, [query.data, extraRows]);
2662
+ const resolveRowId = react.useMemo(
2663
+ () => getRowId ?? ((row, index) => {
2664
+ const r = row;
2665
+ if (typeof r.id === "string" || typeof r.id === "number") return String(r.id);
2666
+ if (typeof r.slug === "string") return r.slug;
2667
+ return String(index);
2668
+ }),
2669
+ [getRowId]
2670
+ );
2671
+ const selectionEnabled = selectionMode === "multiple";
2672
+ const selected = react.useMemo(() => selectedIds ?? /* @__PURE__ */ new Set(), [selectedIds]);
2673
+ const loadedIds = react.useMemo(
2674
+ () => selectionEnabled ? rows.map((row, index) => resolveRowId(row, index)) : [],
2675
+ [selectionEnabled, rows, resolveRowId]
2676
+ );
2677
+ const lastToggledIndexRef = react.useRef(null);
2678
+ const toggleRow = (id, index, isRange) => {
2679
+ if (!onSelectionChange) return;
2680
+ const next = new Set(selected);
2681
+ const anchor = lastToggledIndexRef.current;
2682
+ if (isRange && anchor !== null) {
2683
+ const [from, to] = anchor <= index ? [anchor, index] : [index, anchor];
2684
+ for (let i = from; i <= to; i += 1) {
2685
+ const rangeId = loadedIds[i];
2686
+ if (rangeId !== void 0) next.add(rangeId);
2687
+ }
2688
+ } else if (next.has(id)) {
2689
+ next.delete(id);
2690
+ } else {
2691
+ next.add(id);
2692
+ }
2693
+ lastToggledIndexRef.current = index;
2694
+ onSelectionChange(next);
2695
+ };
2696
+ const loadedSelectedCount = loadedIds.reduce((count, id) => count + (selected.has(id) ? 1 : 0), 0);
2697
+ const allLoadedSelected = loadedIds.length > 0 && loadedSelectedCount === loadedIds.length;
2698
+ const toggleAllLoaded = () => {
2699
+ if (!onSelectionChange) return;
2700
+ const next = new Set(selected);
2701
+ if (allLoadedSelected) {
2702
+ for (const id of loadedIds) next.delete(id);
2703
+ } else {
2704
+ for (const id of loadedIds) next.add(id);
2705
+ }
2706
+ lastToggledIndexRef.current = null;
2707
+ onSelectionChange(next);
2708
+ };
2709
+ const rangeModifierRef = react.useRef(false);
2710
+ const selectionColumn = react.useMemo(
2711
+ () => ({
2712
+ id: SELECTION_COLUMN_ID,
2713
+ size: 36,
2714
+ enableSorting: false,
2715
+ meta: { align: "center", sticky: "left", cellClassName: "px-0 justify-center" },
2716
+ header: () => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center justify-center w-full", children: /* @__PURE__ */ jsxRuntime.jsx(
2717
+ Checkbox,
2718
+ {
2719
+ "aria-label": allLoadedSelected ? "Deselect all rows" : "Select all rows",
2720
+ isSelected: allLoadedSelected,
2721
+ isIndeterminate: loadedSelectedCount > 0 && !allLoadedSelected,
2722
+ isDisabled: loadedIds.length === 0,
2723
+ onChange: toggleAllLoaded
2724
+ }
2725
+ ) }),
2726
+ cell: ({ row }) => (
2727
+ // Stop the click here: selecting a row must never also open it.
2728
+ /* @__PURE__ */ jsxRuntime.jsx(
2729
+ "span",
2730
+ {
2731
+ className: "inline-flex items-center justify-center w-full",
2732
+ onClick: (event) => event.stopPropagation(),
2733
+ onKeyDown: (event) => {
2734
+ event.stopPropagation();
2735
+ rangeModifierRef.current = event.shiftKey;
2736
+ },
2737
+ onPointerDownCapture: (event) => {
2738
+ rangeModifierRef.current = event.shiftKey;
2739
+ },
2740
+ role: "presentation",
2741
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2742
+ Checkbox,
2743
+ {
2744
+ "aria-label": `Select row ${row.index + 1}`,
2745
+ isSelected: selected.has(row.id),
2746
+ onChange: () => toggleRow(row.id, row.index, rangeModifierRef.current)
2747
+ }
2748
+ )
2749
+ }
2750
+ )
2751
+ )
2752
+ }),
2753
+ // biome-ignore lint/correctness/useExhaustiveDependencies: handlers read the latest selection via closure recreated on these inputs
2754
+ [selected, loadedIds, allLoadedSelected, loadedSelectedCount]
2755
+ );
2756
+ const tableColumns = react.useMemo(
2757
+ () => selectionEnabled ? [selectionColumn, ...columns] : columns,
2758
+ [selectionEnabled, selectionColumn, columns]
2759
+ );
2199
2760
  const table = reactTable.useReactTable({
2200
2761
  data: rows,
2201
- columns,
2762
+ columns: tableColumns,
2202
2763
  state: { sorting: sorting ?? [] },
2203
2764
  ...onSortingChange ? { onSortingChange } : {},
2204
2765
  manualSorting: true,
2205
2766
  getCoreRowModel: reactTable.getCoreRowModel(),
2206
- getRowId: getRowId ? (row, index) => getRowId(row, index) : (row, index) => {
2207
- const r = row;
2208
- if (typeof r.id === "string" || typeof r.id === "number") return String(r.id);
2209
- if (typeof r.slug === "string") return r.slug;
2210
- return String(index);
2211
- }
2767
+ getRowId: (row, index) => resolveRowId(row, index)
2212
2768
  });
2213
2769
  const tableRows = table.getRowModel().rows;
2214
2770
  const tableRowCount = tableRows.length;
@@ -2240,8 +2796,8 @@ function DataTable({
2240
2796
  enabled: !!query.hasNextPage
2241
2797
  });
2242
2798
  const totalColumnWidth = react.useMemo(
2243
- () => columns.reduce((sum, c) => sum + (c.size ?? 140), 0),
2244
- [columns]
2799
+ () => tableColumns.reduce((sum, c) => sum + (c.size ?? 140), 0),
2800
+ [tableColumns]
2245
2801
  );
2246
2802
  const columnsRef = react.useRef(columns);
2247
2803
  columnsRef.current = columns;
@@ -4877,25 +5433,25 @@ var OPERATORS = [
4877
5433
  id: "eq",
4878
5434
  label: "is",
4879
5435
  arity: 1,
4880
- types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "relation", "user"]
5436
+ types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "relation", "user", "principal"]
4881
5437
  },
4882
5438
  {
4883
5439
  id: "ne",
4884
5440
  label: "is not",
4885
5441
  arity: 1,
4886
- types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "relation", "user"]
5442
+ types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "relation", "user", "principal"]
4887
5443
  },
4888
5444
  {
4889
5445
  id: "in",
4890
5446
  label: "is any of",
4891
5447
  arity: "n",
4892
- types: ["string", "number", "integer", "currency", "enum", "relation", "user"]
5448
+ types: ["string", "number", "integer", "currency", "enum", "relation", "user", "principal"]
4893
5449
  },
4894
5450
  {
4895
5451
  id: "not_in",
4896
5452
  label: "is none of",
4897
5453
  arity: "n",
4898
- types: ["string", "number", "integer", "currency", "enum", "relation", "user"]
5454
+ types: ["string", "number", "integer", "currency", "enum", "relation", "user", "principal"]
4899
5455
  },
4900
5456
  { id: "contains", label: "contains", arity: 1, types: ["string", "array"] },
4901
5457
  { id: "starts_with", label: "starts with", arity: 1, types: ["string"] },
@@ -4908,13 +5464,13 @@ var OPERATORS = [
4908
5464
  id: "empty",
4909
5465
  label: "is empty",
4910
5466
  arity: 0,
4911
- types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "array", "relation", "user", "file"]
5467
+ types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "array", "relation", "user", "principal", "file"]
4912
5468
  },
4913
5469
  {
4914
5470
  id: "not_empty",
4915
5471
  label: "is not empty",
4916
5472
  arity: 0,
4917
- types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "array", "relation", "user", "file"]
5473
+ types: ["string", "number", "integer", "currency", "datetime", "enum", "boolean", "array", "relation", "user", "principal", "file"]
4918
5474
  }
4919
5475
  ];
4920
5476
  var OP_LABEL_OVERRIDES = {
@@ -5002,9 +5558,16 @@ function ChipItem({
5002
5558
  if (custom !== void 0) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: custom });
5003
5559
  }
5004
5560
  if (field.type === "enum") {
5005
- const variant = field.options?.find((o) => o.value === value)?.variant;
5006
- const label = field.options?.find((o) => o.value === value)?.label ?? value;
5007
- return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant, children: label });
5561
+ const option = field.options?.find((o) => o.value === value);
5562
+ return /* @__PURE__ */ jsxRuntime.jsx(
5563
+ Badge,
5564
+ {
5565
+ variant: option?.variant,
5566
+ ...option?.color ? { color: option.color } : {},
5567
+ ...option?.icon ? { icon: option.icon } : {},
5568
+ children: option?.label ?? value
5569
+ }
5570
+ );
5008
5571
  }
5009
5572
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: chunkMWAXK66H_cjs.cn("font-mono text-[12px] text-ink max-w-[10rem] truncate"), children: formatValue(field, operator, value) });
5010
5573
  }
@@ -5385,8 +5948,16 @@ function EnumSingleValue({
5385
5948
  selectedKey: value === "" ? null : value,
5386
5949
  onSelectionChange: (next) => onChange(next == null ? "" : String(next)),
5387
5950
  renderItem: (o) => {
5388
- const variant = field.options?.find((x) => x.value === o.id)?.variant;
5389
- return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant, children: o.label });
5951
+ const option = field.options?.find((x) => x.value === o.id);
5952
+ return /* @__PURE__ */ jsxRuntime.jsx(
5953
+ Badge,
5954
+ {
5955
+ variant: option?.variant,
5956
+ ...option?.color ? { color: option.color } : {},
5957
+ ...option?.icon ? { icon: option.icon } : {},
5958
+ children: o.label
5959
+ }
5960
+ );
5390
5961
  },
5391
5962
  ...isDisabled !== void 0 ? { isDisabled } : {},
5392
5963
  ...autoFocus ? { autoFocus: true } : {},
@@ -5405,7 +5976,9 @@ function EnumMultiValue({
5405
5976
  const options = (field.options ?? []).map((o) => ({
5406
5977
  id: o.value,
5407
5978
  label: o.label,
5408
- ...o.variant ? { variant: o.variant } : {}
5979
+ ...o.variant ? { variant: o.variant } : {},
5980
+ ...o.color ? { color: o.color } : {},
5981
+ ...o.icon ? { icon: o.icon } : {}
5409
5982
  }));
5410
5983
  return /* @__PURE__ */ jsxRuntime.jsx(
5411
5984
  BadgeMultiSelect,
@@ -7039,6 +7612,74 @@ function TimeField({
7039
7612
  }
7040
7613
  );
7041
7614
  }
7615
+ function createToastQueue(options = {}) {
7616
+ return new reactAriaComponents.UNSTABLE_ToastQueue({ maxVisibleToasts: options.maxVisibleToasts ?? 3 });
7617
+ }
7618
+ var toastStyles = tailwindVariants.tv({
7619
+ slots: {
7620
+ root: [
7621
+ "flex items-start gap-3 w-[360px] max-w-[calc(100vw-32px)]",
7622
+ "rounded-lg border border-rule bg-surface shadow-float",
7623
+ "px-3.5 py-3 outline-none",
7624
+ "focus-visible:shadow-focus",
7625
+ "entering:animate-in entering:fade-in-0 entering:slide-in-from-bottom-2 entering:duration-200",
7626
+ "exiting:animate-out exiting:fade-out-0 exiting:duration-150"
7627
+ ],
7628
+ icon: "size-4 shrink-0 mt-0.5",
7629
+ title: "font-sans text-[13px] font-medium leading-[1.4] text-ink",
7630
+ description: "font-sans text-[12.5px] leading-[1.5] text-ink-3 break-words"
7631
+ },
7632
+ variants: {
7633
+ variant: {
7634
+ info: { icon: "text-ink-3" },
7635
+ success: { icon: "text-success" },
7636
+ danger: { icon: "text-danger" }
7637
+ }
7638
+ },
7639
+ defaultVariants: { variant: "info" }
7640
+ });
7641
+ var VARIANT_ICON = {
7642
+ info: lucideReact.Info,
7643
+ success: lucideReact.CircleCheck,
7644
+ danger: lucideReact.CircleAlert
7645
+ };
7646
+ function ToastRegion({ queue, className }) {
7647
+ return /* @__PURE__ */ jsxRuntime.jsx(
7648
+ reactAriaComponents.UNSTABLE_ToastRegion,
7649
+ {
7650
+ queue,
7651
+ className: chunkMWAXK66H_cjs.cn(
7652
+ "fixed bottom-4 right-4 z-[1300] flex flex-col-reverse gap-2 outline-none",
7653
+ className
7654
+ ),
7655
+ children: ({ toast }) => {
7656
+ const variant = toast.content.variant ?? "info";
7657
+ const Icon = VARIANT_ICON[variant];
7658
+ const { root, icon, title, description } = toastStyles({ variant });
7659
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactAriaComponents.UNSTABLE_Toast, { toast, className: root(), children: [
7660
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: icon(), "aria-hidden": true }),
7661
+ /* @__PURE__ */ jsxRuntime.jsxs(reactAriaComponents.UNSTABLE_ToastContent, { className: "flex flex-col gap-0.5 flex-1 min-w-0", children: [
7662
+ /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Text, { slot: "title", className: title(), children: toast.content.title }),
7663
+ toast.content.description ? /* @__PURE__ */ jsxRuntime.jsx(reactAriaComponents.Text, { slot: "description", className: description(), children: toast.content.description }) : null
7664
+ ] }),
7665
+ /* @__PURE__ */ jsxRuntime.jsx(
7666
+ reactAriaComponents.Button,
7667
+ {
7668
+ slot: "close",
7669
+ "aria-label": "Dismiss",
7670
+ className: chunkMWAXK66H_cjs.cn(
7671
+ "shrink-0 inline-flex items-center justify-center size-6 rounded-md",
7672
+ "text-ink-4 hover:text-ink hover:bg-surface-2 cursor-pointer outline-none",
7673
+ "focus-visible:shadow-focus"
7674
+ ),
7675
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5" })
7676
+ }
7677
+ )
7678
+ ] });
7679
+ }
7680
+ }
7681
+ );
7682
+ }
7042
7683
  function TooltipTrigger({
7043
7684
  delay = 500,
7044
7685
  closeDelay = 0,
@@ -7110,6 +7751,7 @@ exports.ChannelIcon = ChannelIcon;
7110
7751
  exports.Checkbox = Checkbox;
7111
7752
  exports.CheckboxGroup = CheckboxGroup;
7112
7753
  exports.ChipValue = ChipValue;
7754
+ exports.ColorInput = ColorInput;
7113
7755
  exports.Combobox = Combobox;
7114
7756
  exports.Command = Command;
7115
7757
  exports.CommandHint = CommandHint;
@@ -7134,6 +7776,7 @@ exports.FileViewer = FileViewer;
7134
7776
  exports.FileViewerFallbackCard = FileViewerFallbackCard;
7135
7777
  exports.FilterRow = FilterRow;
7136
7778
  exports.FilterValueInput = FilterValueInput;
7779
+ exports.IconPicker = IconPicker;
7137
7780
  exports.ImageAttachment = ImageAttachment;
7138
7781
  exports.ImageLightbox = ImageLightbox;
7139
7782
  exports.Input = Input;
@@ -7175,6 +7818,7 @@ exports.RecordFilterChips = RecordFilterChips;
7175
7818
  exports.RecordFilterEditor = RecordFilterEditor;
7176
7819
  exports.RenderChipItemProvider = RenderChipItemProvider;
7177
7820
  exports.RenderValueInputProvider = RenderValueInputProvider;
7821
+ exports.SELECTION_COLUMN_ID = SELECTION_COLUMN_ID;
7178
7822
  exports.SegmentedControl = SegmentedControl;
7179
7823
  exports.Select = Select;
7180
7824
  exports.Separator = Separator;
@@ -7193,6 +7837,7 @@ exports.Tabs = Tabs;
7193
7837
  exports.TagInput = TagInput;
7194
7838
  exports.Textarea = Textarea;
7195
7839
  exports.TimeField = TimeField;
7840
+ exports.ToastRegion = ToastRegion;
7196
7841
  exports.Tooltip = Tooltip;
7197
7842
  exports.TooltipTrigger = TooltipTrigger;
7198
7843
  exports.TruncateCell = TruncateCell;
@@ -7210,6 +7855,7 @@ exports.cardStyles = cardStyles2;
7210
7855
  exports.channelIcon = channelIcon;
7211
7856
  exports.countLeaves = countLeaves;
7212
7857
  exports.createDraftMessageClient = createDraftMessageClient;
7858
+ exports.createToastQueue = createToastQueue;
7213
7859
  exports.defaultValueFor = defaultValueFor;
7214
7860
  exports.draftMessageCardStyles = draftMessageCardStyles;
7215
7861
  exports.draftMessageComposerStyles = draftMessageComposerStyles;
@@ -7233,6 +7879,7 @@ exports.isPreviewableImageName = isPreviewableImageName;
7233
7879
  exports.makeActionsColumn = makeActionsColumn;
7234
7880
  exports.messageComposerStyles = messageComposerStyles;
7235
7881
  exports.navItemStyles = navItemStyles;
7882
+ exports.normalizeHexColor = normalizeHexColor;
7236
7883
  exports.operatorById = operatorById;
7237
7884
  exports.operatorsForType = operatorsForType;
7238
7885
  exports.parseCombo = parseCombo;
@@ -7244,6 +7891,8 @@ exports.registerDraftMessageActions = registerDraftMessageActions;
7244
7891
  exports.removeLeaf = removeLeaf;
7245
7892
  exports.removeSubgroup = removeSubgroup;
7246
7893
  exports.replaceLeaf = replaceLeaf;
7894
+ exports.resolveLucideIcon = resolveLucideIcon;
7895
+ exports.resolveLucideIconName = resolveLucideIconName;
7247
7896
  exports.segmentedControlStyles = segmentedControlStyles;
7248
7897
  exports.setJoiner = setJoiner;
7249
7898
  exports.subscribeDraftMessageOutcome = subscribeDraftMessageOutcome;
@@ -7251,6 +7900,7 @@ exports.tableCellStyles = tableCellStyles;
7251
7900
  exports.tableHeaderCellStyles = tableHeaderCellStyles;
7252
7901
  exports.tabsStyles = tabsStyles;
7253
7902
  exports.terminalKindFor = terminalKindFor;
7903
+ exports.toastStyles = toastStyles;
7254
7904
  exports.updateLeaf = updateLeaf;
7255
7905
  exports.updateSubgroup = updateSubgroup;
7256
7906
  exports.useAttributeTypeIcon = useAttributeTypeIcon;