@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.
- package/dist/index.cjs +720 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +191 -8
- package/dist/index.d.ts +191 -8
- package/dist/index.js +715 -74
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/attribute-type-icon/attribute-type-icon.tsx +5 -0
- package/src/components/avatar/avatar.stories.tsx +37 -1
- package/src/components/avatar/avatar.test.tsx +42 -0
- package/src/components/avatar/avatar.tsx +39 -4
- package/src/components/avatar-group/avatar-group.test.tsx +19 -0
- package/src/components/avatar-group/avatar-group.tsx +18 -3
- package/src/components/badge/badge.stories.tsx +27 -1
- package/src/components/badge/badge.test.tsx +26 -0
- package/src/components/badge/badge.tsx +48 -4
- package/src/components/badge-multi-select/badge-multi-select.stories.tsx +24 -0
- package/src/components/badge-multi-select/badge-multi-select.tsx +25 -4
- package/src/components/checkbox/checkbox.tsx +8 -1
- package/src/components/color-input/color-input.stories.tsx +72 -0
- package/src/components/color-input/color-input.test.tsx +95 -0
- package/src/components/color-input/color-input.tsx +208 -0
- package/src/components/color-input/index.ts +2 -0
- package/src/components/data-table/data-table.test.tsx +112 -0
- package/src/components/data-table/data-table.tsx +135 -11
- package/src/components/data-table/index.ts +1 -1
- package/src/components/draft-message-composer/draft-message-composer.stories.tsx +1 -1
- package/src/components/icon-picker/icon-picker.stories.tsx +77 -0
- package/src/components/icon-picker/icon-picker.test.tsx +88 -0
- package/src/components/icon-picker/icon-picker.tsx +336 -0
- package/src/components/icon-picker/index.ts +2 -0
- package/src/components/record-filter/chip-value.tsx +10 -3
- package/src/components/record-filter/filter-value-input.tsx +12 -2
- package/src/components/record-filter/operators.ts +6 -6
- package/src/components/record-filter/record-filter.stories.tsx +1 -1
- package/src/components/record-filter/types.ts +4 -0
- package/src/components/table/table.stories.tsx +12 -13
- package/src/components/toast/index.ts +9 -0
- package/src/components/toast/toast.stories.tsx +58 -0
- package/src/components/toast/toast.test.tsx +34 -0
- package/src/components/toast/toast.tsx +121 -0
- package/src/index.ts +3 -0
- 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({
|
|
422
|
-
|
|
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({
|
|
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(
|
|
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
|
-
|
|
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, {
|
|
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
|
-
|
|
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:
|
|
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
|
-
() =>
|
|
2244
|
-
[
|
|
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
|
|
5006
|
-
|
|
5007
|
-
|
|
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
|
|
5389
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
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;
|