@salemcobalt/ui 0.2.0-rc.1 → 0.2.0-rc.10
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/README.md +30 -19
- package/dist/index.d.ts +1153 -42
- package/dist/index.js +1673 -43
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2897 -69
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -14,6 +14,8 @@ function Button({
|
|
|
14
14
|
iconEnd,
|
|
15
15
|
loading = false,
|
|
16
16
|
fullWidth = false,
|
|
17
|
+
shortcut,
|
|
18
|
+
iconOnly = false,
|
|
17
19
|
type = "button",
|
|
18
20
|
className,
|
|
19
21
|
children,
|
|
@@ -36,6 +38,7 @@ function Button({
|
|
|
36
38
|
"data-size": size,
|
|
37
39
|
"data-loading": loading || void 0,
|
|
38
40
|
"data-full-width": fullWidth || void 0,
|
|
41
|
+
"data-icon-only": iconOnly || void 0,
|
|
39
42
|
"aria-busy": loading || void 0,
|
|
40
43
|
onClick: handleClick,
|
|
41
44
|
...rest,
|
|
@@ -43,6 +46,7 @@ function Button({
|
|
|
43
46
|
iconStart ? /* @__PURE__ */ jsx("span", { className: "sc-button__icon", "aria-hidden": "true", children: iconStart }) : null,
|
|
44
47
|
/* @__PURE__ */ jsx("span", { className: "sc-button__label", children }),
|
|
45
48
|
iconEnd ? /* @__PURE__ */ jsx("span", { className: "sc-button__icon", "aria-hidden": "true", children: iconEnd }) : null,
|
|
49
|
+
shortcut ? /* @__PURE__ */ jsx("span", { className: "sc-button__shortcut", "aria-hidden": "true", children: shortcut }) : null,
|
|
46
50
|
loading ? /* @__PURE__ */ jsx("span", { className: "sc-button__spinner", "aria-hidden": "true" }) : null
|
|
47
51
|
]
|
|
48
52
|
}
|
|
@@ -196,12 +200,18 @@ function ArchiveIcon(props) {
|
|
|
196
200
|
/* @__PURE__ */ jsx5("path", { d: "M3.25 5.75v6.5a1 1 0 0 0 1 1h7.5a1 1 0 0 0 1-1v-6.5M6.5 8.75h3" })
|
|
197
201
|
] });
|
|
198
202
|
}
|
|
203
|
+
function ArrowDownIcon(props) {
|
|
204
|
+
return /* @__PURE__ */ jsx5(Icon, { ...props, children: /* @__PURE__ */ jsx5("path", { d: "M8 3v10M4 9l4 4 4-4" }) });
|
|
205
|
+
}
|
|
199
206
|
function ArrowLeftIcon(props) {
|
|
200
207
|
return /* @__PURE__ */ jsx5(Icon, { ...props, children: /* @__PURE__ */ jsx5("path", { d: "M13 8H3M7 4 3 8l4 4" }) });
|
|
201
208
|
}
|
|
202
209
|
function ArrowRightIcon(props) {
|
|
203
210
|
return /* @__PURE__ */ jsx5(Icon, { ...props, children: /* @__PURE__ */ jsx5("path", { d: "M3 8h10M9 4l4 4-4 4" }) });
|
|
204
211
|
}
|
|
212
|
+
function ArrowUpIcon(props) {
|
|
213
|
+
return /* @__PURE__ */ jsx5(Icon, { ...props, children: /* @__PURE__ */ jsx5("path", { d: "M8 13V3M4 7l4-4 4 4" }) });
|
|
214
|
+
}
|
|
205
215
|
function BellIcon(props) {
|
|
206
216
|
return /* @__PURE__ */ jsxs4(Icon, { ...props, children: [
|
|
207
217
|
/* @__PURE__ */ jsx5("path", { d: "M4 6.5a4 4 0 0 1 8 0v3l1.25 2H2.75L4 9.5z" }),
|
|
@@ -451,7 +461,7 @@ function Root({ dismissible = true, onOpenChange, open, defaultOpen, children })
|
|
|
451
461
|
);
|
|
452
462
|
}
|
|
453
463
|
var Trigger = BaseDialog.Trigger;
|
|
454
|
-
function Content({ size = "md", className, children, ...rest }) {
|
|
464
|
+
function Content({ size = "md", variant = "dialog", className, children, ...rest }) {
|
|
455
465
|
return /* @__PURE__ */ jsxs5(BaseDialog.Portal, { children: [
|
|
456
466
|
/* @__PURE__ */ jsx6(BaseDialog.Backdrop, { className: "sc-dialog__backdrop" }),
|
|
457
467
|
/* @__PURE__ */ jsx6(
|
|
@@ -459,6 +469,7 @@ function Content({ size = "md", className, children, ...rest }) {
|
|
|
459
469
|
{
|
|
460
470
|
className: cx("sc-dialog__popup", className),
|
|
461
471
|
"data-size": size,
|
|
472
|
+
"data-variant": variant,
|
|
462
473
|
"aria-modal": "true",
|
|
463
474
|
...rest,
|
|
464
475
|
children
|
|
@@ -489,8 +500,10 @@ var Dialog = { Root, Trigger, Content, Title, Description, Body, Actions, Close
|
|
|
489
500
|
// src/icons/icon-names.gen.ts
|
|
490
501
|
var iconNames = [
|
|
491
502
|
"archive",
|
|
503
|
+
"arrow-down",
|
|
492
504
|
"arrow-left",
|
|
493
505
|
"arrow-right",
|
|
506
|
+
"arrow-up",
|
|
494
507
|
"bell",
|
|
495
508
|
"briefcase",
|
|
496
509
|
"calendar",
|
|
@@ -537,6 +550,9 @@ var iconNames = [
|
|
|
537
550
|
"x"
|
|
538
551
|
];
|
|
539
552
|
|
|
553
|
+
// src/components/IconButton/IconButton.tsx
|
|
554
|
+
import { useRender as useRender2 } from "@base-ui/react/use-render";
|
|
555
|
+
|
|
540
556
|
// src/components/Tooltip/Tooltip.tsx
|
|
541
557
|
import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
542
558
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
@@ -574,7 +590,7 @@ var Provider = BaseTooltip.Provider;
|
|
|
574
590
|
var Tooltip = Object.assign(TooltipBase, { Provider });
|
|
575
591
|
|
|
576
592
|
// src/components/IconButton/IconButton.tsx
|
|
577
|
-
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
593
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
578
594
|
function IconButton({
|
|
579
595
|
label,
|
|
580
596
|
children,
|
|
@@ -584,9 +600,12 @@ function IconButton({
|
|
|
584
600
|
tooltipSide = "top",
|
|
585
601
|
round = false,
|
|
586
602
|
loading = false,
|
|
587
|
-
|
|
603
|
+
dot,
|
|
604
|
+
type,
|
|
588
605
|
className,
|
|
589
606
|
onClick,
|
|
607
|
+
render,
|
|
608
|
+
ref,
|
|
590
609
|
...rest
|
|
591
610
|
}) {
|
|
592
611
|
const handleClick = (event) => {
|
|
@@ -596,10 +615,13 @@ function IconButton({
|
|
|
596
615
|
}
|
|
597
616
|
onClick?.(event);
|
|
598
617
|
};
|
|
599
|
-
const button =
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
618
|
+
const button = useRender2({
|
|
619
|
+
render,
|
|
620
|
+
ref,
|
|
621
|
+
defaultTagName: "button",
|
|
622
|
+
props: {
|
|
623
|
+
// `type` only means something on a real button; a rendered link keeps its own attributes.
|
|
624
|
+
type: render ? type : type ?? "button",
|
|
603
625
|
className: cx("sc-button", "sc-icon-button", className),
|
|
604
626
|
"data-variant": variant,
|
|
605
627
|
"data-size": size,
|
|
@@ -609,19 +631,20 @@ function IconButton({
|
|
|
609
631
|
"aria-label": label,
|
|
610
632
|
onClick: handleClick,
|
|
611
633
|
...rest,
|
|
612
|
-
children: [
|
|
634
|
+
children: /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
613
635
|
/* @__PURE__ */ jsx8("span", { className: "sc-button__icon", "aria-hidden": "true", children }),
|
|
614
|
-
loading ? /* @__PURE__ */ jsx8("span", { className: "sc-button__spinner", "aria-hidden": "true" }) : null
|
|
615
|
-
|
|
636
|
+
loading ? /* @__PURE__ */ jsx8("span", { className: "sc-button__spinner", "aria-hidden": "true" }) : null,
|
|
637
|
+
dot ? /* @__PURE__ */ jsx8("span", { className: "sc-icon-button__dot", "data-tone": dot, "aria-hidden": "true" }) : null
|
|
638
|
+
] })
|
|
616
639
|
}
|
|
617
|
-
);
|
|
640
|
+
});
|
|
618
641
|
if (!tooltip) return button;
|
|
619
642
|
return /* @__PURE__ */ jsx8(Tooltip, { content: tooltip === true ? label : tooltip, side: tooltipSide, children: button });
|
|
620
643
|
}
|
|
621
644
|
|
|
622
645
|
// src/components/Menu/Menu.tsx
|
|
623
646
|
import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
624
|
-
import { Fragment as
|
|
647
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
625
648
|
function Root2({ open, defaultOpen, onOpenChange, disabled, modal = true, children }) {
|
|
626
649
|
return /* @__PURE__ */ jsx9(
|
|
627
650
|
BaseMenu.Root,
|
|
@@ -661,7 +684,7 @@ function ItemBody({
|
|
|
661
684
|
trailing,
|
|
662
685
|
children
|
|
663
686
|
}) {
|
|
664
|
-
return /* @__PURE__ */ jsxs8(
|
|
687
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
665
688
|
/* @__PURE__ */ jsx9("span", { className: "sc-menu__icon", "aria-hidden": "true", children: icon }),
|
|
666
689
|
/* @__PURE__ */ jsx9("span", { className: "sc-menu__label", children }),
|
|
667
690
|
trailing !== void 0 ? /* @__PURE__ */ jsx9("span", { className: "sc-menu__trailing", children: trailing }) : null
|
|
@@ -848,9 +871,14 @@ function Textarea({
|
|
|
848
871
|
className,
|
|
849
872
|
rows = 3,
|
|
850
873
|
resize = "vertical",
|
|
874
|
+
variant = "default",
|
|
851
875
|
onValueChange,
|
|
876
|
+
spellCheck,
|
|
877
|
+
autoCorrect,
|
|
878
|
+
autoCapitalize,
|
|
852
879
|
...rest
|
|
853
880
|
}) {
|
|
881
|
+
const code = variant === "code";
|
|
854
882
|
return /* @__PURE__ */ jsx12(
|
|
855
883
|
FieldShell,
|
|
856
884
|
{
|
|
@@ -866,9 +894,19 @@ function Textarea({
|
|
|
866
894
|
children: /* @__PURE__ */ jsx12(
|
|
867
895
|
Field3.Control,
|
|
868
896
|
{
|
|
869
|
-
render: /* @__PURE__ */ jsx12(
|
|
897
|
+
render: /* @__PURE__ */ jsx12(
|
|
898
|
+
"textarea",
|
|
899
|
+
{
|
|
900
|
+
rows,
|
|
901
|
+
spellCheck: spellCheck ?? (code ? false : void 0),
|
|
902
|
+
autoCorrect: autoCorrect ?? (code ? "off" : void 0),
|
|
903
|
+
autoCapitalize: autoCapitalize ?? (code ? "off" : void 0),
|
|
904
|
+
...rest
|
|
905
|
+
}
|
|
906
|
+
),
|
|
870
907
|
className: "sc-input sc-textarea",
|
|
871
908
|
"data-resize": resize,
|
|
909
|
+
"data-variant": code ? "code" : void 0,
|
|
872
910
|
required,
|
|
873
911
|
onValueChange: onValueChange ? (value) => onValueChange(value) : void 0
|
|
874
912
|
}
|
|
@@ -879,6 +917,7 @@ function Textarea({
|
|
|
879
917
|
|
|
880
918
|
// src/components/Select/Select.tsx
|
|
881
919
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
920
|
+
import { useState } from "react";
|
|
882
921
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
883
922
|
function isGroup(entry) {
|
|
884
923
|
return "options" in entry;
|
|
@@ -905,11 +944,27 @@ function Select({
|
|
|
905
944
|
defaultValue,
|
|
906
945
|
onValueChange,
|
|
907
946
|
placeholder = "Choose\u2026",
|
|
947
|
+
clearable = false,
|
|
948
|
+
clearLabel = "Clear",
|
|
908
949
|
readOnly,
|
|
909
950
|
fullWidth = false,
|
|
910
951
|
id
|
|
911
952
|
}) {
|
|
912
953
|
const items = options.flatMap((entry) => isGroup(entry) ? entry.options : [entry]);
|
|
954
|
+
const [internal, setInternal] = useState(defaultValue ?? null);
|
|
955
|
+
const controlled = value !== void 0;
|
|
956
|
+
const current = controlled ? value : internal;
|
|
957
|
+
const setValue = (next) => {
|
|
958
|
+
if (!controlled) setInternal(next);
|
|
959
|
+
onValueChange?.(next);
|
|
960
|
+
};
|
|
961
|
+
const canClear = clearable && current != null && !disabled && !readOnly;
|
|
962
|
+
const onTriggerKeyDown = (event) => {
|
|
963
|
+
if (canClear && (event.key === "Backspace" || event.key === "Delete")) {
|
|
964
|
+
event.preventDefault();
|
|
965
|
+
setValue(null);
|
|
966
|
+
}
|
|
967
|
+
};
|
|
913
968
|
return /* @__PURE__ */ jsx13(
|
|
914
969
|
FieldShell,
|
|
915
970
|
{
|
|
@@ -927,26 +982,39 @@ function Select({
|
|
|
927
982
|
BaseSelect.Root,
|
|
928
983
|
{
|
|
929
984
|
items,
|
|
930
|
-
value,
|
|
931
|
-
|
|
932
|
-
onValueChange: onValueChange ? (next) => onValueChange(next) : void 0,
|
|
985
|
+
value: current,
|
|
986
|
+
onValueChange: (next) => setValue(next),
|
|
933
987
|
disabled,
|
|
934
988
|
required,
|
|
935
989
|
readOnly,
|
|
936
990
|
children: [
|
|
937
|
-
/* @__PURE__ */ jsxs11(
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
991
|
+
/* @__PURE__ */ jsxs11("span", { className: "sc-select__wrap", "data-full-width": fullWidth || void 0, children: [
|
|
992
|
+
/* @__PURE__ */ jsxs11(
|
|
993
|
+
BaseSelect.Trigger,
|
|
994
|
+
{
|
|
995
|
+
id,
|
|
996
|
+
className: "sc-select",
|
|
997
|
+
"data-size": size,
|
|
998
|
+
"data-full-width": fullWidth || void 0,
|
|
999
|
+
"data-clearable": canClear || void 0,
|
|
1000
|
+
onKeyDown: onTriggerKeyDown,
|
|
1001
|
+
children: [
|
|
1002
|
+
/* @__PURE__ */ jsx13(BaseSelect.Value, { className: "sc-select__value", placeholder }),
|
|
1003
|
+
/* @__PURE__ */ jsx13(BaseSelect.Icon, { className: "sc-select__icon", children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) })
|
|
1004
|
+
]
|
|
1005
|
+
}
|
|
1006
|
+
),
|
|
1007
|
+
canClear ? /* @__PURE__ */ jsx13(
|
|
1008
|
+
"button",
|
|
1009
|
+
{
|
|
1010
|
+
type: "button",
|
|
1011
|
+
className: "sc-select__clear",
|
|
1012
|
+
"aria-label": clearLabel,
|
|
1013
|
+
onClick: () => setValue(null),
|
|
1014
|
+
children: /* @__PURE__ */ jsx13(XIcon, { size: "sm" })
|
|
1015
|
+
}
|
|
1016
|
+
) : null
|
|
1017
|
+
] }),
|
|
950
1018
|
/* @__PURE__ */ jsx13(BaseSelect.Portal, { children: /* @__PURE__ */ jsx13(
|
|
951
1019
|
BaseSelect.Positioner,
|
|
952
1020
|
{
|
|
@@ -1046,7 +1114,7 @@ function Switch({
|
|
|
1046
1114
|
|
|
1047
1115
|
// src/components/Tabs/Tabs.tsx
|
|
1048
1116
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
1049
|
-
import { Fragment as
|
|
1117
|
+
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1050
1118
|
function Root3({ className, onValueChange, ...rest }) {
|
|
1051
1119
|
return /* @__PURE__ */ jsx16(
|
|
1052
1120
|
BaseTabs.Root,
|
|
@@ -1057,17 +1125,26 @@ function Root3({ className, onValueChange, ...rest }) {
|
|
|
1057
1125
|
}
|
|
1058
1126
|
);
|
|
1059
1127
|
}
|
|
1060
|
-
function List({ fill = false, className, children, ...rest }) {
|
|
1061
|
-
return /* @__PURE__ */ jsxs14(
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1128
|
+
function List({ fill = false, variant = "line", className, children, ...rest }) {
|
|
1129
|
+
return /* @__PURE__ */ jsxs14(
|
|
1130
|
+
BaseTabs.List,
|
|
1131
|
+
{
|
|
1132
|
+
className: cx("sc-tabs__list", className),
|
|
1133
|
+
"data-fill": fill || void 0,
|
|
1134
|
+
"data-variant": variant,
|
|
1135
|
+
...rest,
|
|
1136
|
+
children: [
|
|
1137
|
+
children,
|
|
1138
|
+
/* @__PURE__ */ jsx16(BaseTabs.Indicator, { className: "sc-tabs__indicator" })
|
|
1139
|
+
]
|
|
1140
|
+
}
|
|
1141
|
+
);
|
|
1065
1142
|
}
|
|
1066
1143
|
function Tab({ icon, count, className, children, ...rest }) {
|
|
1067
1144
|
return /* @__PURE__ */ jsxs14(BaseTabs.Tab, { className: cx("sc-tabs__tab", className), ...rest, children: [
|
|
1068
1145
|
icon ? /* @__PURE__ */ jsx16("span", { className: "sc-tabs__icon", "aria-hidden": "true", children: icon }) : null,
|
|
1069
1146
|
/* @__PURE__ */ jsx16("span", { className: "sc-tabs__label", children }),
|
|
1070
|
-
count != null ? /* @__PURE__ */ jsxs14(
|
|
1147
|
+
count != null ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
1071
1148
|
" ",
|
|
1072
1149
|
/* @__PURE__ */ jsx16("span", { className: "sc-tabs__count", children: count })
|
|
1073
1150
|
] }) : null
|
|
@@ -1099,13 +1176,14 @@ function Separator2({ className, ...rest }) {
|
|
|
1099
1176
|
return /* @__PURE__ */ jsx17(BaseToolbar.Separator, { className: cx("sc-toolbar__separator", className), ...rest });
|
|
1100
1177
|
}
|
|
1101
1178
|
var Button2 = BaseToolbar.Button;
|
|
1179
|
+
var Link = BaseToolbar.Link;
|
|
1102
1180
|
function Spacer({ className }) {
|
|
1103
1181
|
return /* @__PURE__ */ jsx17("div", { className: cx("sc-toolbar__spacer", className), "aria-hidden": "true" });
|
|
1104
1182
|
}
|
|
1105
|
-
var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Spacer };
|
|
1183
|
+
var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Link, Spacer };
|
|
1106
1184
|
|
|
1107
1185
|
// src/components/Banner/Banner.tsx
|
|
1108
|
-
import { useState } from "react";
|
|
1186
|
+
import { useState as useState2 } from "react";
|
|
1109
1187
|
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1110
1188
|
var toneIcons = {
|
|
1111
1189
|
info: /* @__PURE__ */ jsx18(InfoIcon, {}),
|
|
@@ -1127,7 +1205,7 @@ function Banner({
|
|
|
1127
1205
|
children,
|
|
1128
1206
|
...rest
|
|
1129
1207
|
}) {
|
|
1130
|
-
const [dismissed, setDismissed] =
|
|
1208
|
+
const [dismissed, setDismissed] = useState2(false);
|
|
1131
1209
|
const visible = open ?? !dismissed;
|
|
1132
1210
|
if (!visible) return null;
|
|
1133
1211
|
const glyph = icon === false ? null : icon ?? toneIcons[tone];
|
|
@@ -1279,30 +1357,1569 @@ function Text({
|
|
|
1279
1357
|
style,
|
|
1280
1358
|
...rest
|
|
1281
1359
|
}) {
|
|
1282
|
-
const
|
|
1360
|
+
const clamp2 = typeof truncate === "number" ? truncate : void 0;
|
|
1283
1361
|
return createElement4(as, {
|
|
1284
1362
|
className: cx("sc-text", className),
|
|
1285
1363
|
"data-size": size,
|
|
1286
1364
|
"data-tone": tone,
|
|
1287
1365
|
"data-weight": weight,
|
|
1288
1366
|
"data-align": align,
|
|
1289
|
-
"data-truncate": truncate === true ? "" :
|
|
1367
|
+
"data-truncate": truncate === true ? "" : clamp2 !== void 0 ? "clamp" : void 0,
|
|
1290
1368
|
"data-numeric": numeric || void 0,
|
|
1291
|
-
style:
|
|
1369
|
+
style: clamp2 !== void 0 ? { ...style, "--sc-text-lines": clamp2 } : style,
|
|
1292
1370
|
...rest
|
|
1293
1371
|
});
|
|
1294
1372
|
}
|
|
1295
1373
|
|
|
1374
|
+
// src/components/Table/Table.tsx
|
|
1375
|
+
import { Checkbox as BaseCheckbox2 } from "@base-ui/react/checkbox";
|
|
1376
|
+
import {
|
|
1377
|
+
createContext,
|
|
1378
|
+
useContext
|
|
1379
|
+
} from "react";
|
|
1380
|
+
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1381
|
+
var SelectionContext = createContext(null);
|
|
1382
|
+
var RowIdContext = createContext(void 0);
|
|
1383
|
+
function useSelection(part) {
|
|
1384
|
+
const selection = useContext(SelectionContext);
|
|
1385
|
+
if (!selection) throw new Error(`${part} needs Table.Root selection={useRowSelection(ids)}`);
|
|
1386
|
+
return selection;
|
|
1387
|
+
}
|
|
1388
|
+
function isTextEntry(target) {
|
|
1389
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
1390
|
+
if (target.isContentEditable || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement)
|
|
1391
|
+
return true;
|
|
1392
|
+
return target instanceof HTMLInputElement && !["checkbox", "radio", "button", "submit", "reset", "image", "file", "color", "range"].includes(
|
|
1393
|
+
target.type
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
var CONTROLS = 'a[href], button, input, select, textarea, label, summary, [role="checkbox"], [role="button"], [role="link"], [contenteditable="true"]';
|
|
1397
|
+
function fromControl(event) {
|
|
1398
|
+
const control = event.target instanceof Element ? event.target.closest(CONTROLS) : null;
|
|
1399
|
+
return control !== null && event.currentTarget.contains(control);
|
|
1400
|
+
}
|
|
1401
|
+
function Root5({
|
|
1402
|
+
stickyHeader = false,
|
|
1403
|
+
maxHeight,
|
|
1404
|
+
density,
|
|
1405
|
+
divided = true,
|
|
1406
|
+
layout = "auto",
|
|
1407
|
+
wrapperClassName,
|
|
1408
|
+
wrapperStyle,
|
|
1409
|
+
className,
|
|
1410
|
+
style,
|
|
1411
|
+
children,
|
|
1412
|
+
selection,
|
|
1413
|
+
onKeyDown,
|
|
1414
|
+
...rest
|
|
1415
|
+
}) {
|
|
1416
|
+
const handleKeyDown = (event) => {
|
|
1417
|
+
onKeyDown?.(event);
|
|
1418
|
+
if (!selection || event.defaultPrevented) return;
|
|
1419
|
+
if (!(event.target instanceof Node) || !event.currentTarget.contains(event.target)) return;
|
|
1420
|
+
if (isTextEntry(event.target)) return;
|
|
1421
|
+
if ((event.metaKey || event.ctrlKey) && !event.altKey && event.key.toLowerCase() === "a") {
|
|
1422
|
+
event.preventDefault();
|
|
1423
|
+
selection.selectAll();
|
|
1424
|
+
} else if (event.key === "Escape" && selection.count > 0) {
|
|
1425
|
+
event.preventDefault();
|
|
1426
|
+
selection.clear();
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
return /* @__PURE__ */ jsx21(
|
|
1430
|
+
"div",
|
|
1431
|
+
{
|
|
1432
|
+
className: cx("sc-table-wrap", wrapperClassName),
|
|
1433
|
+
"data-sticky-header": stickyHeader || void 0,
|
|
1434
|
+
"data-scroll": maxHeight ? "" : void 0,
|
|
1435
|
+
style: maxHeight ? { ...wrapperStyle, maxBlockSize: maxHeight } : wrapperStyle,
|
|
1436
|
+
children: /* @__PURE__ */ jsx21(
|
|
1437
|
+
"table",
|
|
1438
|
+
{
|
|
1439
|
+
className: cx("sc-table", className),
|
|
1440
|
+
"data-density": density,
|
|
1441
|
+
"data-divided": divided || void 0,
|
|
1442
|
+
"data-layout": layout,
|
|
1443
|
+
style,
|
|
1444
|
+
onKeyDown: selection ? handleKeyDown : onKeyDown,
|
|
1445
|
+
...rest,
|
|
1446
|
+
children: /* @__PURE__ */ jsx21(SelectionContext.Provider, { value: selection ?? null, children })
|
|
1447
|
+
}
|
|
1448
|
+
)
|
|
1449
|
+
}
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
function Caption({ className, ...rest }) {
|
|
1453
|
+
return /* @__PURE__ */ jsx21("caption", { className: cx("sc-table__caption", className), ...rest });
|
|
1454
|
+
}
|
|
1455
|
+
function Head({ className, ...rest }) {
|
|
1456
|
+
return /* @__PURE__ */ jsx21("thead", { className: cx("sc-table__head", className), ...rest });
|
|
1457
|
+
}
|
|
1458
|
+
function Body2({ className, ...rest }) {
|
|
1459
|
+
return /* @__PURE__ */ jsx21("tbody", { className: cx("sc-table__body", className), ...rest });
|
|
1460
|
+
}
|
|
1461
|
+
function Foot({ className, ...rest }) {
|
|
1462
|
+
return /* @__PURE__ */ jsx21("tfoot", { className: cx("sc-table__foot", className), ...rest });
|
|
1463
|
+
}
|
|
1464
|
+
function Row({
|
|
1465
|
+
selected,
|
|
1466
|
+
interactive = false,
|
|
1467
|
+
selectionId,
|
|
1468
|
+
className,
|
|
1469
|
+
onClick,
|
|
1470
|
+
onMouseDown,
|
|
1471
|
+
...rest
|
|
1472
|
+
}) {
|
|
1473
|
+
const selection = useContext(SelectionContext);
|
|
1474
|
+
const selectable = selection !== null && selectionId !== void 0;
|
|
1475
|
+
const isSelected = selected ?? (selectable && selection.isSelected(selectionId));
|
|
1476
|
+
const row = /* @__PURE__ */ jsx21(
|
|
1477
|
+
"tr",
|
|
1478
|
+
{
|
|
1479
|
+
className: cx("sc-table__row", className),
|
|
1480
|
+
"data-selected": isSelected || void 0,
|
|
1481
|
+
"data-interactive": interactive || void 0,
|
|
1482
|
+
"aria-selected": selectable ? isSelected : isSelected || void 0,
|
|
1483
|
+
onClick: selectable ? (event) => {
|
|
1484
|
+
if ((event.shiftKey || event.metaKey || event.ctrlKey) && !fromControl(event)) {
|
|
1485
|
+
event.preventDefault();
|
|
1486
|
+
if (event.shiftKey) selection.toggleRange(selectionId);
|
|
1487
|
+
else selection.toggle(selectionId);
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
onClick?.(event);
|
|
1491
|
+
} : onClick,
|
|
1492
|
+
onMouseDown: selectable ? (event) => {
|
|
1493
|
+
if (event.shiftKey && !fromControl(event)) event.preventDefault();
|
|
1494
|
+
onMouseDown?.(event);
|
|
1495
|
+
} : onMouseDown,
|
|
1496
|
+
...rest
|
|
1497
|
+
}
|
|
1498
|
+
);
|
|
1499
|
+
return selectionId === void 0 ? row : /* @__PURE__ */ jsx21(RowIdContext.Provider, { value: selectionId, children: row });
|
|
1500
|
+
}
|
|
1501
|
+
function SelectionBox({
|
|
1502
|
+
label,
|
|
1503
|
+
...rest
|
|
1504
|
+
}) {
|
|
1505
|
+
return /* @__PURE__ */ jsx21(BaseCheckbox2.Root, { className: "sc-checkbox", "aria-label": label, ...rest, children: /* @__PURE__ */ jsxs18(BaseCheckbox2.Indicator, { className: "sc-checkbox__indicator", children: [
|
|
1506
|
+
/* @__PURE__ */ jsx21(CheckIcon, { size: "sm", className: "sc-checkbox__check" }),
|
|
1507
|
+
/* @__PURE__ */ jsx21(MinusIcon, { size: "sm", className: "sc-checkbox__dash" })
|
|
1508
|
+
] }) });
|
|
1509
|
+
}
|
|
1510
|
+
var onCheckbox = (event) => event.target instanceof Element && event.target.closest('[role="checkbox"]') !== null;
|
|
1511
|
+
function SelectionHeader({
|
|
1512
|
+
label = "Select all rows",
|
|
1513
|
+
className,
|
|
1514
|
+
onClick,
|
|
1515
|
+
...rest
|
|
1516
|
+
}) {
|
|
1517
|
+
const selection = useSelection("Table.SelectionHeader");
|
|
1518
|
+
const disabled = selection.ids.length === 0;
|
|
1519
|
+
const toggleAll = () => selection.headerState === "all" ? selection.clear() : selection.selectAll();
|
|
1520
|
+
return /* @__PURE__ */ jsx21(
|
|
1521
|
+
"th",
|
|
1522
|
+
{
|
|
1523
|
+
scope: "col",
|
|
1524
|
+
className: cx("sc-table__header", "sc-table__select", className),
|
|
1525
|
+
"data-disabled": disabled || void 0,
|
|
1526
|
+
onClick: (event) => {
|
|
1527
|
+
onClick?.(event);
|
|
1528
|
+
if (!disabled && !onCheckbox(event)) toggleAll();
|
|
1529
|
+
},
|
|
1530
|
+
...rest,
|
|
1531
|
+
children: /* @__PURE__ */ jsx21(
|
|
1532
|
+
SelectionBox,
|
|
1533
|
+
{
|
|
1534
|
+
label,
|
|
1535
|
+
checked: selection.headerState === "all",
|
|
1536
|
+
indeterminate: selection.headerState === "some",
|
|
1537
|
+
disabled,
|
|
1538
|
+
onCheckedChange: toggleAll
|
|
1539
|
+
}
|
|
1540
|
+
)
|
|
1541
|
+
}
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
function SelectionCell({ label, className, onClick, onClickCapture, ...rest }) {
|
|
1545
|
+
const selection = useSelection("Table.SelectionCell");
|
|
1546
|
+
const id = useContext(RowIdContext);
|
|
1547
|
+
if (id === void 0) throw new Error("Table.SelectionCell goes inside a Table.Row with selectionId");
|
|
1548
|
+
return /* @__PURE__ */ jsx21(
|
|
1549
|
+
"td",
|
|
1550
|
+
{
|
|
1551
|
+
className: cx("sc-table__cell", "sc-table__select", className),
|
|
1552
|
+
onClickCapture: (event) => {
|
|
1553
|
+
onClickCapture?.(event);
|
|
1554
|
+
if (!event.shiftKey) return;
|
|
1555
|
+
event.preventDefault();
|
|
1556
|
+
event.stopPropagation();
|
|
1557
|
+
selection.toggleRange(id);
|
|
1558
|
+
},
|
|
1559
|
+
onClick: (event) => {
|
|
1560
|
+
onClick?.(event);
|
|
1561
|
+
event.stopPropagation();
|
|
1562
|
+
if (!onCheckbox(event)) selection.toggle(id);
|
|
1563
|
+
},
|
|
1564
|
+
...rest,
|
|
1565
|
+
children: /* @__PURE__ */ jsx21(
|
|
1566
|
+
SelectionBox,
|
|
1567
|
+
{
|
|
1568
|
+
label,
|
|
1569
|
+
checked: selection.isSelected(id),
|
|
1570
|
+
onCheckedChange: () => selection.toggle(id)
|
|
1571
|
+
}
|
|
1572
|
+
)
|
|
1573
|
+
}
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
function Header({
|
|
1577
|
+
align,
|
|
1578
|
+
numeric = false,
|
|
1579
|
+
nowrap = false,
|
|
1580
|
+
truncate = false,
|
|
1581
|
+
width,
|
|
1582
|
+
sortable = false,
|
|
1583
|
+
sortDirection = "none",
|
|
1584
|
+
onSort,
|
|
1585
|
+
scope = "col",
|
|
1586
|
+
className,
|
|
1587
|
+
style,
|
|
1588
|
+
children,
|
|
1589
|
+
...rest
|
|
1590
|
+
}) {
|
|
1591
|
+
const sorted = sortable && sortDirection !== "none";
|
|
1592
|
+
return /* @__PURE__ */ jsx21(
|
|
1593
|
+
"th",
|
|
1594
|
+
{
|
|
1595
|
+
scope,
|
|
1596
|
+
className: cx("sc-table__header", className),
|
|
1597
|
+
"data-align": align ?? (numeric ? "end" : void 0),
|
|
1598
|
+
"data-numeric": numeric || void 0,
|
|
1599
|
+
"data-nowrap": nowrap || void 0,
|
|
1600
|
+
"data-truncate": truncate || void 0,
|
|
1601
|
+
"data-sortable": sortable || void 0,
|
|
1602
|
+
"data-sorted": sorted ? sortDirection : void 0,
|
|
1603
|
+
"aria-sort": sorted ? sortDirection : void 0,
|
|
1604
|
+
style: width ? { ...style, inlineSize: width } : style,
|
|
1605
|
+
...rest,
|
|
1606
|
+
children: sortable ? /* @__PURE__ */ jsxs18(
|
|
1607
|
+
"button",
|
|
1608
|
+
{
|
|
1609
|
+
type: "button",
|
|
1610
|
+
className: "sc-table__sort",
|
|
1611
|
+
onClick: () => onSort?.(sortDirection === "ascending" ? "descending" : "ascending"),
|
|
1612
|
+
children: [
|
|
1613
|
+
/* @__PURE__ */ jsx21("span", { className: "sc-table__sort-label", children }),
|
|
1614
|
+
/* @__PURE__ */ jsx21("span", { className: "sc-table__sort-icon", "aria-hidden": "true", children: sortDirection === "descending" ? /* @__PURE__ */ jsx21(ArrowDownIcon, { size: "xs" }) : /* @__PURE__ */ jsx21(ArrowUpIcon, { size: "xs" }) })
|
|
1615
|
+
]
|
|
1616
|
+
}
|
|
1617
|
+
) : children
|
|
1618
|
+
}
|
|
1619
|
+
);
|
|
1620
|
+
}
|
|
1621
|
+
function Cell({
|
|
1622
|
+
align,
|
|
1623
|
+
numeric = false,
|
|
1624
|
+
nowrap = false,
|
|
1625
|
+
truncate = false,
|
|
1626
|
+
width,
|
|
1627
|
+
className,
|
|
1628
|
+
style,
|
|
1629
|
+
...rest
|
|
1630
|
+
}) {
|
|
1631
|
+
return /* @__PURE__ */ jsx21(
|
|
1632
|
+
"td",
|
|
1633
|
+
{
|
|
1634
|
+
className: cx("sc-table__cell", className),
|
|
1635
|
+
"data-align": align ?? (numeric ? "end" : void 0),
|
|
1636
|
+
"data-numeric": numeric || void 0,
|
|
1637
|
+
"data-nowrap": nowrap || void 0,
|
|
1638
|
+
"data-truncate": truncate || void 0,
|
|
1639
|
+
style: width ? { ...style, inlineSize: width } : style,
|
|
1640
|
+
...rest
|
|
1641
|
+
}
|
|
1642
|
+
);
|
|
1643
|
+
}
|
|
1644
|
+
var Table = { Root: Root5, Caption, Head, Body: Body2, Foot, Row, Header, Cell, SelectionHeader, SelectionCell };
|
|
1645
|
+
|
|
1646
|
+
// src/components/Table/useRowSelection.ts
|
|
1647
|
+
import { useMemo, useReducer } from "react";
|
|
1648
|
+
|
|
1649
|
+
// src/components/Table/rowSelection.ts
|
|
1650
|
+
function initRowSelection(ids) {
|
|
1651
|
+
return { ids, selected: /* @__PURE__ */ new Set(), anchor: null };
|
|
1652
|
+
}
|
|
1653
|
+
function sameIds(a, b) {
|
|
1654
|
+
if (a === b) return true;
|
|
1655
|
+
if (a.length !== b.length) return false;
|
|
1656
|
+
for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
|
|
1657
|
+
return true;
|
|
1658
|
+
}
|
|
1659
|
+
function toggle(state, id) {
|
|
1660
|
+
if (!state.ids.includes(id)) return state;
|
|
1661
|
+
const selected = new Set(state.selected);
|
|
1662
|
+
if (selected.has(id)) selected.delete(id);
|
|
1663
|
+
else selected.add(id);
|
|
1664
|
+
return { ...state, selected, anchor: id };
|
|
1665
|
+
}
|
|
1666
|
+
function toggleRange(state, id) {
|
|
1667
|
+
const to = state.ids.indexOf(id);
|
|
1668
|
+
if (to < 0) return state;
|
|
1669
|
+
const from = state.anchor === null ? -1 : state.ids.indexOf(state.anchor);
|
|
1670
|
+
if (from < 0 || from === to) return toggle(state, id);
|
|
1671
|
+
const on = !state.selected.has(id);
|
|
1672
|
+
const selected = new Set(state.selected);
|
|
1673
|
+
const [start, end] = from < to ? [from, to] : [to, from];
|
|
1674
|
+
for (let i = start; i <= end; i += 1) {
|
|
1675
|
+
const rowId = state.ids[i];
|
|
1676
|
+
if (on) selected.add(rowId);
|
|
1677
|
+
else selected.delete(rowId);
|
|
1678
|
+
}
|
|
1679
|
+
return { ...state, selected, anchor: id };
|
|
1680
|
+
}
|
|
1681
|
+
function sync(state, ids) {
|
|
1682
|
+
if (sameIds(state.ids, ids)) return state;
|
|
1683
|
+
const present = new Set(ids);
|
|
1684
|
+
let selected = state.selected;
|
|
1685
|
+
for (const id of state.selected) {
|
|
1686
|
+
if (present.has(id)) continue;
|
|
1687
|
+
selected = new Set([...state.selected].filter((x) => present.has(x)));
|
|
1688
|
+
break;
|
|
1689
|
+
}
|
|
1690
|
+
const anchor = state.anchor !== null && present.has(state.anchor) ? state.anchor : null;
|
|
1691
|
+
return { ids, selected, anchor };
|
|
1692
|
+
}
|
|
1693
|
+
function rowSelectionReducer(state, event) {
|
|
1694
|
+
switch (event.type) {
|
|
1695
|
+
case "selection.sync":
|
|
1696
|
+
return sync(state, event.ids);
|
|
1697
|
+
case "selection.toggle":
|
|
1698
|
+
return toggle(state, event.id);
|
|
1699
|
+
case "selection.toggleRange":
|
|
1700
|
+
return toggleRange(state, event.id);
|
|
1701
|
+
case "selection.selectAll":
|
|
1702
|
+
return state.selected.size === state.ids.length ? state : { ...state, selected: new Set(state.ids) };
|
|
1703
|
+
case "selection.clear":
|
|
1704
|
+
return state.selected.size === 0 && state.anchor === null ? state : { ...state, selected: /* @__PURE__ */ new Set(), anchor: null };
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
function headerState(state) {
|
|
1708
|
+
if (state.selected.size === 0) return "none";
|
|
1709
|
+
return state.selected.size === state.ids.length ? "all" : "some";
|
|
1710
|
+
}
|
|
1711
|
+
function selectedIds(state) {
|
|
1712
|
+
return state.ids.filter((id) => state.selected.has(id));
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// src/components/Table/useRowSelection.ts
|
|
1716
|
+
function useRowSelection(ids) {
|
|
1717
|
+
const [stored, dispatch] = useReducer(rowSelectionReducer, ids, initRowSelection);
|
|
1718
|
+
const state = sameIds(stored.ids, ids) ? stored : rowSelectionReducer(stored, { type: "selection.sync", ids });
|
|
1719
|
+
if (state !== stored) dispatch({ type: "selection.sync", ids });
|
|
1720
|
+
const actions = useMemo(
|
|
1721
|
+
() => ({
|
|
1722
|
+
toggle: (id) => dispatch({ type: "selection.toggle", id }),
|
|
1723
|
+
toggleRange: (id) => dispatch({ type: "selection.toggleRange", id }),
|
|
1724
|
+
selectAll: () => dispatch({ type: "selection.selectAll" }),
|
|
1725
|
+
clear: () => dispatch({ type: "selection.clear" })
|
|
1726
|
+
}),
|
|
1727
|
+
[]
|
|
1728
|
+
);
|
|
1729
|
+
return useMemo(
|
|
1730
|
+
() => ({
|
|
1731
|
+
ids: state.ids,
|
|
1732
|
+
selected: state.selected,
|
|
1733
|
+
selectedIds: selectedIds(state),
|
|
1734
|
+
count: state.selected.size,
|
|
1735
|
+
anchor: state.anchor,
|
|
1736
|
+
headerState: headerState(state),
|
|
1737
|
+
isSelected: (id) => state.selected.has(id),
|
|
1738
|
+
...actions
|
|
1739
|
+
}),
|
|
1740
|
+
[state, actions]
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
// src/components/SelectionBar/SelectionBar.tsx
|
|
1745
|
+
import { useEffect, useLayoutEffect, useRef, useState as useState3 } from "react";
|
|
1746
|
+
import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1747
|
+
var defaultCountLabel = (count) => `${count} selected`;
|
|
1748
|
+
var LEAVE_MS = 200;
|
|
1749
|
+
function SelectionBar({
|
|
1750
|
+
count,
|
|
1751
|
+
onClear,
|
|
1752
|
+
children,
|
|
1753
|
+
"aria-label": ariaLabel = "Bulk actions",
|
|
1754
|
+
countLabel = defaultCountLabel,
|
|
1755
|
+
clearLabel = "Clear",
|
|
1756
|
+
clearedMessage = "Selection cleared",
|
|
1757
|
+
className
|
|
1758
|
+
}) {
|
|
1759
|
+
const open = count > 0;
|
|
1760
|
+
const [hadSelection, setHadSelection] = useState3(open);
|
|
1761
|
+
if (open && !hadSelection) setHadSelection(true);
|
|
1762
|
+
const message = open ? countLabel(count) : hadSelection ? clearedMessage : "";
|
|
1763
|
+
const [rendered, setRendered] = useState3(open);
|
|
1764
|
+
const [shownCount, setShownCount] = useState3(count);
|
|
1765
|
+
if (open && !rendered) setRendered(true);
|
|
1766
|
+
if (open && shownCount !== count) setShownCount(count);
|
|
1767
|
+
useEffect(() => {
|
|
1768
|
+
if (open || !rendered) return;
|
|
1769
|
+
const timer = setTimeout(() => setRendered(false), LEAVE_MS);
|
|
1770
|
+
return () => clearTimeout(timer);
|
|
1771
|
+
}, [open, rendered]);
|
|
1772
|
+
const barRef = useRef(null);
|
|
1773
|
+
const returnTo = useRef(null);
|
|
1774
|
+
useLayoutEffect(() => {
|
|
1775
|
+
const bar = barRef.current;
|
|
1776
|
+
if (open || !bar?.contains(bar.ownerDocument.activeElement)) return;
|
|
1777
|
+
if (returnTo.current?.isConnected) returnTo.current.focus();
|
|
1778
|
+
}, [open]);
|
|
1779
|
+
const [height, setHeight] = useState3(0);
|
|
1780
|
+
useEffect(() => {
|
|
1781
|
+
const bar = barRef.current;
|
|
1782
|
+
if (!rendered || !bar || typeof ResizeObserver === "undefined") return;
|
|
1783
|
+
const observer = new ResizeObserver(([entry]) => setHeight(entry.borderBoxSize[0]?.blockSize ?? 0));
|
|
1784
|
+
observer.observe(bar);
|
|
1785
|
+
return () => observer.disconnect();
|
|
1786
|
+
}, [rendered]);
|
|
1787
|
+
return /* @__PURE__ */ jsxs19(Fragment5, { children: [
|
|
1788
|
+
/* @__PURE__ */ jsx22("span", { role: "status", className: "sc-visually-hidden", children: message }),
|
|
1789
|
+
rendered ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
|
|
1790
|
+
open ? /* @__PURE__ */ jsx22(
|
|
1791
|
+
"div",
|
|
1792
|
+
{
|
|
1793
|
+
className: "sc-selection-bar__spacer",
|
|
1794
|
+
style: { "--sc-selection-bar-height": `${height}px` },
|
|
1795
|
+
"aria-hidden": "true"
|
|
1796
|
+
}
|
|
1797
|
+
) : null,
|
|
1798
|
+
/* @__PURE__ */ jsx22(
|
|
1799
|
+
"div",
|
|
1800
|
+
{
|
|
1801
|
+
ref: barRef,
|
|
1802
|
+
className: cx("sc-selection-bar", className),
|
|
1803
|
+
"data-open": open || void 0,
|
|
1804
|
+
onFocus: (event) => {
|
|
1805
|
+
const from = event.relatedTarget;
|
|
1806
|
+
if (from instanceof HTMLElement && !event.currentTarget.contains(from)) returnTo.current = from;
|
|
1807
|
+
},
|
|
1808
|
+
children: /* @__PURE__ */ jsxs19(Toolbar.Root, { "aria-label": ariaLabel, className: "sc-selection-bar__toolbar", children: [
|
|
1809
|
+
/* @__PURE__ */ jsx22("span", { className: "sc-selection-bar__count", children: countLabel(shownCount) }),
|
|
1810
|
+
/* @__PURE__ */ jsx22(Toolbar.Separator, {}),
|
|
1811
|
+
children,
|
|
1812
|
+
/* @__PURE__ */ jsx22(Toolbar.Spacer, {}),
|
|
1813
|
+
/* @__PURE__ */ jsx22(Toolbar.Button, { render: /* @__PURE__ */ jsx22(Button, { variant: "ghost", size: "sm" }), onClick: onClear, children: clearLabel })
|
|
1814
|
+
] })
|
|
1815
|
+
}
|
|
1816
|
+
)
|
|
1817
|
+
] }) : null
|
|
1818
|
+
] });
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
// src/components/Toast/Toast.tsx
|
|
1822
|
+
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
1823
|
+
import { useMemo as useMemo2 } from "react";
|
|
1824
|
+
import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1825
|
+
function Provider2({ children, timeout = 6e3, limit = 3 }) {
|
|
1826
|
+
return /* @__PURE__ */ jsxs20(BaseToast.Provider, { timeout, limit, children: [
|
|
1827
|
+
children,
|
|
1828
|
+
/* @__PURE__ */ jsx23(BaseToast.Portal, { children: /* @__PURE__ */ jsx23(Viewport, {}) })
|
|
1829
|
+
] });
|
|
1830
|
+
}
|
|
1831
|
+
function Viewport() {
|
|
1832
|
+
const { toasts, close } = BaseToast.useToastManager();
|
|
1833
|
+
return /* @__PURE__ */ jsx23(BaseToast.Viewport, { className: "sc-toast-viewport", children: toasts.map((toast) => /* @__PURE__ */ jsxs20(BaseToast.Root, { toast, className: "sc-toast", "data-tone": toast.type ?? "neutral", children: [
|
|
1834
|
+
/* @__PURE__ */ jsxs20(BaseToast.Content, { className: "sc-toast__content", children: [
|
|
1835
|
+
/* @__PURE__ */ jsx23(BaseToast.Title, { className: "sc-toast__title" }),
|
|
1836
|
+
toast.description != null ? /* @__PURE__ */ jsx23(BaseToast.Description, { className: "sc-toast__description" }) : null
|
|
1837
|
+
] }),
|
|
1838
|
+
toast.actionProps ? /* @__PURE__ */ jsx23(
|
|
1839
|
+
BaseToast.Action,
|
|
1840
|
+
{
|
|
1841
|
+
className: "sc-toast__action",
|
|
1842
|
+
render: /* @__PURE__ */ jsx23(Button, { variant: "secondary", size: "sm" })
|
|
1843
|
+
}
|
|
1844
|
+
) : null,
|
|
1845
|
+
/* @__PURE__ */ jsx23(IconButton, { label: "Dismiss", size: "sm", className: "sc-toast__close", onClick: () => close(toast.id), children: /* @__PURE__ */ jsx23(XIcon, {}) })
|
|
1846
|
+
] }, toast.id)) });
|
|
1847
|
+
}
|
|
1848
|
+
function useToast() {
|
|
1849
|
+
const manager = BaseToast.useToastManager();
|
|
1850
|
+
return useMemo2(
|
|
1851
|
+
() => ({
|
|
1852
|
+
add: ({ title, description, tone = "neutral", action, timeout, priority }) => {
|
|
1853
|
+
let id = "";
|
|
1854
|
+
id = manager.add({
|
|
1855
|
+
title,
|
|
1856
|
+
description,
|
|
1857
|
+
type: tone,
|
|
1858
|
+
...timeout !== void 0 ? { timeout } : {},
|
|
1859
|
+
...priority ? { priority } : {},
|
|
1860
|
+
...action ? {
|
|
1861
|
+
actionProps: {
|
|
1862
|
+
children: action.label,
|
|
1863
|
+
onClick: () => {
|
|
1864
|
+
action.onClick();
|
|
1865
|
+
manager.close(id);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
} : {}
|
|
1869
|
+
});
|
|
1870
|
+
return id;
|
|
1871
|
+
},
|
|
1872
|
+
close: manager.close
|
|
1873
|
+
}),
|
|
1874
|
+
[manager]
|
|
1875
|
+
);
|
|
1876
|
+
}
|
|
1877
|
+
var Toast = { Provider: Provider2 };
|
|
1878
|
+
|
|
1879
|
+
// src/components/Stat/Stat.tsx
|
|
1880
|
+
import { createElement as createElement5 } from "react";
|
|
1881
|
+
import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1882
|
+
var trendIcons = {
|
|
1883
|
+
up: /* @__PURE__ */ jsx24(ArrowUpIcon, { size: "xs" }),
|
|
1884
|
+
down: /* @__PURE__ */ jsx24(ArrowDownIcon, { size: "xs" }),
|
|
1885
|
+
flat: /* @__PURE__ */ jsx24(ArrowRightIcon, { size: "xs" })
|
|
1886
|
+
};
|
|
1887
|
+
function Stat({
|
|
1888
|
+
label,
|
|
1889
|
+
value,
|
|
1890
|
+
delta,
|
|
1891
|
+
deltaTone = "neutral",
|
|
1892
|
+
trend,
|
|
1893
|
+
hint,
|
|
1894
|
+
icon,
|
|
1895
|
+
variant = "outlined",
|
|
1896
|
+
size = "md",
|
|
1897
|
+
as = "div",
|
|
1898
|
+
className,
|
|
1899
|
+
...rest
|
|
1900
|
+
}) {
|
|
1901
|
+
return createElement5(
|
|
1902
|
+
as,
|
|
1903
|
+
{
|
|
1904
|
+
className: cx("sc-stat", className),
|
|
1905
|
+
"data-variant": variant,
|
|
1906
|
+
"data-size": size,
|
|
1907
|
+
...rest
|
|
1908
|
+
},
|
|
1909
|
+
/* @__PURE__ */ jsxs21(Fragment6, { children: [
|
|
1910
|
+
/* @__PURE__ */ jsx24("div", { className: "sc-stat__label", children: label }),
|
|
1911
|
+
icon ? /* @__PURE__ */ jsx24("span", { className: "sc-stat__icon", "aria-hidden": "true", children: icon }) : null,
|
|
1912
|
+
/* @__PURE__ */ jsx24("div", { className: "sc-stat__value", children: value }),
|
|
1913
|
+
delta != null ? /* @__PURE__ */ jsxs21("div", { className: "sc-stat__delta", "data-tone": deltaTone, children: [
|
|
1914
|
+
trend ? /* @__PURE__ */ jsx24("span", { className: "sc-stat__trend", "aria-hidden": "true", children: trendIcons[trend] }) : null,
|
|
1915
|
+
trend ? /* @__PURE__ */ jsxs21("span", { className: "sc-visually-hidden", children: [
|
|
1916
|
+
trend === "flat" ? "unchanged" : trend,
|
|
1917
|
+
" "
|
|
1918
|
+
] }) : null,
|
|
1919
|
+
delta
|
|
1920
|
+
] }) : null,
|
|
1921
|
+
hint != null ? /* @__PURE__ */ jsx24("div", { className: "sc-stat__hint", children: hint }) : null
|
|
1922
|
+
] })
|
|
1923
|
+
);
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
// src/components/Chip/Chip.tsx
|
|
1927
|
+
import { Fragment as Fragment7, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1928
|
+
function Chip({
|
|
1929
|
+
children,
|
|
1930
|
+
icon,
|
|
1931
|
+
tone = "neutral",
|
|
1932
|
+
size = "md",
|
|
1933
|
+
selected = false,
|
|
1934
|
+
onClick,
|
|
1935
|
+
onRemove,
|
|
1936
|
+
removeLabel,
|
|
1937
|
+
disabled = false,
|
|
1938
|
+
className,
|
|
1939
|
+
...rest
|
|
1940
|
+
}) {
|
|
1941
|
+
const interactive = onClick !== void 0;
|
|
1942
|
+
const removeName = removeLabel ?? (typeof children === "string" ? `Remove ${children}` : "Remove");
|
|
1943
|
+
const handleRemoveKey = (event) => {
|
|
1944
|
+
if (onRemove && !disabled && (event.key === "Backspace" || event.key === "Delete")) {
|
|
1945
|
+
event.preventDefault();
|
|
1946
|
+
onRemove();
|
|
1947
|
+
}
|
|
1948
|
+
};
|
|
1949
|
+
const shared = {
|
|
1950
|
+
className: cx("sc-chip", className),
|
|
1951
|
+
"data-tone": tone,
|
|
1952
|
+
"data-size": size,
|
|
1953
|
+
"data-selected": selected || void 0,
|
|
1954
|
+
"data-removable": onRemove ? "" : void 0,
|
|
1955
|
+
"data-disabled": disabled || void 0
|
|
1956
|
+
};
|
|
1957
|
+
const body = /* @__PURE__ */ jsxs22(Fragment7, { children: [
|
|
1958
|
+
icon ? /* @__PURE__ */ jsx25("span", { className: "sc-chip__icon", "aria-hidden": "true", children: icon }) : null,
|
|
1959
|
+
/* @__PURE__ */ jsx25("span", { className: "sc-chip__label", children })
|
|
1960
|
+
] });
|
|
1961
|
+
const remove = onRemove ? /* @__PURE__ */ jsx25(
|
|
1962
|
+
"button",
|
|
1963
|
+
{
|
|
1964
|
+
type: "button",
|
|
1965
|
+
className: "sc-chip__remove",
|
|
1966
|
+
"aria-label": removeName,
|
|
1967
|
+
disabled,
|
|
1968
|
+
onClick: (event) => {
|
|
1969
|
+
event.stopPropagation();
|
|
1970
|
+
onRemove();
|
|
1971
|
+
},
|
|
1972
|
+
onKeyDown: handleRemoveKey,
|
|
1973
|
+
children: /* @__PURE__ */ jsx25(XIcon, { size: "xs" })
|
|
1974
|
+
}
|
|
1975
|
+
) : null;
|
|
1976
|
+
if (interactive) {
|
|
1977
|
+
return /* @__PURE__ */ jsxs22("span", { ...shared, ...rest, children: [
|
|
1978
|
+
/* @__PURE__ */ jsx25(
|
|
1979
|
+
"button",
|
|
1980
|
+
{
|
|
1981
|
+
type: "button",
|
|
1982
|
+
className: "sc-chip__action",
|
|
1983
|
+
"aria-pressed": selected,
|
|
1984
|
+
disabled,
|
|
1985
|
+
onClick,
|
|
1986
|
+
onKeyDown: handleRemoveKey,
|
|
1987
|
+
children: body
|
|
1988
|
+
}
|
|
1989
|
+
),
|
|
1990
|
+
remove
|
|
1991
|
+
] });
|
|
1992
|
+
}
|
|
1993
|
+
return /* @__PURE__ */ jsxs22("span", { ...shared, ...rest, children: [
|
|
1994
|
+
body,
|
|
1995
|
+
remove
|
|
1996
|
+
] });
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
// src/components/Disclosure/Disclosure.tsx
|
|
2000
|
+
import {
|
|
2001
|
+
useEffect as useEffect2,
|
|
2002
|
+
useRef as useRef2,
|
|
2003
|
+
useState as useState4
|
|
2004
|
+
} from "react";
|
|
2005
|
+
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2006
|
+
function Disclosure({
|
|
2007
|
+
summary,
|
|
2008
|
+
summaryOpen,
|
|
2009
|
+
open,
|
|
2010
|
+
defaultOpen = false,
|
|
2011
|
+
onOpenChange,
|
|
2012
|
+
previewLines,
|
|
2013
|
+
summaryPosition,
|
|
2014
|
+
className,
|
|
2015
|
+
style,
|
|
2016
|
+
children,
|
|
2017
|
+
ref,
|
|
2018
|
+
...rest
|
|
2019
|
+
}) {
|
|
2020
|
+
const controlled = open !== void 0;
|
|
2021
|
+
const [internal, setInternal] = useState4(defaultOpen);
|
|
2022
|
+
const isOpen = controlled ? open : internal;
|
|
2023
|
+
const inner = useRef2(null);
|
|
2024
|
+
useEffect2(() => {
|
|
2025
|
+
if (controlled && inner.current && inner.current.open !== open) inner.current.open = open;
|
|
2026
|
+
});
|
|
2027
|
+
const onToggle = (event) => {
|
|
2028
|
+
const next = event.currentTarget.open;
|
|
2029
|
+
if (next === isOpen) return;
|
|
2030
|
+
if (!controlled) setInternal(next);
|
|
2031
|
+
onOpenChange?.(next);
|
|
2032
|
+
};
|
|
2033
|
+
const position = summaryPosition ?? (previewLines ? "end" : "start");
|
|
2034
|
+
return /* @__PURE__ */ jsxs23(
|
|
2035
|
+
"details",
|
|
2036
|
+
{
|
|
2037
|
+
ref: (node) => {
|
|
2038
|
+
inner.current = node;
|
|
2039
|
+
if (typeof ref === "function") ref(node);
|
|
2040
|
+
else if (ref) ref.current = node;
|
|
2041
|
+
},
|
|
2042
|
+
className: cx("sc-disclosure", className),
|
|
2043
|
+
open: isOpen,
|
|
2044
|
+
onToggle,
|
|
2045
|
+
"data-summary-position": position,
|
|
2046
|
+
"data-preview": previewLines ? "" : void 0,
|
|
2047
|
+
style: previewLines ? { ...style, "--_lines": previewLines } : style,
|
|
2048
|
+
...rest,
|
|
2049
|
+
children: [
|
|
2050
|
+
/* @__PURE__ */ jsxs23("summary", { className: "sc-disclosure__summary", children: [
|
|
2051
|
+
/* @__PURE__ */ jsx26(ChevronDownIcon, { className: "sc-disclosure__chevron" }),
|
|
2052
|
+
/* @__PURE__ */ jsx26("span", { className: "sc-disclosure__summary-text", children: isOpen && summaryOpen != null ? summaryOpen : summary })
|
|
2053
|
+
] }),
|
|
2054
|
+
/* @__PURE__ */ jsx26("div", { className: "sc-disclosure__content", children })
|
|
2055
|
+
]
|
|
2056
|
+
}
|
|
2057
|
+
);
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
// src/components/EmptyState/EmptyState.tsx
|
|
2061
|
+
import { createElement as createElement6 } from "react";
|
|
2062
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2063
|
+
function EmptyState({
|
|
2064
|
+
title,
|
|
2065
|
+
description,
|
|
2066
|
+
icon,
|
|
2067
|
+
children,
|
|
2068
|
+
size = "md",
|
|
2069
|
+
as = "div",
|
|
2070
|
+
className,
|
|
2071
|
+
...rest
|
|
2072
|
+
}) {
|
|
2073
|
+
return createElement6(
|
|
2074
|
+
as,
|
|
2075
|
+
{ className: cx("sc-empty-state", className), "data-size": size, ...rest },
|
|
2076
|
+
icon ? /* @__PURE__ */ jsx27("span", { className: "sc-empty-state__icon", "aria-hidden": "true", children: icon }) : null,
|
|
2077
|
+
/* @__PURE__ */ jsx27("p", { className: "sc-empty-state__title", children: title }),
|
|
2078
|
+
description != null ? /* @__PURE__ */ jsx27("p", { className: "sc-empty-state__description", children: description }) : null,
|
|
2079
|
+
children != null ? /* @__PURE__ */ jsx27("div", { className: "sc-empty-state__actions", children }) : null
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
// src/components/Skeleton/Skeleton.tsx
|
|
2084
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
2085
|
+
function Skeleton({
|
|
2086
|
+
variant = "text",
|
|
2087
|
+
width,
|
|
2088
|
+
height,
|
|
2089
|
+
lines = 1,
|
|
2090
|
+
still = false,
|
|
2091
|
+
className,
|
|
2092
|
+
style,
|
|
2093
|
+
...rest
|
|
2094
|
+
}) {
|
|
2095
|
+
const size = {
|
|
2096
|
+
...style,
|
|
2097
|
+
...width !== void 0 ? { inlineSize: width } : {},
|
|
2098
|
+
...height !== void 0 ? { blockSize: height } : {}
|
|
2099
|
+
};
|
|
2100
|
+
if (variant === "text" && lines > 1) {
|
|
2101
|
+
return /* @__PURE__ */ jsx28("span", { className: cx("sc-skeleton-lines", className), "aria-hidden": "true", style, ...rest, children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx28(
|
|
2102
|
+
"span",
|
|
2103
|
+
{
|
|
2104
|
+
className: "sc-skeleton",
|
|
2105
|
+
"data-variant": "text",
|
|
2106
|
+
"data-still": still || void 0,
|
|
2107
|
+
"data-last": i === lines - 1 || void 0,
|
|
2108
|
+
style: width !== void 0 ? { inlineSize: width } : void 0
|
|
2109
|
+
},
|
|
2110
|
+
i
|
|
2111
|
+
)) });
|
|
2112
|
+
}
|
|
2113
|
+
return /* @__PURE__ */ jsx28(
|
|
2114
|
+
"span",
|
|
2115
|
+
{
|
|
2116
|
+
className: cx("sc-skeleton", className),
|
|
2117
|
+
"data-variant": variant,
|
|
2118
|
+
"data-still": still || void 0,
|
|
2119
|
+
"aria-hidden": "true",
|
|
2120
|
+
style: size,
|
|
2121
|
+
...rest
|
|
2122
|
+
}
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
// src/components/FileInput/FileInput.tsx
|
|
2127
|
+
import { useEffect as useEffect3, useId as useId3, useRef as useRef3, useState as useState5 } from "react";
|
|
2128
|
+
|
|
2129
|
+
// src/components/FileInput/accept.ts
|
|
2130
|
+
function parseAccept(accept) {
|
|
2131
|
+
if (accept == null) return [];
|
|
2132
|
+
const list = typeof accept === "string" ? accept.split(",") : accept;
|
|
2133
|
+
return list.map((entry) => entry.trim().toLowerCase()).filter(Boolean);
|
|
2134
|
+
}
|
|
2135
|
+
function matchesAccept(file, accept) {
|
|
2136
|
+
if (accept.length === 0) return true;
|
|
2137
|
+
const name = file.name.toLowerCase();
|
|
2138
|
+
const type = file.type.toLowerCase();
|
|
2139
|
+
return accept.some((entry) => {
|
|
2140
|
+
if (entry.startsWith(".")) return name.endsWith(entry);
|
|
2141
|
+
if (entry.endsWith("/*")) return type.startsWith(entry.slice(0, -1));
|
|
2142
|
+
return type === entry;
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
2145
|
+
var UNITS = { b: 1, kb: 1e3, mb: 1e6, gb: 1e9 };
|
|
2146
|
+
function parseSize(size) {
|
|
2147
|
+
if (size == null) return void 0;
|
|
2148
|
+
if (typeof size === "number") return size;
|
|
2149
|
+
const match = /^\s*(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)\s*$/i.exec(size);
|
|
2150
|
+
if (!match) throw new Error(`FileInput: maxFileSize "${size}" is not a size like "10MB".`);
|
|
2151
|
+
return Math.round(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
2152
|
+
}
|
|
2153
|
+
function formatSize(bytes) {
|
|
2154
|
+
const [unit, base] = bytes >= 1e9 ? ["GB", 1e9] : bytes >= 1e6 ? ["MB", 1e6] : bytes >= 1e3 ? ["KB", 1e3] : ["bytes", 1];
|
|
2155
|
+
const value = bytes / base;
|
|
2156
|
+
return `${Number.isInteger(value) ? value : Number(value.toFixed(1))} ${unit}`;
|
|
2157
|
+
}
|
|
2158
|
+
var MIME_NAMES = {
|
|
2159
|
+
"application/pdf": "PDF",
|
|
2160
|
+
"application/msword": "DOC",
|
|
2161
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "DOCX",
|
|
2162
|
+
"application/json": "JSON",
|
|
2163
|
+
"text/plain": "plain text",
|
|
2164
|
+
"text/markdown": "Markdown",
|
|
2165
|
+
"text/csv": "CSV",
|
|
2166
|
+
"image/png": "PNG",
|
|
2167
|
+
"image/jpeg": "JPEG"
|
|
2168
|
+
};
|
|
2169
|
+
function describeAccept(accept) {
|
|
2170
|
+
const names = accept.map((entry) => {
|
|
2171
|
+
if (entry.startsWith(".")) return entry.slice(1).toUpperCase();
|
|
2172
|
+
if (entry.endsWith("/*")) return `any ${entry.slice(0, -2)}`;
|
|
2173
|
+
return MIME_NAMES[entry] ?? entry.split("/").pop().toUpperCase();
|
|
2174
|
+
});
|
|
2175
|
+
const unique = [...new Set(names)];
|
|
2176
|
+
if (unique.length <= 1) return unique[0] ?? "";
|
|
2177
|
+
return `${unique.slice(0, -1).join(", ")} or ${unique.at(-1)}`;
|
|
2178
|
+
}
|
|
2179
|
+
function rejectionMessage(reason, detail) {
|
|
2180
|
+
switch (reason) {
|
|
2181
|
+
case "type":
|
|
2182
|
+
return `${detail.name} is not an accepted file type. Use ${detail.acceptLabel}.`;
|
|
2183
|
+
case "size":
|
|
2184
|
+
return `${detail.name} is ${formatSize(detail.size ?? 0)}, over the ${formatSize(detail.maxFileSize ?? 0)} limit.`;
|
|
2185
|
+
case "count":
|
|
2186
|
+
return detail.maxFiles === 1 ? "Choose one file." : `Up to ${detail.maxFiles} files. Remove one to add another.`;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
function escapeHtml(text) {
|
|
2190
|
+
return text.replace(
|
|
2191
|
+
/[&<>"']/g,
|
|
2192
|
+
(ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[ch]
|
|
2193
|
+
);
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
// src/components/FileInput/FileInput.tsx
|
|
2197
|
+
import { jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2198
|
+
var REMOVE_ICON = '<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg>';
|
|
2199
|
+
var sameFiles = (a, b) => a.length === b.length && a.every((file, i) => file === b[i]);
|
|
2200
|
+
function FileInput({
|
|
2201
|
+
label,
|
|
2202
|
+
hideLabel = false,
|
|
2203
|
+
description,
|
|
2204
|
+
error,
|
|
2205
|
+
invalid = false,
|
|
2206
|
+
required = false,
|
|
2207
|
+
disabled = false,
|
|
2208
|
+
name,
|
|
2209
|
+
size = "md",
|
|
2210
|
+
className,
|
|
2211
|
+
accept,
|
|
2212
|
+
acceptLabel,
|
|
2213
|
+
maxFileSize,
|
|
2214
|
+
multiple = false,
|
|
2215
|
+
maxFiles,
|
|
2216
|
+
files,
|
|
2217
|
+
defaultFiles,
|
|
2218
|
+
onFilesChange,
|
|
2219
|
+
idleLabel,
|
|
2220
|
+
browseLabel = "browse"
|
|
2221
|
+
}) {
|
|
2222
|
+
const id = useId3();
|
|
2223
|
+
const labelId = `${id}label`;
|
|
2224
|
+
const descriptionId = `${id}description`;
|
|
2225
|
+
const messagesId = `${id}messages`;
|
|
2226
|
+
const controlled = files !== void 0;
|
|
2227
|
+
const [uncontrolledFiles, setUncontrolledFiles] = useState5(defaultFiles ?? []);
|
|
2228
|
+
const current = controlled ? files : uncontrolledFiles;
|
|
2229
|
+
const [rejections, setRejections] = useState5([]);
|
|
2230
|
+
const [inputId, setInputId] = useState5();
|
|
2231
|
+
const [pondVersion, setPondVersion] = useState5(0);
|
|
2232
|
+
const hostRef = useRef3(null);
|
|
2233
|
+
const pondRef = useRef3(null);
|
|
2234
|
+
const moduleRef = useRef3(null);
|
|
2235
|
+
const patchRef = useRef3(() => {
|
|
2236
|
+
});
|
|
2237
|
+
const settledRef = useRef3(current);
|
|
2238
|
+
const targetRef = useRef3(null);
|
|
2239
|
+
const acceptList = parseAccept(accept);
|
|
2240
|
+
const acceptAttr = acceptList.join(",");
|
|
2241
|
+
const maxBytes = parseSize(maxFileSize);
|
|
2242
|
+
const messages = [...rejections, ...error != null ? [error] : []];
|
|
2243
|
+
const isInvalid = invalid || messages.length > 0;
|
|
2244
|
+
const idleText = idleLabel ?? (multiple ? "Drop files here or" : current.length > 0 ? "Drop another file to replace it, or" : "Drop a file here or");
|
|
2245
|
+
const live = {
|
|
2246
|
+
acceptList,
|
|
2247
|
+
acceptLabel: acceptLabel ?? describeAccept(acceptList),
|
|
2248
|
+
maxBytes,
|
|
2249
|
+
maxFiles: multiple ? maxFiles : 1,
|
|
2250
|
+
multiple,
|
|
2251
|
+
current,
|
|
2252
|
+
controlled,
|
|
2253
|
+
onFilesChange,
|
|
2254
|
+
labelId,
|
|
2255
|
+
describedBy: [description != null ? descriptionId : null, messages.length > 0 ? messagesId : null],
|
|
2256
|
+
isInvalid,
|
|
2257
|
+
acceptAttr
|
|
2258
|
+
};
|
|
2259
|
+
const liveRef = useRef3(live);
|
|
2260
|
+
useEffect3(() => {
|
|
2261
|
+
liveRef.current = live;
|
|
2262
|
+
});
|
|
2263
|
+
useEffect3(() => {
|
|
2264
|
+
let cancelled = false;
|
|
2265
|
+
let pond = null;
|
|
2266
|
+
let observer = null;
|
|
2267
|
+
const host = hostRef.current;
|
|
2268
|
+
if (!host) return void 0;
|
|
2269
|
+
const reject = (reason, file) => {
|
|
2270
|
+
const l = liveRef.current;
|
|
2271
|
+
const message = rejectionMessage(reason, {
|
|
2272
|
+
name: file?.name,
|
|
2273
|
+
size: file?.size,
|
|
2274
|
+
acceptLabel: l.acceptLabel,
|
|
2275
|
+
maxFileSize: l.maxBytes,
|
|
2276
|
+
maxFiles: l.maxFiles
|
|
2277
|
+
});
|
|
2278
|
+
setRejections((list) => list.includes(message) ? list : [...list, message]);
|
|
2279
|
+
if (file && targetRef.current) {
|
|
2280
|
+
targetRef.current = targetRef.current.filter((f) => f !== file);
|
|
2281
|
+
queueMicrotask(emit);
|
|
2282
|
+
}
|
|
2283
|
+
};
|
|
2284
|
+
const startAttempt = () => setRejections((list) => list.length ? [] : list);
|
|
2285
|
+
let removeIntent = false;
|
|
2286
|
+
const acceptedIds = /* @__PURE__ */ new Set();
|
|
2287
|
+
const noteRemove = (event) => {
|
|
2288
|
+
if (event.target?.closest?.(".filepond--action-remove-item")) removeIntent = true;
|
|
2289
|
+
};
|
|
2290
|
+
const emit = () => {
|
|
2291
|
+
const mod = moduleRef.current;
|
|
2292
|
+
if (!pond || !mod) return;
|
|
2293
|
+
const idle = pond.getFiles().filter((item) => item.status === mod.FileStatus.IDLE).map((item) => item.file);
|
|
2294
|
+
const accepted = liveRef.current.multiple ? idle : idle.slice(-1);
|
|
2295
|
+
const target = targetRef.current;
|
|
2296
|
+
if (target) {
|
|
2297
|
+
if (!sameFiles(accepted, target)) return;
|
|
2298
|
+
targetRef.current = null;
|
|
2299
|
+
settledRef.current = accepted;
|
|
2300
|
+
if (!sameFiles(accepted, liveRef.current.current)) {
|
|
2301
|
+
if (!liveRef.current.controlled) setUncontrolledFiles(accepted);
|
|
2302
|
+
liveRef.current.onFilesChange?.(accepted);
|
|
2303
|
+
}
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
if (sameFiles(accepted, settledRef.current)) return;
|
|
2307
|
+
settledRef.current = accepted;
|
|
2308
|
+
if (!liveRef.current.controlled) setUncontrolledFiles(accepted);
|
|
2309
|
+
liveRef.current.onFilesChange?.(accepted);
|
|
2310
|
+
};
|
|
2311
|
+
const patch = () => {
|
|
2312
|
+
if (!pond) return;
|
|
2313
|
+
const l = liveRef.current;
|
|
2314
|
+
const root = pond.element;
|
|
2315
|
+
if (!root) return;
|
|
2316
|
+
const set = (el, attr, value) => {
|
|
2317
|
+
if (!el || el.getAttribute(attr) === value) return;
|
|
2318
|
+
if (value == null) el.removeAttribute(attr);
|
|
2319
|
+
else el.setAttribute(attr, value);
|
|
2320
|
+
};
|
|
2321
|
+
const input = root.querySelector("input.filepond--browser");
|
|
2322
|
+
const dropLabel = root.querySelector(".filepond--drop-label label");
|
|
2323
|
+
set(input, "aria-labelledby", l.labelId);
|
|
2324
|
+
set(input, "aria-describedby", [dropLabel?.id, ...l.describedBy].filter(Boolean).join(" ") || null);
|
|
2325
|
+
set(input, "aria-invalid", l.isInvalid ? "true" : null);
|
|
2326
|
+
set(input, "accept", l.acceptAttr || null);
|
|
2327
|
+
set(input, "multiple", l.multiple ? "" : null);
|
|
2328
|
+
set(root.querySelector(".filepond--label-action"), "tabindex", null);
|
|
2329
|
+
for (const item of root.querySelectorAll(".filepond--item")) {
|
|
2330
|
+
const fileName = item.querySelector(".filepond--file-info-main")?.textContent?.trim();
|
|
2331
|
+
if (fileName)
|
|
2332
|
+
set(item.querySelector(".filepond--action-remove-item"), "aria-label", `Remove ${fileName}`);
|
|
2333
|
+
}
|
|
2334
|
+
setInputId(input?.id || void 0);
|
|
2335
|
+
};
|
|
2336
|
+
void import("filepond").then((mod) => {
|
|
2337
|
+
if (cancelled || !mod.supported()) return;
|
|
2338
|
+
moduleRef.current = mod;
|
|
2339
|
+
const options = {
|
|
2340
|
+
credits: false,
|
|
2341
|
+
allowPaste: false,
|
|
2342
|
+
allowReorder: false,
|
|
2343
|
+
allowProcess: false,
|
|
2344
|
+
allowRevert: false,
|
|
2345
|
+
instantUpload: false,
|
|
2346
|
+
dropOnPage: false,
|
|
2347
|
+
// Always multi: FilePond's own single mode replaces the current file *before* validating the new
|
|
2348
|
+
// one, so a rejected file would discard a good one. Replacement happens in `addfile` instead.
|
|
2349
|
+
allowMultiple: true,
|
|
2350
|
+
allowReplace: false,
|
|
2351
|
+
itemInsertLocation: "after",
|
|
2352
|
+
fileSizeBase: 1e3,
|
|
2353
|
+
iconRemove: REMOVE_ICON,
|
|
2354
|
+
labelButtonRemoveItem: "Remove",
|
|
2355
|
+
styleButtonRemoveItemPosition: "right",
|
|
2356
|
+
beforeAddFile: (item) => {
|
|
2357
|
+
const l = liveRef.current;
|
|
2358
|
+
const file = item.file;
|
|
2359
|
+
if (!matchesAccept(file, l.acceptList)) return reject("type", file), false;
|
|
2360
|
+
if (l.maxBytes != null && file.size > l.maxBytes) return reject("size", file), false;
|
|
2361
|
+
return true;
|
|
2362
|
+
}
|
|
2363
|
+
};
|
|
2364
|
+
pond = mod.create(options);
|
|
2365
|
+
const root = pond.element;
|
|
2366
|
+
if (!root) return;
|
|
2367
|
+
host.appendChild(root);
|
|
2368
|
+
pondRef.current = pond;
|
|
2369
|
+
patchRef.current = patch;
|
|
2370
|
+
pond.on("addfile", (error2, added) => {
|
|
2371
|
+
if (!error2) acceptedIds.add(added.id);
|
|
2372
|
+
if (!error2 && !liveRef.current.multiple) {
|
|
2373
|
+
for (const other of pond?.getFiles() ?? []) if (other.id !== added.id) pond?.removeFile(other.id);
|
|
2374
|
+
}
|
|
2375
|
+
emit();
|
|
2376
|
+
});
|
|
2377
|
+
pond.on("removefile", (_error, removed) => {
|
|
2378
|
+
const active = document.activeElement;
|
|
2379
|
+
const inRemovedRow = active?.closest(".filepond--item")?.id === `filepond--item-${removed.id}`;
|
|
2380
|
+
if (inRemovedRow || removeIntent && (active == null || active === document.body))
|
|
2381
|
+
root.querySelector("input.filepond--browser")?.focus();
|
|
2382
|
+
removeIntent = false;
|
|
2383
|
+
if (acceptedIds.delete(removed.id)) startAttempt();
|
|
2384
|
+
emit();
|
|
2385
|
+
});
|
|
2386
|
+
pond.on("updatefiles", emit);
|
|
2387
|
+
pond.on("warning", (warning) => {
|
|
2388
|
+
if (warning?.body === "Max files") reject("count");
|
|
2389
|
+
});
|
|
2390
|
+
observer = new MutationObserver(patch);
|
|
2391
|
+
observer.observe(root, {
|
|
2392
|
+
subtree: true,
|
|
2393
|
+
childList: true,
|
|
2394
|
+
attributes: true,
|
|
2395
|
+
attributeFilter: ["tabindex", "aria-labelledby", "aria-describedby", "accept", "id", "multiple"]
|
|
2396
|
+
});
|
|
2397
|
+
host.addEventListener("drop", startAttempt, true);
|
|
2398
|
+
host.addEventListener("change", startAttempt, true);
|
|
2399
|
+
host.addEventListener("click", noteRemove, true);
|
|
2400
|
+
settledRef.current = [];
|
|
2401
|
+
setPondVersion((v) => v + 1);
|
|
2402
|
+
});
|
|
2403
|
+
return () => {
|
|
2404
|
+
cancelled = true;
|
|
2405
|
+
host.removeEventListener("drop", startAttempt, true);
|
|
2406
|
+
host.removeEventListener("change", startAttempt, true);
|
|
2407
|
+
host.removeEventListener("click", noteRemove, true);
|
|
2408
|
+
observer?.disconnect();
|
|
2409
|
+
if (pond) {
|
|
2410
|
+
pond.element?.remove();
|
|
2411
|
+
pond.destroy();
|
|
2412
|
+
}
|
|
2413
|
+
pondRef.current = null;
|
|
2414
|
+
patchRef.current = () => {
|
|
2415
|
+
};
|
|
2416
|
+
};
|
|
2417
|
+
}, []);
|
|
2418
|
+
useEffect3(() => {
|
|
2419
|
+
const pond = pondRef.current;
|
|
2420
|
+
if (!pond) return;
|
|
2421
|
+
pond.setOptions({
|
|
2422
|
+
name: name ?? "",
|
|
2423
|
+
storeAsFile: name != null,
|
|
2424
|
+
disabled,
|
|
2425
|
+
required,
|
|
2426
|
+
maxFiles: multiple ? maxFiles ?? null : null,
|
|
2427
|
+
allowRemove: !disabled,
|
|
2428
|
+
labelIdle: `${escapeHtml(idleText)} <span class="filepond--label-action">${escapeHtml(browseLabel)}</span>`
|
|
2429
|
+
});
|
|
2430
|
+
patchRef.current();
|
|
2431
|
+
}, [
|
|
2432
|
+
pondVersion,
|
|
2433
|
+
name,
|
|
2434
|
+
disabled,
|
|
2435
|
+
required,
|
|
2436
|
+
multiple,
|
|
2437
|
+
maxFiles,
|
|
2438
|
+
idleText,
|
|
2439
|
+
browseLabel,
|
|
2440
|
+
labelId,
|
|
2441
|
+
acceptAttr,
|
|
2442
|
+
isInvalid,
|
|
2443
|
+
description,
|
|
2444
|
+
messages.length
|
|
2445
|
+
]);
|
|
2446
|
+
useEffect3(() => {
|
|
2447
|
+
const pond = pondRef.current;
|
|
2448
|
+
const mod = moduleRef.current;
|
|
2449
|
+
if (!pond || !mod) return;
|
|
2450
|
+
const items = pond.getFiles();
|
|
2451
|
+
const idle = items.filter((item) => item.status === mod.FileStatus.IDLE);
|
|
2452
|
+
const inPond = idle.map((item) => item.file);
|
|
2453
|
+
if (sameFiles(inPond, current)) {
|
|
2454
|
+
settledRef.current = current;
|
|
2455
|
+
return;
|
|
2456
|
+
}
|
|
2457
|
+
targetRef.current = current;
|
|
2458
|
+
for (const item of idle) if (!current.includes(item.file)) pond.removeFile(item.id);
|
|
2459
|
+
const toAdd = current.filter((file) => !inPond.includes(file));
|
|
2460
|
+
if (toAdd.length > 0) void pond.addFiles(toAdd);
|
|
2461
|
+
}, [current, pondVersion]);
|
|
2462
|
+
const ready = pondVersion > 0;
|
|
2463
|
+
return /* @__PURE__ */ jsxs24(
|
|
2464
|
+
"div",
|
|
2465
|
+
{
|
|
2466
|
+
className: cx("sc-field", "sc-file-input-field", className),
|
|
2467
|
+
"data-size": size,
|
|
2468
|
+
"data-disabled": disabled ? "" : void 0,
|
|
2469
|
+
"data-invalid": isInvalid ? "" : void 0,
|
|
2470
|
+
children: [
|
|
2471
|
+
/* @__PURE__ */ jsxs24(
|
|
2472
|
+
"label",
|
|
2473
|
+
{
|
|
2474
|
+
id: labelId,
|
|
2475
|
+
htmlFor: inputId,
|
|
2476
|
+
className: cx("sc-field__label", hideLabel && "sc-visually-hidden"),
|
|
2477
|
+
children: [
|
|
2478
|
+
label,
|
|
2479
|
+
required ? /* @__PURE__ */ jsx29("span", { className: "sc-field__required", "aria-hidden": "true", children: "*" }) : null
|
|
2480
|
+
]
|
|
2481
|
+
}
|
|
2482
|
+
),
|
|
2483
|
+
/* @__PURE__ */ jsxs24(
|
|
2484
|
+
"div",
|
|
2485
|
+
{
|
|
2486
|
+
className: "sc-file-input",
|
|
2487
|
+
"data-ready": ready ? "" : void 0,
|
|
2488
|
+
"data-disabled": disabled ? "" : void 0,
|
|
2489
|
+
"data-invalid": isInvalid ? "" : void 0,
|
|
2490
|
+
"data-multiple": multiple ? "" : void 0,
|
|
2491
|
+
children: [
|
|
2492
|
+
ready ? null : (
|
|
2493
|
+
// Server render and first paint: the same drop zone, inert until FilePond takes over.
|
|
2494
|
+
/* @__PURE__ */ jsxs24("div", { className: "sc-file-input__placeholder", "aria-hidden": "true", children: [
|
|
2495
|
+
idleText,
|
|
2496
|
+
" ",
|
|
2497
|
+
/* @__PURE__ */ jsx29("span", { className: "sc-file-input__browse", children: browseLabel })
|
|
2498
|
+
] })
|
|
2499
|
+
),
|
|
2500
|
+
/* @__PURE__ */ jsx29("div", { ref: hostRef, className: "sc-file-input__pond" })
|
|
2501
|
+
]
|
|
2502
|
+
}
|
|
2503
|
+
),
|
|
2504
|
+
description != null ? /* @__PURE__ */ jsx29("p", { id: descriptionId, className: "sc-field__description", children: description }) : null,
|
|
2505
|
+
/* @__PURE__ */ jsx29("div", { id: messagesId, className: "sc-file-input__messages", "aria-live": "polite", children: messages.map((message, i) => /* @__PURE__ */ jsx29("p", { className: "sc-field__error", children: message }, i)) })
|
|
2506
|
+
]
|
|
2507
|
+
}
|
|
2508
|
+
);
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
// src/components/PriorityNav/PriorityNav.tsx
|
|
2512
|
+
import {
|
|
2513
|
+
useEffect as useEffect4,
|
|
2514
|
+
useId as useId4,
|
|
2515
|
+
useLayoutEffect as useLayoutEffect2,
|
|
2516
|
+
useRef as useRef4,
|
|
2517
|
+
useState as useState6
|
|
2518
|
+
} from "react";
|
|
2519
|
+
|
|
2520
|
+
// src/components/PriorityNav/fit.ts
|
|
2521
|
+
var EPSILON = 0.5;
|
|
2522
|
+
function rowWidth(widths, gap) {
|
|
2523
|
+
let total = 0;
|
|
2524
|
+
for (const w of widths) total += w;
|
|
2525
|
+
return widths.length > 1 ? total + gap * (widths.length - 1) : total;
|
|
2526
|
+
}
|
|
2527
|
+
function fitCount({ widths, current, available, more, gap }) {
|
|
2528
|
+
const n = widths.length;
|
|
2529
|
+
const hasCurrent = current >= 0 && current < n;
|
|
2530
|
+
const others = hasCurrent ? n - 1 : n;
|
|
2531
|
+
if (rowWidth(widths, gap) <= available + EPSILON) return others;
|
|
2532
|
+
let used = more + (hasCurrent ? widths[current] + gap : 0);
|
|
2533
|
+
let count = 0;
|
|
2534
|
+
for (let i = 0; i < n; i++) {
|
|
2535
|
+
if (i === current) continue;
|
|
2536
|
+
const next = used + widths[i] + gap;
|
|
2537
|
+
if (next > available + EPSILON) break;
|
|
2538
|
+
used = next;
|
|
2539
|
+
count++;
|
|
2540
|
+
}
|
|
2541
|
+
return count;
|
|
2542
|
+
}
|
|
2543
|
+
function inlineFlags(length, current, count) {
|
|
2544
|
+
const flags = [];
|
|
2545
|
+
let seen = 0;
|
|
2546
|
+
for (let i = 0; i < length; i++) {
|
|
2547
|
+
if (i === current) flags.push(true);
|
|
2548
|
+
else flags.push(seen++ < count);
|
|
2549
|
+
}
|
|
2550
|
+
return flags;
|
|
2551
|
+
}
|
|
2552
|
+
function isOverflowing({ widths, gap, available, was, hysteresis }) {
|
|
2553
|
+
const total = rowWidth(widths, gap);
|
|
2554
|
+
return was ? total + Math.max(0, hysteresis) > available + EPSILON : total > available + EPSILON;
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
// src/components/PriorityNav/place.ts
|
|
2558
|
+
var clamp = (value, min, max) => Math.max(min, Math.min(value, max));
|
|
2559
|
+
function placePanel({ anchor, panel, viewport, gutter, offset, rtl = false }) {
|
|
2560
|
+
const endAligned = rtl ? anchor.left : anchor.right - panel.width;
|
|
2561
|
+
const startAligned = rtl ? anchor.right - panel.width : anchor.left;
|
|
2562
|
+
const fitsX = (x2) => x2 >= gutter && x2 + panel.width <= viewport.width - gutter;
|
|
2563
|
+
const x = fitsX(endAligned) ? endAligned : fitsX(startAligned) ? startAligned : endAligned;
|
|
2564
|
+
const left = clamp(x, gutter, Math.max(gutter, viewport.width - gutter - panel.width));
|
|
2565
|
+
const below = anchor.bottom + offset;
|
|
2566
|
+
const above = anchor.top - offset - panel.height;
|
|
2567
|
+
const fitsBelow = below + panel.height <= viewport.height - gutter;
|
|
2568
|
+
const top = fitsBelow || above < gutter ? below : above;
|
|
2569
|
+
return { left, top };
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
// src/components/PriorityNav/PriorityNav.tsx
|
|
2573
|
+
import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2574
|
+
var defaultCountLabel2 = (n) => n === 1 ? "1 link" : `${n} links`;
|
|
2575
|
+
var defaultLink = ({ children, ...props }) => /* @__PURE__ */ jsx30("a", { ...props, children });
|
|
2576
|
+
var keyOf = (item) => item.id ?? item.href;
|
|
2577
|
+
var supportsAnchor = () => typeof CSS !== "undefined" && typeof CSS.supports === "function" && CSS.supports("anchor-name: --a");
|
|
2578
|
+
var supportsPopover = (el) => typeof el.showPopover === "function";
|
|
2579
|
+
function signatureOf(items) {
|
|
2580
|
+
return items.map((item) => {
|
|
2581
|
+
const text = typeof item.label === "string" || typeof item.label === "number" ? item.label : "";
|
|
2582
|
+
return `${keyOf(item)}${text}`;
|
|
2583
|
+
}).join("");
|
|
2584
|
+
}
|
|
2585
|
+
function PriorityNav({
|
|
2586
|
+
items,
|
|
2587
|
+
moreLabel = "More",
|
|
2588
|
+
moreCountLabel = defaultCountLabel2,
|
|
2589
|
+
renderLink = defaultLink,
|
|
2590
|
+
onOverflowChange,
|
|
2591
|
+
overflowHysteresis = 0,
|
|
2592
|
+
className,
|
|
2593
|
+
style,
|
|
2594
|
+
...rest
|
|
2595
|
+
}) {
|
|
2596
|
+
const signature = signatureOf(items);
|
|
2597
|
+
const current = items.findIndex((item) => item.current);
|
|
2598
|
+
const [fit, setFit] = useState6({ signature: null, current: -1, count: 0, overflowing: false });
|
|
2599
|
+
const [open, setOpen] = useState6(false);
|
|
2600
|
+
const panelId = useId4();
|
|
2601
|
+
const listRef = useRef4(null);
|
|
2602
|
+
const moreRef = useRef4(null);
|
|
2603
|
+
const toggleRef = useRef4(null);
|
|
2604
|
+
const panelRef = useRef4(null);
|
|
2605
|
+
const measured = useRef4(null);
|
|
2606
|
+
const currentRef = useRef4(current);
|
|
2607
|
+
const fitRef = useRef4(fit);
|
|
2608
|
+
const hysteresisRef = useRef4(overflowHysteresis);
|
|
2609
|
+
const onOverflowRef = useRef4(onOverflowChange);
|
|
2610
|
+
const solve = (m, cur, was) => ({
|
|
2611
|
+
count: fitCount({ ...m, current: cur }),
|
|
2612
|
+
overflowing: isOverflowing({ ...m, was, hysteresis: hysteresisRef.current })
|
|
2613
|
+
});
|
|
2614
|
+
const measuring = fit.signature !== signature;
|
|
2615
|
+
useLayoutEffect2(() => {
|
|
2616
|
+
currentRef.current = current;
|
|
2617
|
+
fitRef.current = fit;
|
|
2618
|
+
hysteresisRef.current = overflowHysteresis;
|
|
2619
|
+
onOverflowRef.current = onOverflowChange;
|
|
2620
|
+
});
|
|
2621
|
+
useLayoutEffect2(() => {
|
|
2622
|
+
const list = listRef.current;
|
|
2623
|
+
const more = moreRef.current;
|
|
2624
|
+
if (!list || !more) return;
|
|
2625
|
+
if (measuring) {
|
|
2626
|
+
const widths = Array.from(
|
|
2627
|
+
list.querySelectorAll(":scope > .sc-priority-nav__item"),
|
|
2628
|
+
(el) => el.getBoundingClientRect().width
|
|
2629
|
+
);
|
|
2630
|
+
measured.current = {
|
|
2631
|
+
widths,
|
|
2632
|
+
more: more.getBoundingClientRect().width,
|
|
2633
|
+
gap: parseFloat(getComputedStyle(list).columnGap) || 0,
|
|
2634
|
+
available: list.clientWidth
|
|
2635
|
+
};
|
|
2636
|
+
} else if (fit.current === current) return;
|
|
2637
|
+
const m = measured.current;
|
|
2638
|
+
if (!m) return;
|
|
2639
|
+
setFit({ signature, current, ...solve(m, current, fit.overflowing) });
|
|
2640
|
+
}, [measuring, signature, current, fit]);
|
|
2641
|
+
useEffect4(() => {
|
|
2642
|
+
const list = listRef.current;
|
|
2643
|
+
const more = moreRef.current;
|
|
2644
|
+
if (!list || !more || typeof ResizeObserver === "undefined") return;
|
|
2645
|
+
const observer = new ResizeObserver((entries) => {
|
|
2646
|
+
const m = measured.current;
|
|
2647
|
+
if (!m) return;
|
|
2648
|
+
for (const entry of entries) {
|
|
2649
|
+
if (entry.target === list)
|
|
2650
|
+
m.available = entry.contentBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
|
|
2651
|
+
else {
|
|
2652
|
+
const width = entry.borderBoxSize?.[0]?.inlineSize ?? 0;
|
|
2653
|
+
if (width > 0) m.more = width;
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
const prev = fitRef.current;
|
|
2657
|
+
if (prev.signature === null) return;
|
|
2658
|
+
const next = solve(m, currentRef.current, prev.overflowing);
|
|
2659
|
+
if (prev.count !== next.count || prev.overflowing !== next.overflowing) setFit({ ...prev, ...next });
|
|
2660
|
+
});
|
|
2661
|
+
observer.observe(list);
|
|
2662
|
+
observer.observe(more);
|
|
2663
|
+
return () => observer.disconnect();
|
|
2664
|
+
}, []);
|
|
2665
|
+
const reported = useRef4(false);
|
|
2666
|
+
useEffect4(() => {
|
|
2667
|
+
if (reported.current === fit.overflowing) return;
|
|
2668
|
+
reported.current = fit.overflowing;
|
|
2669
|
+
onOverflowRef.current?.(fit.overflowing);
|
|
2670
|
+
}, [fit.overflowing]);
|
|
2671
|
+
useEffect4(() => {
|
|
2672
|
+
const fonts = typeof document === "undefined" ? void 0 : document.fonts;
|
|
2673
|
+
if (!fonts || fonts.status === "loaded") return;
|
|
2674
|
+
let live = true;
|
|
2675
|
+
void fonts.ready.then(() => {
|
|
2676
|
+
if (live) setFit((prev) => ({ ...prev, signature: null }));
|
|
2677
|
+
});
|
|
2678
|
+
return () => {
|
|
2679
|
+
live = false;
|
|
2680
|
+
};
|
|
2681
|
+
}, []);
|
|
2682
|
+
const flags = measuring ? null : inlineFlags(items.length, current, fit.count);
|
|
2683
|
+
const overflow = flags ? items.filter((_, i) => !flags[i]) : [];
|
|
2684
|
+
const expanded = open && overflow.length > 0;
|
|
2685
|
+
useLayoutEffect2(() => {
|
|
2686
|
+
const panel = panelRef.current;
|
|
2687
|
+
if (!panel || !supportsPopover(panel)) return;
|
|
2688
|
+
if (!panel.hasAttribute("popover")) panel.setAttribute("popover", "manual");
|
|
2689
|
+
const shown = panel.matches(":popover-open");
|
|
2690
|
+
if (expanded && !shown) panel.showPopover();
|
|
2691
|
+
else if (!expanded && shown) panel.hidePopover();
|
|
2692
|
+
}, [expanded]);
|
|
2693
|
+
useLayoutEffect2(() => {
|
|
2694
|
+
const panel = panelRef.current;
|
|
2695
|
+
const toggle2 = toggleRef.current;
|
|
2696
|
+
if (!expanded || !panel || !toggle2 || supportsAnchor()) return;
|
|
2697
|
+
const place = () => {
|
|
2698
|
+
const anchor = toggle2.getBoundingClientRect();
|
|
2699
|
+
const box = panel.getBoundingClientRect();
|
|
2700
|
+
const css = getComputedStyle(panel);
|
|
2701
|
+
const { left, top } = placePanel({
|
|
2702
|
+
anchor,
|
|
2703
|
+
panel: { width: box.width, height: box.height },
|
|
2704
|
+
viewport: { width: document.documentElement.clientWidth, height: window.innerHeight },
|
|
2705
|
+
gutter: parseFloat(css.getPropertyValue("--sc-spacing-md")) || 16,
|
|
2706
|
+
offset: parseFloat(css.getPropertyValue("--sc-spacing-2xs")) || 4,
|
|
2707
|
+
rtl: css.direction === "rtl"
|
|
2708
|
+
});
|
|
2709
|
+
panel.style.left = `${left}px`;
|
|
2710
|
+
panel.style.top = `${top}px`;
|
|
2711
|
+
};
|
|
2712
|
+
place();
|
|
2713
|
+
window.addEventListener("resize", place, { passive: true });
|
|
2714
|
+
window.addEventListener("scroll", place, { passive: true, capture: true });
|
|
2715
|
+
return () => {
|
|
2716
|
+
window.removeEventListener("resize", place);
|
|
2717
|
+
window.removeEventListener("scroll", place, { capture: true });
|
|
2718
|
+
panel.style.left = "";
|
|
2719
|
+
panel.style.top = "";
|
|
2720
|
+
};
|
|
2721
|
+
}, [expanded]);
|
|
2722
|
+
useEffect4(() => {
|
|
2723
|
+
if (!expanded) return;
|
|
2724
|
+
const onPointerDown = (event) => {
|
|
2725
|
+
if (!moreRef.current?.contains(event.target)) setOpen(false);
|
|
2726
|
+
};
|
|
2727
|
+
const onKeyDown = (event) => {
|
|
2728
|
+
if (event.key !== "Escape") return;
|
|
2729
|
+
const active = document.activeElement;
|
|
2730
|
+
setOpen(false);
|
|
2731
|
+
if (!active || active === document.body || moreRef.current?.contains(active))
|
|
2732
|
+
toggleRef.current?.focus();
|
|
2733
|
+
};
|
|
2734
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
2735
|
+
document.addEventListener("keydown", onKeyDown);
|
|
2736
|
+
return () => {
|
|
2737
|
+
document.removeEventListener("pointerdown", onPointerDown);
|
|
2738
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
2739
|
+
};
|
|
2740
|
+
}, [expanded]);
|
|
2741
|
+
const onBlur = (event) => {
|
|
2742
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
2743
|
+
};
|
|
2744
|
+
const link = (item, inPanel) => renderLink(
|
|
2745
|
+
{
|
|
2746
|
+
href: item.href,
|
|
2747
|
+
className: "sc-priority-nav__link",
|
|
2748
|
+
"aria-current": item.current ? "page" : void 0,
|
|
2749
|
+
onClick: inPanel ? () => setOpen(false) : void 0,
|
|
2750
|
+
children: /* @__PURE__ */ jsx30("span", { className: "sc-priority-nav__label", children: item.label })
|
|
2751
|
+
},
|
|
2752
|
+
item
|
|
2753
|
+
);
|
|
2754
|
+
return /* @__PURE__ */ jsx30(
|
|
2755
|
+
"nav",
|
|
2756
|
+
{
|
|
2757
|
+
className: cx("sc-priority-nav", className),
|
|
2758
|
+
"data-measuring": measuring || void 0,
|
|
2759
|
+
"data-overflowing": fit.overflowing || void 0,
|
|
2760
|
+
style: { ...style, "--_anchor": `--sc-priority-nav${panelId.replace(/[^\w-]/g, "")}` },
|
|
2761
|
+
...rest,
|
|
2762
|
+
children: /* @__PURE__ */ jsxs25("ul", { ref: listRef, className: "sc-priority-nav__list", children: [
|
|
2763
|
+
items.map(
|
|
2764
|
+
(item, i) => flags && !flags[i] ? null : /* @__PURE__ */ jsx30("li", { className: "sc-priority-nav__item", "data-current": item.current || void 0, children: link(item, false) }, keyOf(item))
|
|
2765
|
+
),
|
|
2766
|
+
/* @__PURE__ */ jsxs25(
|
|
2767
|
+
"li",
|
|
2768
|
+
{
|
|
2769
|
+
ref: moreRef,
|
|
2770
|
+
className: "sc-priority-nav__more",
|
|
2771
|
+
hidden: measuring || overflow.length === 0,
|
|
2772
|
+
onBlur,
|
|
2773
|
+
children: [
|
|
2774
|
+
/* @__PURE__ */ jsxs25(
|
|
2775
|
+
"button",
|
|
2776
|
+
{
|
|
2777
|
+
ref: toggleRef,
|
|
2778
|
+
type: "button",
|
|
2779
|
+
className: "sc-priority-nav__toggle",
|
|
2780
|
+
"aria-expanded": expanded,
|
|
2781
|
+
"aria-controls": panelId,
|
|
2782
|
+
onClick: () => setOpen((o) => !o),
|
|
2783
|
+
children: [
|
|
2784
|
+
/* @__PURE__ */ jsx30(MoreHorizontalIcon, { className: "sc-priority-nav__ellipsis" }),
|
|
2785
|
+
/* @__PURE__ */ jsx30("span", { className: "sc-priority-nav__toggle-label", children: moreLabel }),
|
|
2786
|
+
/* @__PURE__ */ jsxs25("span", { className: "sc-visually-hidden", children: [
|
|
2787
|
+
", ",
|
|
2788
|
+
moreCountLabel(overflow.length)
|
|
2789
|
+
] }),
|
|
2790
|
+
/* @__PURE__ */ jsx30(ChevronDownIcon, { size: "sm", className: "sc-priority-nav__chevron" })
|
|
2791
|
+
]
|
|
2792
|
+
}
|
|
2793
|
+
),
|
|
2794
|
+
/* @__PURE__ */ jsx30("ul", { ref: panelRef, id: panelId, className: "sc-priority-nav__panel", hidden: !expanded, children: overflow.map((item) => /* @__PURE__ */ jsx30("li", { children: link(item, true) }, keyOf(item))) })
|
|
2795
|
+
]
|
|
2796
|
+
}
|
|
2797
|
+
)
|
|
2798
|
+
] })
|
|
2799
|
+
}
|
|
2800
|
+
);
|
|
2801
|
+
}
|
|
2802
|
+
|
|
2803
|
+
// src/components/Popover/Popover.tsx
|
|
2804
|
+
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
2805
|
+
import { jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2806
|
+
function Root6({ open, defaultOpen, onOpenChange, modal = false, children }) {
|
|
2807
|
+
return /* @__PURE__ */ jsx31(
|
|
2808
|
+
BasePopover.Root,
|
|
2809
|
+
{
|
|
2810
|
+
open,
|
|
2811
|
+
defaultOpen,
|
|
2812
|
+
onOpenChange: onOpenChange ? (next) => onOpenChange(next) : void 0,
|
|
2813
|
+
modal,
|
|
2814
|
+
children
|
|
2815
|
+
}
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
function Trigger3({ render, className, children, ...rest }) {
|
|
2819
|
+
return /* @__PURE__ */ jsx31(
|
|
2820
|
+
BasePopover.Trigger,
|
|
2821
|
+
{
|
|
2822
|
+
render: render ?? /* @__PURE__ */ jsx31(Button, { variant: "secondary", className }),
|
|
2823
|
+
className: render ? className : void 0,
|
|
2824
|
+
...rest,
|
|
2825
|
+
children
|
|
2826
|
+
}
|
|
2827
|
+
);
|
|
2828
|
+
}
|
|
2829
|
+
function Content3({
|
|
2830
|
+
side = "bottom",
|
|
2831
|
+
align = "center",
|
|
2832
|
+
sideOffset,
|
|
2833
|
+
arrow = false,
|
|
2834
|
+
className,
|
|
2835
|
+
children,
|
|
2836
|
+
...rest
|
|
2837
|
+
}) {
|
|
2838
|
+
return /* @__PURE__ */ jsx31(BasePopover.Portal, { children: /* @__PURE__ */ jsx31(
|
|
2839
|
+
BasePopover.Positioner,
|
|
2840
|
+
{
|
|
2841
|
+
side,
|
|
2842
|
+
align,
|
|
2843
|
+
sideOffset: sideOffset ?? (arrow ? 8 : 4),
|
|
2844
|
+
className: "sc-popover__positioner",
|
|
2845
|
+
children: /* @__PURE__ */ jsxs26(BasePopover.Popup, { className: cx("sc-popover", className), ...rest, children: [
|
|
2846
|
+
arrow ? /* @__PURE__ */ jsx31(BasePopover.Arrow, { className: "sc-popover__arrow" }) : null,
|
|
2847
|
+
children
|
|
2848
|
+
] })
|
|
2849
|
+
}
|
|
2850
|
+
) });
|
|
2851
|
+
}
|
|
2852
|
+
function Title2({ className, ...rest }) {
|
|
2853
|
+
return /* @__PURE__ */ jsx31(BasePopover.Title, { className: cx("sc-popover__title", className), ...rest });
|
|
2854
|
+
}
|
|
2855
|
+
function Description2({ className, ...rest }) {
|
|
2856
|
+
return /* @__PURE__ */ jsx31(BasePopover.Description, { className: cx("sc-popover__description", className), ...rest });
|
|
2857
|
+
}
|
|
2858
|
+
function Close2({ className, children, render, ...rest }) {
|
|
2859
|
+
if (children === void 0 && render === void 0) {
|
|
2860
|
+
return /* @__PURE__ */ jsx31(BasePopover.Close, { className: cx("sc-popover__close", className), "aria-label": "Close", ...rest, children: /* @__PURE__ */ jsx31(XIcon, {}) });
|
|
2861
|
+
}
|
|
2862
|
+
return /* @__PURE__ */ jsx31(BasePopover.Close, { className, render, ...rest, children });
|
|
2863
|
+
}
|
|
2864
|
+
var Popover = { Root: Root6, Trigger: Trigger3, Content: Content3, Title: Title2, Description: Description2, Close: Close2 };
|
|
2865
|
+
|
|
2866
|
+
// src/components/BroomIcon/BroomIcon.tsx
|
|
2867
|
+
import { jsx as jsx32, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2868
|
+
function BroomIcon({ sweeping = false, size = "lg", title, className, ...rest }) {
|
|
2869
|
+
return /* @__PURE__ */ jsxs27(
|
|
2870
|
+
"svg",
|
|
2871
|
+
{
|
|
2872
|
+
className: cx("sc-icon", "sc-broom", className),
|
|
2873
|
+
"data-size": size,
|
|
2874
|
+
"data-sweeping": sweeping || void 0,
|
|
2875
|
+
viewBox: "0 0 24 24",
|
|
2876
|
+
fill: "none",
|
|
2877
|
+
focusable: "false",
|
|
2878
|
+
"aria-hidden": title ? void 0 : true,
|
|
2879
|
+
role: title ? "img" : void 0,
|
|
2880
|
+
"aria-label": title,
|
|
2881
|
+
...rest,
|
|
2882
|
+
children: [
|
|
2883
|
+
/* @__PURE__ */ jsxs27(
|
|
2884
|
+
"g",
|
|
2885
|
+
{
|
|
2886
|
+
className: "sc-broom__body",
|
|
2887
|
+
fill: "none",
|
|
2888
|
+
stroke: "currentColor",
|
|
2889
|
+
strokeLinecap: "round",
|
|
2890
|
+
strokeLinejoin: "round",
|
|
2891
|
+
children: [
|
|
2892
|
+
/* @__PURE__ */ jsx32("path", { d: "M16.1 10.48 L19.36 1.86 A0.87 0.87 0 0 1 20.98 2.47 L17.84 10.78" }),
|
|
2893
|
+
/* @__PURE__ */ jsx32("path", { d: "M13.33 12 C14.23 10.67 16.73 9.87 18.17 11 C19.07 12.67 18.93 18.33 18.4 21.4 C16.07 22.4 11.07 22.07 6.4 18.07 C9.07 16.67 11.8 15 13.33 12 Z" }),
|
|
2894
|
+
/* @__PURE__ */ jsx32("path", { className: "sc-broom__band", d: "M13.47 12.13 L18.4 13.5 L18.33 14.1 L13.27 12.77 Z" }),
|
|
2895
|
+
/* @__PURE__ */ jsx32("path", { d: "M12.87 13.73 L14.4 14.47 M16.2 15.27 L18.47 15.87" }),
|
|
2896
|
+
/* @__PURE__ */ jsx32("path", { d: "M12.8 16.87 C11.86 18.24 10.75 19.38 9.57 20.23 M15.6 17.4 C15.22 18.96 14.6 20.44 13.77 21.71" })
|
|
2897
|
+
]
|
|
2898
|
+
}
|
|
2899
|
+
),
|
|
2900
|
+
/* @__PURE__ */ jsxs27("g", { className: "sc-broom__dust", fill: "none", stroke: "currentColor", children: [
|
|
2901
|
+
/* @__PURE__ */ jsx32("circle", { cx: "4.77", cy: "13.53", r: "0.5" }),
|
|
2902
|
+
/* @__PURE__ */ jsx32("circle", { cx: "2.7", cy: "15.53", r: "0.87" }),
|
|
2903
|
+
/* @__PURE__ */ jsx32("circle", { cx: "4.1", cy: "18.27", r: "0.5" })
|
|
2904
|
+
] })
|
|
2905
|
+
]
|
|
2906
|
+
}
|
|
2907
|
+
);
|
|
2908
|
+
}
|
|
2909
|
+
|
|
1296
2910
|
// src/index.ts
|
|
1297
2911
|
var version = "0.1.1";
|
|
1298
2912
|
export {
|
|
1299
2913
|
ArchiveIcon,
|
|
2914
|
+
ArrowDownIcon,
|
|
1300
2915
|
ArrowLeftIcon,
|
|
1301
2916
|
ArrowRightIcon,
|
|
2917
|
+
ArrowUpIcon,
|
|
1302
2918
|
Badge,
|
|
1303
2919
|
Banner,
|
|
1304
2920
|
BellIcon,
|
|
1305
2921
|
BriefcaseIcon,
|
|
2922
|
+
BroomIcon,
|
|
1306
2923
|
Button,
|
|
1307
2924
|
CalendarIcon,
|
|
1308
2925
|
Card,
|
|
@@ -1312,16 +2929,20 @@ export {
|
|
|
1312
2929
|
ChevronLeftIcon,
|
|
1313
2930
|
ChevronRightIcon,
|
|
1314
2931
|
ChevronUpIcon,
|
|
2932
|
+
Chip,
|
|
1315
2933
|
CircleCheckIcon,
|
|
1316
2934
|
CircleXIcon,
|
|
1317
2935
|
ClockIcon,
|
|
1318
2936
|
CopyIcon,
|
|
1319
2937
|
Dialog,
|
|
2938
|
+
Disclosure,
|
|
1320
2939
|
DocumentIcon,
|
|
1321
2940
|
DownloadIcon,
|
|
1322
2941
|
EditIcon,
|
|
2942
|
+
EmptyState,
|
|
1323
2943
|
ExternalLinkIcon,
|
|
1324
2944
|
EyeIcon,
|
|
2945
|
+
FileInput,
|
|
1325
2946
|
FilterIcon,
|
|
1326
2947
|
FlagIcon,
|
|
1327
2948
|
Heading,
|
|
@@ -1344,21 +2965,28 @@ export {
|
|
|
1344
2965
|
PauseIcon,
|
|
1345
2966
|
PlayIcon,
|
|
1346
2967
|
PlusIcon,
|
|
2968
|
+
Popover,
|
|
2969
|
+
PriorityNav,
|
|
1347
2970
|
Progress,
|
|
1348
2971
|
RefreshIcon,
|
|
1349
2972
|
SearchIcon,
|
|
1350
2973
|
Select,
|
|
2974
|
+
SelectionBar,
|
|
1351
2975
|
SettingsIcon,
|
|
2976
|
+
Skeleton,
|
|
1352
2977
|
Spinner,
|
|
1353
2978
|
Stack,
|
|
1354
2979
|
StarIcon,
|
|
2980
|
+
Stat,
|
|
1355
2981
|
SunIcon,
|
|
1356
2982
|
Switch,
|
|
2983
|
+
Table,
|
|
1357
2984
|
Tabs,
|
|
1358
2985
|
Text,
|
|
1359
2986
|
Textarea,
|
|
1360
2987
|
ThumbsDownIcon,
|
|
1361
2988
|
ThumbsUpIcon,
|
|
2989
|
+
Toast,
|
|
1362
2990
|
Toolbar,
|
|
1363
2991
|
Tooltip,
|
|
1364
2992
|
TrashIcon,
|
|
@@ -1367,6 +2995,8 @@ export {
|
|
|
1367
2995
|
WarningIcon,
|
|
1368
2996
|
XIcon,
|
|
1369
2997
|
iconNames,
|
|
2998
|
+
useRowSelection,
|
|
2999
|
+
useToast,
|
|
1370
3000
|
version
|
|
1371
3001
|
};
|
|
1372
3002
|
//# sourceMappingURL=index.js.map
|