@salemcobalt/ui 0.2.0-rc.2 → 0.2.0-rc.20
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 +96 -19
- package/dist/codemirror-D3Z4MYFA.js +376 -0
- package/dist/codemirror-D3Z4MYFA.js.map +1 -0
- package/dist/editor.d.ts +46 -0
- package/dist/editor.js +149 -0
- package/dist/editor.js.map +1 -0
- package/dist/index.d.ts +1362 -60
- package/dist/index.js +2275 -76
- package/dist/index.js.map +1 -1
- package/dist/markdown-5O5GUVBJ.js +10 -0
- package/dist/markdown-5O5GUVBJ.js.map +1 -0
- package/dist/styles.css +3677 -46
- package/package.json +59 -6
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
|
}
|
|
@@ -438,7 +442,19 @@ function XIcon(props) {
|
|
|
438
442
|
|
|
439
443
|
// src/components/Dialog/Dialog.tsx
|
|
440
444
|
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
441
|
-
|
|
445
|
+
var REQUESTABLE = /* @__PURE__ */ new Set([
|
|
446
|
+
"escape-key",
|
|
447
|
+
"outside-press",
|
|
448
|
+
"close-press"
|
|
449
|
+
]);
|
|
450
|
+
function Root({
|
|
451
|
+
dismissible = true,
|
|
452
|
+
onOpenChange,
|
|
453
|
+
onRequestClose,
|
|
454
|
+
open,
|
|
455
|
+
defaultOpen,
|
|
456
|
+
children
|
|
457
|
+
}) {
|
|
442
458
|
return /* @__PURE__ */ jsx6(
|
|
443
459
|
BaseDialog.Root,
|
|
444
460
|
{
|
|
@@ -450,6 +466,11 @@ function Root({ dismissible = true, onOpenChange, open, defaultOpen, children })
|
|
|
450
466
|
details.cancel();
|
|
451
467
|
return;
|
|
452
468
|
}
|
|
469
|
+
if (!next && onRequestClose && REQUESTABLE.has(details.reason)) {
|
|
470
|
+
details.cancel();
|
|
471
|
+
onRequestClose(details.reason);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
453
474
|
onOpenChange?.(next);
|
|
454
475
|
},
|
|
455
476
|
children
|
|
@@ -457,7 +478,7 @@ function Root({ dismissible = true, onOpenChange, open, defaultOpen, children })
|
|
|
457
478
|
);
|
|
458
479
|
}
|
|
459
480
|
var Trigger = BaseDialog.Trigger;
|
|
460
|
-
function Content({ size = "md", className, children, ...rest }) {
|
|
481
|
+
function Content({ size = "md", variant = "dialog", className, children, ...rest }) {
|
|
461
482
|
return /* @__PURE__ */ jsxs5(BaseDialog.Portal, { children: [
|
|
462
483
|
/* @__PURE__ */ jsx6(BaseDialog.Backdrop, { className: "sc-dialog__backdrop" }),
|
|
463
484
|
/* @__PURE__ */ jsx6(
|
|
@@ -465,6 +486,7 @@ function Content({ size = "md", className, children, ...rest }) {
|
|
|
465
486
|
{
|
|
466
487
|
className: cx("sc-dialog__popup", className),
|
|
467
488
|
"data-size": size,
|
|
489
|
+
"data-variant": variant,
|
|
468
490
|
"aria-modal": "true",
|
|
469
491
|
...rest,
|
|
470
492
|
children
|
|
@@ -545,6 +567,9 @@ var iconNames = [
|
|
|
545
567
|
"x"
|
|
546
568
|
];
|
|
547
569
|
|
|
570
|
+
// src/components/IconButton/IconButton.tsx
|
|
571
|
+
import { useRender as useRender2 } from "@base-ui/react/use-render";
|
|
572
|
+
|
|
548
573
|
// src/components/Tooltip/Tooltip.tsx
|
|
549
574
|
import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
550
575
|
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
@@ -582,7 +607,7 @@ var Provider = BaseTooltip.Provider;
|
|
|
582
607
|
var Tooltip = Object.assign(TooltipBase, { Provider });
|
|
583
608
|
|
|
584
609
|
// src/components/IconButton/IconButton.tsx
|
|
585
|
-
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
610
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
586
611
|
function IconButton({
|
|
587
612
|
label,
|
|
588
613
|
children,
|
|
@@ -592,9 +617,12 @@ function IconButton({
|
|
|
592
617
|
tooltipSide = "top",
|
|
593
618
|
round = false,
|
|
594
619
|
loading = false,
|
|
595
|
-
|
|
620
|
+
dot,
|
|
621
|
+
type,
|
|
596
622
|
className,
|
|
597
623
|
onClick,
|
|
624
|
+
render,
|
|
625
|
+
ref,
|
|
598
626
|
...rest
|
|
599
627
|
}) {
|
|
600
628
|
const handleClick = (event) => {
|
|
@@ -604,10 +632,13 @@ function IconButton({
|
|
|
604
632
|
}
|
|
605
633
|
onClick?.(event);
|
|
606
634
|
};
|
|
607
|
-
const button =
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
635
|
+
const button = useRender2({
|
|
636
|
+
render,
|
|
637
|
+
ref,
|
|
638
|
+
defaultTagName: "button",
|
|
639
|
+
props: {
|
|
640
|
+
// `type` only means something on a real button; a rendered link keeps its own attributes.
|
|
641
|
+
type: render ? type : type ?? "button",
|
|
611
642
|
className: cx("sc-button", "sc-icon-button", className),
|
|
612
643
|
"data-variant": variant,
|
|
613
644
|
"data-size": size,
|
|
@@ -617,19 +648,20 @@ function IconButton({
|
|
|
617
648
|
"aria-label": label,
|
|
618
649
|
onClick: handleClick,
|
|
619
650
|
...rest,
|
|
620
|
-
children: [
|
|
651
|
+
children: /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
621
652
|
/* @__PURE__ */ jsx8("span", { className: "sc-button__icon", "aria-hidden": "true", children }),
|
|
622
|
-
loading ? /* @__PURE__ */ jsx8("span", { className: "sc-button__spinner", "aria-hidden": "true" }) : null
|
|
623
|
-
|
|
653
|
+
loading ? /* @__PURE__ */ jsx8("span", { className: "sc-button__spinner", "aria-hidden": "true" }) : null,
|
|
654
|
+
dot ? /* @__PURE__ */ jsx8("span", { className: "sc-icon-button__dot", "data-tone": dot, "aria-hidden": "true" }) : null
|
|
655
|
+
] })
|
|
624
656
|
}
|
|
625
|
-
);
|
|
657
|
+
});
|
|
626
658
|
if (!tooltip) return button;
|
|
627
659
|
return /* @__PURE__ */ jsx8(Tooltip, { content: tooltip === true ? label : tooltip, side: tooltipSide, children: button });
|
|
628
660
|
}
|
|
629
661
|
|
|
630
662
|
// src/components/Menu/Menu.tsx
|
|
631
663
|
import { Menu as BaseMenu } from "@base-ui/react/menu";
|
|
632
|
-
import { Fragment as
|
|
664
|
+
import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
633
665
|
function Root2({ open, defaultOpen, onOpenChange, disabled, modal = true, children }) {
|
|
634
666
|
return /* @__PURE__ */ jsx9(
|
|
635
667
|
BaseMenu.Root,
|
|
@@ -669,7 +701,7 @@ function ItemBody({
|
|
|
669
701
|
trailing,
|
|
670
702
|
children
|
|
671
703
|
}) {
|
|
672
|
-
return /* @__PURE__ */ jsxs8(
|
|
704
|
+
return /* @__PURE__ */ jsxs8(Fragment3, { children: [
|
|
673
705
|
/* @__PURE__ */ jsx9("span", { className: "sc-menu__icon", "aria-hidden": "true", children: icon }),
|
|
674
706
|
/* @__PURE__ */ jsx9("span", { className: "sc-menu__label", children }),
|
|
675
707
|
trailing !== void 0 ? /* @__PURE__ */ jsx9("span", { className: "sc-menu__trailing", children: trailing }) : null
|
|
@@ -678,8 +710,25 @@ function ItemBody({
|
|
|
678
710
|
function Item({ icon, trailing, tone = "default", className, children, ...rest }) {
|
|
679
711
|
return /* @__PURE__ */ jsx9(BaseMenu.Item, { className: cx("sc-menu__item", className), "data-tone": tone, ...rest, children: /* @__PURE__ */ jsx9(ItemBody, { icon, trailing, children }) });
|
|
680
712
|
}
|
|
681
|
-
function LinkItem({
|
|
682
|
-
|
|
713
|
+
function LinkItem({
|
|
714
|
+
icon,
|
|
715
|
+
trailing,
|
|
716
|
+
tone = "default",
|
|
717
|
+
className,
|
|
718
|
+
closeOnClick = true,
|
|
719
|
+
children,
|
|
720
|
+
...rest
|
|
721
|
+
}) {
|
|
722
|
+
return /* @__PURE__ */ jsx9(
|
|
723
|
+
BaseMenu.LinkItem,
|
|
724
|
+
{
|
|
725
|
+
className: cx("sc-menu__item", className),
|
|
726
|
+
"data-tone": tone,
|
|
727
|
+
closeOnClick,
|
|
728
|
+
...rest,
|
|
729
|
+
children: /* @__PURE__ */ jsx9(ItemBody, { icon, trailing, children })
|
|
730
|
+
}
|
|
731
|
+
);
|
|
683
732
|
}
|
|
684
733
|
function CheckboxItem({ trailing, onCheckedChange, className, children, ...rest }) {
|
|
685
734
|
return /* @__PURE__ */ jsxs8(
|
|
@@ -856,9 +905,14 @@ function Textarea({
|
|
|
856
905
|
className,
|
|
857
906
|
rows = 3,
|
|
858
907
|
resize = "vertical",
|
|
908
|
+
variant = "default",
|
|
859
909
|
onValueChange,
|
|
910
|
+
spellCheck,
|
|
911
|
+
autoCorrect,
|
|
912
|
+
autoCapitalize,
|
|
860
913
|
...rest
|
|
861
914
|
}) {
|
|
915
|
+
const code = variant === "code";
|
|
862
916
|
return /* @__PURE__ */ jsx12(
|
|
863
917
|
FieldShell,
|
|
864
918
|
{
|
|
@@ -874,9 +928,19 @@ function Textarea({
|
|
|
874
928
|
children: /* @__PURE__ */ jsx12(
|
|
875
929
|
Field3.Control,
|
|
876
930
|
{
|
|
877
|
-
render: /* @__PURE__ */ jsx12(
|
|
931
|
+
render: /* @__PURE__ */ jsx12(
|
|
932
|
+
"textarea",
|
|
933
|
+
{
|
|
934
|
+
rows,
|
|
935
|
+
spellCheck: spellCheck ?? (code ? false : void 0),
|
|
936
|
+
autoCorrect: autoCorrect ?? (code ? "off" : void 0),
|
|
937
|
+
autoCapitalize: autoCapitalize ?? (code ? "off" : void 0),
|
|
938
|
+
...rest
|
|
939
|
+
}
|
|
940
|
+
),
|
|
878
941
|
className: "sc-input sc-textarea",
|
|
879
942
|
"data-resize": resize,
|
|
943
|
+
"data-variant": code ? "code" : void 0,
|
|
880
944
|
required,
|
|
881
945
|
onValueChange: onValueChange ? (value) => onValueChange(value) : void 0
|
|
882
946
|
}
|
|
@@ -887,6 +951,7 @@ function Textarea({
|
|
|
887
951
|
|
|
888
952
|
// src/components/Select/Select.tsx
|
|
889
953
|
import { Select as BaseSelect } from "@base-ui/react/select";
|
|
954
|
+
import { useState } from "react";
|
|
890
955
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
891
956
|
function isGroup(entry) {
|
|
892
957
|
return "options" in entry;
|
|
@@ -913,11 +978,27 @@ function Select({
|
|
|
913
978
|
defaultValue,
|
|
914
979
|
onValueChange,
|
|
915
980
|
placeholder = "Choose\u2026",
|
|
981
|
+
clearable = false,
|
|
982
|
+
clearLabel = "Clear",
|
|
916
983
|
readOnly,
|
|
917
984
|
fullWidth = false,
|
|
918
985
|
id
|
|
919
986
|
}) {
|
|
920
987
|
const items = options.flatMap((entry) => isGroup(entry) ? entry.options : [entry]);
|
|
988
|
+
const [internal, setInternal] = useState(defaultValue ?? null);
|
|
989
|
+
const controlled = value !== void 0;
|
|
990
|
+
const current = controlled ? value : internal;
|
|
991
|
+
const setValue = (next) => {
|
|
992
|
+
if (!controlled) setInternal(next);
|
|
993
|
+
onValueChange?.(next);
|
|
994
|
+
};
|
|
995
|
+
const canClear = clearable && current != null && !disabled && !readOnly;
|
|
996
|
+
const onTriggerKeyDown = (event) => {
|
|
997
|
+
if (canClear && (event.key === "Backspace" || event.key === "Delete")) {
|
|
998
|
+
event.preventDefault();
|
|
999
|
+
setValue(null);
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
921
1002
|
return /* @__PURE__ */ jsx13(
|
|
922
1003
|
FieldShell,
|
|
923
1004
|
{
|
|
@@ -935,26 +1016,39 @@ function Select({
|
|
|
935
1016
|
BaseSelect.Root,
|
|
936
1017
|
{
|
|
937
1018
|
items,
|
|
938
|
-
value,
|
|
939
|
-
|
|
940
|
-
onValueChange: onValueChange ? (next) => onValueChange(next) : void 0,
|
|
1019
|
+
value: current,
|
|
1020
|
+
onValueChange: (next) => setValue(next),
|
|
941
1021
|
disabled,
|
|
942
1022
|
required,
|
|
943
1023
|
readOnly,
|
|
944
1024
|
children: [
|
|
945
|
-
/* @__PURE__ */ jsxs11(
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1025
|
+
/* @__PURE__ */ jsxs11("span", { className: "sc-select__wrap", "data-full-width": fullWidth || void 0, children: [
|
|
1026
|
+
/* @__PURE__ */ jsxs11(
|
|
1027
|
+
BaseSelect.Trigger,
|
|
1028
|
+
{
|
|
1029
|
+
id,
|
|
1030
|
+
className: "sc-select",
|
|
1031
|
+
"data-size": size,
|
|
1032
|
+
"data-full-width": fullWidth || void 0,
|
|
1033
|
+
"data-clearable": canClear || void 0,
|
|
1034
|
+
onKeyDown: onTriggerKeyDown,
|
|
1035
|
+
children: [
|
|
1036
|
+
/* @__PURE__ */ jsx13(BaseSelect.Value, { className: "sc-select__value", placeholder }),
|
|
1037
|
+
/* @__PURE__ */ jsx13(BaseSelect.Icon, { className: "sc-select__icon", children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) })
|
|
1038
|
+
]
|
|
1039
|
+
}
|
|
1040
|
+
),
|
|
1041
|
+
canClear ? /* @__PURE__ */ jsx13(
|
|
1042
|
+
"button",
|
|
1043
|
+
{
|
|
1044
|
+
type: "button",
|
|
1045
|
+
className: "sc-select__clear",
|
|
1046
|
+
"aria-label": clearLabel,
|
|
1047
|
+
onClick: () => setValue(null),
|
|
1048
|
+
children: /* @__PURE__ */ jsx13(XIcon, { size: "sm" })
|
|
1049
|
+
}
|
|
1050
|
+
) : null
|
|
1051
|
+
] }),
|
|
958
1052
|
/* @__PURE__ */ jsx13(BaseSelect.Portal, { children: /* @__PURE__ */ jsx13(
|
|
959
1053
|
BaseSelect.Positioner,
|
|
960
1054
|
{
|
|
@@ -1054,7 +1148,7 @@ function Switch({
|
|
|
1054
1148
|
|
|
1055
1149
|
// src/components/Tabs/Tabs.tsx
|
|
1056
1150
|
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
1057
|
-
import { Fragment as
|
|
1151
|
+
import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1058
1152
|
function Root3({ className, onValueChange, ...rest }) {
|
|
1059
1153
|
return /* @__PURE__ */ jsx16(
|
|
1060
1154
|
BaseTabs.Root,
|
|
@@ -1065,17 +1159,26 @@ function Root3({ className, onValueChange, ...rest }) {
|
|
|
1065
1159
|
}
|
|
1066
1160
|
);
|
|
1067
1161
|
}
|
|
1068
|
-
function List({ fill = false, className, children, ...rest }) {
|
|
1069
|
-
return /* @__PURE__ */ jsxs14(
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1162
|
+
function List({ fill = false, variant = "line", className, children, ...rest }) {
|
|
1163
|
+
return /* @__PURE__ */ jsxs14(
|
|
1164
|
+
BaseTabs.List,
|
|
1165
|
+
{
|
|
1166
|
+
className: cx("sc-tabs__list", className),
|
|
1167
|
+
"data-fill": fill || void 0,
|
|
1168
|
+
"data-variant": variant,
|
|
1169
|
+
...rest,
|
|
1170
|
+
children: [
|
|
1171
|
+
children,
|
|
1172
|
+
/* @__PURE__ */ jsx16(BaseTabs.Indicator, { className: "sc-tabs__indicator" })
|
|
1173
|
+
]
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1073
1176
|
}
|
|
1074
1177
|
function Tab({ icon, count, className, children, ...rest }) {
|
|
1075
1178
|
return /* @__PURE__ */ jsxs14(BaseTabs.Tab, { className: cx("sc-tabs__tab", className), ...rest, children: [
|
|
1076
1179
|
icon ? /* @__PURE__ */ jsx16("span", { className: "sc-tabs__icon", "aria-hidden": "true", children: icon }) : null,
|
|
1077
1180
|
/* @__PURE__ */ jsx16("span", { className: "sc-tabs__label", children }),
|
|
1078
|
-
count != null ? /* @__PURE__ */ jsxs14(
|
|
1181
|
+
count != null ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
1079
1182
|
" ",
|
|
1080
1183
|
/* @__PURE__ */ jsx16("span", { className: "sc-tabs__count", children: count })
|
|
1081
1184
|
] }) : null
|
|
@@ -1107,13 +1210,14 @@ function Separator2({ className, ...rest }) {
|
|
|
1107
1210
|
return /* @__PURE__ */ jsx17(BaseToolbar.Separator, { className: cx("sc-toolbar__separator", className), ...rest });
|
|
1108
1211
|
}
|
|
1109
1212
|
var Button2 = BaseToolbar.Button;
|
|
1213
|
+
var Link = BaseToolbar.Link;
|
|
1110
1214
|
function Spacer({ className }) {
|
|
1111
1215
|
return /* @__PURE__ */ jsx17("div", { className: cx("sc-toolbar__spacer", className), "aria-hidden": "true" });
|
|
1112
1216
|
}
|
|
1113
|
-
var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Spacer };
|
|
1217
|
+
var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Link, Spacer };
|
|
1114
1218
|
|
|
1115
1219
|
// src/components/Banner/Banner.tsx
|
|
1116
|
-
import { useState } from "react";
|
|
1220
|
+
import { useState as useState2 } from "react";
|
|
1117
1221
|
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1118
1222
|
var toneIcons = {
|
|
1119
1223
|
info: /* @__PURE__ */ jsx18(InfoIcon, {}),
|
|
@@ -1135,7 +1239,7 @@ function Banner({
|
|
|
1135
1239
|
children,
|
|
1136
1240
|
...rest
|
|
1137
1241
|
}) {
|
|
1138
|
-
const [dismissed, setDismissed] =
|
|
1242
|
+
const [dismissed, setDismissed] = useState2(false);
|
|
1139
1243
|
const visible = open ?? !dismissed;
|
|
1140
1244
|
if (!visible) return null;
|
|
1141
1245
|
const glyph = icon === false ? null : icon ?? toneIcons[tone];
|
|
@@ -1255,19 +1359,11 @@ var sizeByLevel = {
|
|
|
1255
1359
|
5: "md",
|
|
1256
1360
|
6: "sm"
|
|
1257
1361
|
};
|
|
1258
|
-
function Heading({
|
|
1259
|
-
level = 2,
|
|
1260
|
-
size,
|
|
1261
|
-
as,
|
|
1262
|
-
tone = "default",
|
|
1263
|
-
truncate = false,
|
|
1264
|
-
className,
|
|
1265
|
-
...rest
|
|
1266
|
-
}) {
|
|
1362
|
+
function Heading({ level = 2, size, as, tone, truncate = false, className, ...rest }) {
|
|
1267
1363
|
return createElement3(as ?? `h${level}`, {
|
|
1268
1364
|
className: cx("sc-heading", className),
|
|
1269
1365
|
"data-size": size ?? sizeByLevel[level],
|
|
1270
|
-
"data-tone": tone,
|
|
1366
|
+
"data-tone": tone ?? (size === "overline" ? "muted" : "default"),
|
|
1271
1367
|
"data-truncate": truncate || void 0,
|
|
1272
1368
|
...rest
|
|
1273
1369
|
});
|
|
@@ -1283,26 +1379,53 @@ function Text({
|
|
|
1283
1379
|
align,
|
|
1284
1380
|
truncate = false,
|
|
1285
1381
|
numeric = false,
|
|
1382
|
+
family = "sans",
|
|
1286
1383
|
className,
|
|
1287
1384
|
style,
|
|
1288
1385
|
...rest
|
|
1289
1386
|
}) {
|
|
1290
|
-
const
|
|
1387
|
+
const clamp2 = typeof truncate === "number" ? truncate : void 0;
|
|
1291
1388
|
return createElement4(as, {
|
|
1292
1389
|
className: cx("sc-text", className),
|
|
1293
1390
|
"data-size": size,
|
|
1294
1391
|
"data-tone": tone,
|
|
1295
1392
|
"data-weight": weight,
|
|
1296
1393
|
"data-align": align,
|
|
1297
|
-
"data-truncate": truncate === true ? "" :
|
|
1394
|
+
"data-truncate": truncate === true ? "" : clamp2 !== void 0 ? "clamp" : void 0,
|
|
1298
1395
|
"data-numeric": numeric || void 0,
|
|
1299
|
-
|
|
1396
|
+
"data-family": family === "mono" ? "mono" : void 0,
|
|
1397
|
+
style: clamp2 !== void 0 ? { ...style, "--sc-text-lines": clamp2 } : style,
|
|
1300
1398
|
...rest
|
|
1301
1399
|
});
|
|
1302
1400
|
}
|
|
1303
1401
|
|
|
1304
1402
|
// src/components/Table/Table.tsx
|
|
1305
|
-
import {
|
|
1403
|
+
import { Checkbox as BaseCheckbox2 } from "@base-ui/react/checkbox";
|
|
1404
|
+
import {
|
|
1405
|
+
createContext,
|
|
1406
|
+
useContext
|
|
1407
|
+
} from "react";
|
|
1408
|
+
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1409
|
+
var SelectionContext = createContext(null);
|
|
1410
|
+
var RowIdContext = createContext(void 0);
|
|
1411
|
+
function useSelection(part) {
|
|
1412
|
+
const selection = useContext(SelectionContext);
|
|
1413
|
+
if (!selection) throw new Error(`${part} needs Table.Root selection={useRowSelection(ids)}`);
|
|
1414
|
+
return selection;
|
|
1415
|
+
}
|
|
1416
|
+
function isTextEntry(target) {
|
|
1417
|
+
if (!(target instanceof HTMLElement)) return false;
|
|
1418
|
+
if (target.isContentEditable || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement)
|
|
1419
|
+
return true;
|
|
1420
|
+
return target instanceof HTMLInputElement && !["checkbox", "radio", "button", "submit", "reset", "image", "file", "color", "range"].includes(
|
|
1421
|
+
target.type
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
var CONTROLS = 'a[href], button, input, select, textarea, label, summary, [role="checkbox"], [role="button"], [role="link"], [contenteditable="true"]';
|
|
1425
|
+
function fromControl(event) {
|
|
1426
|
+
const control = event.target instanceof Element ? event.target.closest(CONTROLS) : null;
|
|
1427
|
+
return control !== null && event.currentTarget.contains(control);
|
|
1428
|
+
}
|
|
1306
1429
|
function Root5({
|
|
1307
1430
|
stickyHeader = false,
|
|
1308
1431
|
maxHeight,
|
|
@@ -1314,8 +1437,23 @@ function Root5({
|
|
|
1314
1437
|
className,
|
|
1315
1438
|
style,
|
|
1316
1439
|
children,
|
|
1440
|
+
selection,
|
|
1441
|
+
onKeyDown,
|
|
1317
1442
|
...rest
|
|
1318
1443
|
}) {
|
|
1444
|
+
const handleKeyDown = (event) => {
|
|
1445
|
+
onKeyDown?.(event);
|
|
1446
|
+
if (!selection || event.defaultPrevented) return;
|
|
1447
|
+
if (!(event.target instanceof Node) || !event.currentTarget.contains(event.target)) return;
|
|
1448
|
+
if (isTextEntry(event.target)) return;
|
|
1449
|
+
if ((event.metaKey || event.ctrlKey) && !event.altKey && event.key.toLowerCase() === "a") {
|
|
1450
|
+
event.preventDefault();
|
|
1451
|
+
selection.selectAll();
|
|
1452
|
+
} else if (event.key === "Escape" && selection.count > 0) {
|
|
1453
|
+
event.preventDefault();
|
|
1454
|
+
selection.clear();
|
|
1455
|
+
}
|
|
1456
|
+
};
|
|
1319
1457
|
return /* @__PURE__ */ jsx21(
|
|
1320
1458
|
"div",
|
|
1321
1459
|
{
|
|
@@ -1331,8 +1469,9 @@ function Root5({
|
|
|
1331
1469
|
"data-divided": divided || void 0,
|
|
1332
1470
|
"data-layout": layout,
|
|
1333
1471
|
style,
|
|
1472
|
+
onKeyDown: selection ? handleKeyDown : onKeyDown,
|
|
1334
1473
|
...rest,
|
|
1335
|
-
children
|
|
1474
|
+
children: /* @__PURE__ */ jsx21(SelectionContext.Provider, { value: selection ?? null, children })
|
|
1336
1475
|
}
|
|
1337
1476
|
)
|
|
1338
1477
|
}
|
|
@@ -1350,17 +1489,117 @@ function Body2({ className, ...rest }) {
|
|
|
1350
1489
|
function Foot({ className, ...rest }) {
|
|
1351
1490
|
return /* @__PURE__ */ jsx21("tfoot", { className: cx("sc-table__foot", className), ...rest });
|
|
1352
1491
|
}
|
|
1353
|
-
function Row({
|
|
1354
|
-
|
|
1492
|
+
function Row({
|
|
1493
|
+
selected,
|
|
1494
|
+
interactive = false,
|
|
1495
|
+
selectionId,
|
|
1496
|
+
className,
|
|
1497
|
+
onClick,
|
|
1498
|
+
onMouseDown,
|
|
1499
|
+
...rest
|
|
1500
|
+
}) {
|
|
1501
|
+
const selection = useContext(SelectionContext);
|
|
1502
|
+
const selectable = selection !== null && selectionId !== void 0;
|
|
1503
|
+
const isSelected = selected ?? (selectable && selection.isSelected(selectionId));
|
|
1504
|
+
const row = /* @__PURE__ */ jsx21(
|
|
1355
1505
|
"tr",
|
|
1356
1506
|
{
|
|
1357
1507
|
className: cx("sc-table__row", className),
|
|
1358
|
-
"data-selected":
|
|
1508
|
+
"data-selected": isSelected || void 0,
|
|
1359
1509
|
"data-interactive": interactive || void 0,
|
|
1360
|
-
"aria-selected":
|
|
1510
|
+
"aria-selected": selectable ? isSelected : isSelected || void 0,
|
|
1511
|
+
onClick: selectable ? (event) => {
|
|
1512
|
+
if ((event.shiftKey || event.metaKey || event.ctrlKey) && !fromControl(event)) {
|
|
1513
|
+
event.preventDefault();
|
|
1514
|
+
if (event.shiftKey) selection.toggleRange(selectionId);
|
|
1515
|
+
else selection.toggle(selectionId);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
onClick?.(event);
|
|
1519
|
+
} : onClick,
|
|
1520
|
+
onMouseDown: selectable ? (event) => {
|
|
1521
|
+
if (event.shiftKey && !fromControl(event)) event.preventDefault();
|
|
1522
|
+
onMouseDown?.(event);
|
|
1523
|
+
} : onMouseDown,
|
|
1361
1524
|
...rest
|
|
1362
1525
|
}
|
|
1363
1526
|
);
|
|
1527
|
+
return selectionId === void 0 ? row : /* @__PURE__ */ jsx21(RowIdContext.Provider, { value: selectionId, children: row });
|
|
1528
|
+
}
|
|
1529
|
+
function SelectionBox({
|
|
1530
|
+
label,
|
|
1531
|
+
...rest
|
|
1532
|
+
}) {
|
|
1533
|
+
return /* @__PURE__ */ jsx21(BaseCheckbox2.Root, { className: "sc-checkbox", "aria-label": label, ...rest, children: /* @__PURE__ */ jsxs18(BaseCheckbox2.Indicator, { className: "sc-checkbox__indicator", children: [
|
|
1534
|
+
/* @__PURE__ */ jsx21(CheckIcon, { size: "sm", className: "sc-checkbox__check" }),
|
|
1535
|
+
/* @__PURE__ */ jsx21(MinusIcon, { size: "sm", className: "sc-checkbox__dash" })
|
|
1536
|
+
] }) });
|
|
1537
|
+
}
|
|
1538
|
+
var onCheckbox = (event) => event.target instanceof Element && event.target.closest('[role="checkbox"]') !== null;
|
|
1539
|
+
function SelectionHeader({
|
|
1540
|
+
label = "Select all rows",
|
|
1541
|
+
className,
|
|
1542
|
+
onClick,
|
|
1543
|
+
...rest
|
|
1544
|
+
}) {
|
|
1545
|
+
const selection = useSelection("Table.SelectionHeader");
|
|
1546
|
+
const disabled = selection.ids.length === 0;
|
|
1547
|
+
const toggleAll = () => selection.headerState === "all" ? selection.clear() : selection.selectAll();
|
|
1548
|
+
return /* @__PURE__ */ jsx21(
|
|
1549
|
+
"th",
|
|
1550
|
+
{
|
|
1551
|
+
scope: "col",
|
|
1552
|
+
className: cx("sc-table__header", "sc-table__select", className),
|
|
1553
|
+
"data-disabled": disabled || void 0,
|
|
1554
|
+
onClick: (event) => {
|
|
1555
|
+
onClick?.(event);
|
|
1556
|
+
if (!disabled && !onCheckbox(event)) toggleAll();
|
|
1557
|
+
},
|
|
1558
|
+
...rest,
|
|
1559
|
+
children: /* @__PURE__ */ jsx21(
|
|
1560
|
+
SelectionBox,
|
|
1561
|
+
{
|
|
1562
|
+
label,
|
|
1563
|
+
checked: selection.headerState === "all",
|
|
1564
|
+
indeterminate: selection.headerState === "some",
|
|
1565
|
+
disabled,
|
|
1566
|
+
onCheckedChange: toggleAll
|
|
1567
|
+
}
|
|
1568
|
+
)
|
|
1569
|
+
}
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
function SelectionCell({ label, className, onClick, onClickCapture, ...rest }) {
|
|
1573
|
+
const selection = useSelection("Table.SelectionCell");
|
|
1574
|
+
const id = useContext(RowIdContext);
|
|
1575
|
+
if (id === void 0) throw new Error("Table.SelectionCell goes inside a Table.Row with selectionId");
|
|
1576
|
+
return /* @__PURE__ */ jsx21(
|
|
1577
|
+
"td",
|
|
1578
|
+
{
|
|
1579
|
+
className: cx("sc-table__cell", "sc-table__select", className),
|
|
1580
|
+
onClickCapture: (event) => {
|
|
1581
|
+
onClickCapture?.(event);
|
|
1582
|
+
if (!event.shiftKey) return;
|
|
1583
|
+
event.preventDefault();
|
|
1584
|
+
event.stopPropagation();
|
|
1585
|
+
selection.toggleRange(id);
|
|
1586
|
+
},
|
|
1587
|
+
onClick: (event) => {
|
|
1588
|
+
onClick?.(event);
|
|
1589
|
+
event.stopPropagation();
|
|
1590
|
+
if (!onCheckbox(event)) selection.toggle(id);
|
|
1591
|
+
},
|
|
1592
|
+
...rest,
|
|
1593
|
+
children: /* @__PURE__ */ jsx21(
|
|
1594
|
+
SelectionBox,
|
|
1595
|
+
{
|
|
1596
|
+
label,
|
|
1597
|
+
checked: selection.isSelected(id),
|
|
1598
|
+
onCheckedChange: () => selection.toggle(id)
|
|
1599
|
+
}
|
|
1600
|
+
)
|
|
1601
|
+
}
|
|
1602
|
+
);
|
|
1364
1603
|
}
|
|
1365
1604
|
function Header({
|
|
1366
1605
|
align,
|
|
@@ -1368,11 +1607,16 @@ function Header({
|
|
|
1368
1607
|
nowrap = false,
|
|
1369
1608
|
truncate = false,
|
|
1370
1609
|
width,
|
|
1610
|
+
sortable = false,
|
|
1611
|
+
sortDirection = "none",
|
|
1612
|
+
onSort,
|
|
1371
1613
|
scope = "col",
|
|
1372
1614
|
className,
|
|
1373
1615
|
style,
|
|
1616
|
+
children,
|
|
1374
1617
|
...rest
|
|
1375
1618
|
}) {
|
|
1619
|
+
const sorted = sortable && sortDirection !== "none";
|
|
1376
1620
|
return /* @__PURE__ */ jsx21(
|
|
1377
1621
|
"th",
|
|
1378
1622
|
{
|
|
@@ -1382,8 +1626,23 @@ function Header({
|
|
|
1382
1626
|
"data-numeric": numeric || void 0,
|
|
1383
1627
|
"data-nowrap": nowrap || void 0,
|
|
1384
1628
|
"data-truncate": truncate || void 0,
|
|
1629
|
+
"data-sortable": sortable || void 0,
|
|
1630
|
+
"data-sorted": sorted ? sortDirection : void 0,
|
|
1631
|
+
"aria-sort": sorted ? sortDirection : void 0,
|
|
1385
1632
|
style: width ? { ...style, inlineSize: width } : style,
|
|
1386
|
-
...rest
|
|
1633
|
+
...rest,
|
|
1634
|
+
children: sortable ? /* @__PURE__ */ jsxs18(
|
|
1635
|
+
"button",
|
|
1636
|
+
{
|
|
1637
|
+
type: "button",
|
|
1638
|
+
className: "sc-table__sort",
|
|
1639
|
+
onClick: () => onSort?.(sortDirection === "ascending" ? "descending" : "ascending"),
|
|
1640
|
+
children: [
|
|
1641
|
+
/* @__PURE__ */ jsx21("span", { className: "sc-table__sort-label", children }),
|
|
1642
|
+
/* @__PURE__ */ jsx21("span", { className: "sc-table__sort-icon", "aria-hidden": "true", children: sortDirection === "descending" ? /* @__PURE__ */ jsx21(ArrowDownIcon, { size: "xs" }) : /* @__PURE__ */ jsx21(ArrowUpIcon, { size: "xs" }) })
|
|
1643
|
+
]
|
|
1644
|
+
}
|
|
1645
|
+
) : children
|
|
1387
1646
|
}
|
|
1388
1647
|
);
|
|
1389
1648
|
}
|
|
@@ -1410,15 +1669,248 @@ function Cell({
|
|
|
1410
1669
|
}
|
|
1411
1670
|
);
|
|
1412
1671
|
}
|
|
1413
|
-
var Table = { Root: Root5, Caption, Head, Body: Body2, Foot, Row, Header, Cell };
|
|
1672
|
+
var Table = { Root: Root5, Caption, Head, Body: Body2, Foot, Row, Header, Cell, SelectionHeader, SelectionCell };
|
|
1673
|
+
|
|
1674
|
+
// src/components/Table/useRowSelection.ts
|
|
1675
|
+
import { useMemo, useReducer } from "react";
|
|
1676
|
+
|
|
1677
|
+
// src/components/Table/rowSelection.ts
|
|
1678
|
+
function initRowSelection(ids) {
|
|
1679
|
+
return { ids, selected: /* @__PURE__ */ new Set(), anchor: null };
|
|
1680
|
+
}
|
|
1681
|
+
function sameIds(a, b) {
|
|
1682
|
+
if (a === b) return true;
|
|
1683
|
+
if (a.length !== b.length) return false;
|
|
1684
|
+
for (let i = 0; i < a.length; i += 1) if (a[i] !== b[i]) return false;
|
|
1685
|
+
return true;
|
|
1686
|
+
}
|
|
1687
|
+
function toggle(state, id) {
|
|
1688
|
+
if (!state.ids.includes(id)) return state;
|
|
1689
|
+
const selected = new Set(state.selected);
|
|
1690
|
+
if (selected.has(id)) selected.delete(id);
|
|
1691
|
+
else selected.add(id);
|
|
1692
|
+
return { ...state, selected, anchor: id };
|
|
1693
|
+
}
|
|
1694
|
+
function toggleRange(state, id) {
|
|
1695
|
+
const to = state.ids.indexOf(id);
|
|
1696
|
+
if (to < 0) return state;
|
|
1697
|
+
const from = state.anchor === null ? -1 : state.ids.indexOf(state.anchor);
|
|
1698
|
+
if (from < 0 || from === to) return toggle(state, id);
|
|
1699
|
+
const on = !state.selected.has(id);
|
|
1700
|
+
const selected = new Set(state.selected);
|
|
1701
|
+
const [start, end] = from < to ? [from, to] : [to, from];
|
|
1702
|
+
for (let i = start; i <= end; i += 1) {
|
|
1703
|
+
const rowId = state.ids[i];
|
|
1704
|
+
if (on) selected.add(rowId);
|
|
1705
|
+
else selected.delete(rowId);
|
|
1706
|
+
}
|
|
1707
|
+
return { ...state, selected, anchor: id };
|
|
1708
|
+
}
|
|
1709
|
+
function sync(state, ids) {
|
|
1710
|
+
if (sameIds(state.ids, ids)) return state;
|
|
1711
|
+
const present = new Set(ids);
|
|
1712
|
+
let selected = state.selected;
|
|
1713
|
+
for (const id of state.selected) {
|
|
1714
|
+
if (present.has(id)) continue;
|
|
1715
|
+
selected = new Set([...state.selected].filter((x) => present.has(x)));
|
|
1716
|
+
break;
|
|
1717
|
+
}
|
|
1718
|
+
const anchor = state.anchor !== null && present.has(state.anchor) ? state.anchor : null;
|
|
1719
|
+
return { ids, selected, anchor };
|
|
1720
|
+
}
|
|
1721
|
+
function rowSelectionReducer(state, event) {
|
|
1722
|
+
switch (event.type) {
|
|
1723
|
+
case "selection.sync":
|
|
1724
|
+
return sync(state, event.ids);
|
|
1725
|
+
case "selection.toggle":
|
|
1726
|
+
return toggle(state, event.id);
|
|
1727
|
+
case "selection.toggleRange":
|
|
1728
|
+
return toggleRange(state, event.id);
|
|
1729
|
+
case "selection.selectAll":
|
|
1730
|
+
return state.selected.size === state.ids.length ? state : { ...state, selected: new Set(state.ids) };
|
|
1731
|
+
case "selection.clear":
|
|
1732
|
+
return state.selected.size === 0 && state.anchor === null ? state : { ...state, selected: /* @__PURE__ */ new Set(), anchor: null };
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
function headerState(state) {
|
|
1736
|
+
if (state.selected.size === 0) return "none";
|
|
1737
|
+
return state.selected.size === state.ids.length ? "all" : "some";
|
|
1738
|
+
}
|
|
1739
|
+
function selectedIds(state) {
|
|
1740
|
+
return state.ids.filter((id) => state.selected.has(id));
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
// src/components/Table/useRowSelection.ts
|
|
1744
|
+
function useRowSelection(ids) {
|
|
1745
|
+
const [stored, dispatch] = useReducer(rowSelectionReducer, ids, initRowSelection);
|
|
1746
|
+
const state = sameIds(stored.ids, ids) ? stored : rowSelectionReducer(stored, { type: "selection.sync", ids });
|
|
1747
|
+
if (state !== stored) dispatch({ type: "selection.sync", ids });
|
|
1748
|
+
const actions = useMemo(
|
|
1749
|
+
() => ({
|
|
1750
|
+
toggle: (id) => dispatch({ type: "selection.toggle", id }),
|
|
1751
|
+
toggleRange: (id) => dispatch({ type: "selection.toggleRange", id }),
|
|
1752
|
+
selectAll: () => dispatch({ type: "selection.selectAll" }),
|
|
1753
|
+
clear: () => dispatch({ type: "selection.clear" })
|
|
1754
|
+
}),
|
|
1755
|
+
[]
|
|
1756
|
+
);
|
|
1757
|
+
return useMemo(
|
|
1758
|
+
() => ({
|
|
1759
|
+
ids: state.ids,
|
|
1760
|
+
selected: state.selected,
|
|
1761
|
+
selectedIds: selectedIds(state),
|
|
1762
|
+
count: state.selected.size,
|
|
1763
|
+
anchor: state.anchor,
|
|
1764
|
+
headerState: headerState(state),
|
|
1765
|
+
isSelected: (id) => state.selected.has(id),
|
|
1766
|
+
...actions
|
|
1767
|
+
}),
|
|
1768
|
+
[state, actions]
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
// src/components/SelectionBar/SelectionBar.tsx
|
|
1773
|
+
import { useEffect, useLayoutEffect, useRef, useState as useState3 } from "react";
|
|
1774
|
+
import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1775
|
+
var defaultCountLabel = (count) => `${count} selected`;
|
|
1776
|
+
var LEAVE_MS = 200;
|
|
1777
|
+
function SelectionBar({
|
|
1778
|
+
count,
|
|
1779
|
+
onClear,
|
|
1780
|
+
children,
|
|
1781
|
+
"aria-label": ariaLabel = "Bulk actions",
|
|
1782
|
+
countLabel = defaultCountLabel,
|
|
1783
|
+
clearLabel = "Clear",
|
|
1784
|
+
clearedMessage = "Selection cleared",
|
|
1785
|
+
className
|
|
1786
|
+
}) {
|
|
1787
|
+
const open = count > 0;
|
|
1788
|
+
const [hadSelection, setHadSelection] = useState3(open);
|
|
1789
|
+
if (open && !hadSelection) setHadSelection(true);
|
|
1790
|
+
const message = open ? countLabel(count) : hadSelection ? clearedMessage : "";
|
|
1791
|
+
const [rendered, setRendered] = useState3(open);
|
|
1792
|
+
const [shownCount, setShownCount] = useState3(count);
|
|
1793
|
+
if (open && !rendered) setRendered(true);
|
|
1794
|
+
if (open && shownCount !== count) setShownCount(count);
|
|
1795
|
+
useEffect(() => {
|
|
1796
|
+
if (open || !rendered) return;
|
|
1797
|
+
const timer = setTimeout(() => setRendered(false), LEAVE_MS);
|
|
1798
|
+
return () => clearTimeout(timer);
|
|
1799
|
+
}, [open, rendered]);
|
|
1800
|
+
const barRef = useRef(null);
|
|
1801
|
+
const returnTo = useRef(null);
|
|
1802
|
+
useLayoutEffect(() => {
|
|
1803
|
+
const bar = barRef.current;
|
|
1804
|
+
if (open || !bar?.contains(bar.ownerDocument.activeElement)) return;
|
|
1805
|
+
if (returnTo.current?.isConnected) returnTo.current.focus();
|
|
1806
|
+
}, [open]);
|
|
1807
|
+
const [height, setHeight] = useState3(0);
|
|
1808
|
+
useEffect(() => {
|
|
1809
|
+
const bar = barRef.current;
|
|
1810
|
+
if (!rendered || !bar || typeof ResizeObserver === "undefined") return;
|
|
1811
|
+
const observer = new ResizeObserver(([entry]) => setHeight(entry.borderBoxSize[0]?.blockSize ?? 0));
|
|
1812
|
+
observer.observe(bar);
|
|
1813
|
+
return () => observer.disconnect();
|
|
1814
|
+
}, [rendered]);
|
|
1815
|
+
return /* @__PURE__ */ jsxs19(Fragment5, { children: [
|
|
1816
|
+
/* @__PURE__ */ jsx22("span", { role: "status", className: "sc-visually-hidden", children: message }),
|
|
1817
|
+
rendered ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
|
|
1818
|
+
open ? /* @__PURE__ */ jsx22(
|
|
1819
|
+
"div",
|
|
1820
|
+
{
|
|
1821
|
+
className: "sc-selection-bar__spacer",
|
|
1822
|
+
style: { "--sc-selection-bar-height": `${height}px` },
|
|
1823
|
+
"aria-hidden": "true"
|
|
1824
|
+
}
|
|
1825
|
+
) : null,
|
|
1826
|
+
/* @__PURE__ */ jsx22(
|
|
1827
|
+
"div",
|
|
1828
|
+
{
|
|
1829
|
+
ref: barRef,
|
|
1830
|
+
className: cx("sc-selection-bar", className),
|
|
1831
|
+
"data-open": open || void 0,
|
|
1832
|
+
onFocus: (event) => {
|
|
1833
|
+
const from = event.relatedTarget;
|
|
1834
|
+
if (from instanceof HTMLElement && !event.currentTarget.contains(from)) returnTo.current = from;
|
|
1835
|
+
},
|
|
1836
|
+
children: /* @__PURE__ */ jsxs19(Toolbar.Root, { "aria-label": ariaLabel, className: "sc-selection-bar__toolbar", children: [
|
|
1837
|
+
/* @__PURE__ */ jsx22("span", { className: "sc-selection-bar__count", children: countLabel(shownCount) }),
|
|
1838
|
+
/* @__PURE__ */ jsx22(Toolbar.Separator, {}),
|
|
1839
|
+
children,
|
|
1840
|
+
/* @__PURE__ */ jsx22(Toolbar.Spacer, {}),
|
|
1841
|
+
/* @__PURE__ */ jsx22(Toolbar.Button, { render: /* @__PURE__ */ jsx22(Button, { variant: "ghost", size: "sm" }), onClick: onClear, children: clearLabel })
|
|
1842
|
+
] })
|
|
1843
|
+
}
|
|
1844
|
+
)
|
|
1845
|
+
] }) : null
|
|
1846
|
+
] });
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// src/components/Toast/Toast.tsx
|
|
1850
|
+
import { Toast as BaseToast } from "@base-ui/react/toast";
|
|
1851
|
+
import { useMemo as useMemo2 } from "react";
|
|
1852
|
+
import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1853
|
+
function Provider2({ children, timeout = 6e3, limit = 3 }) {
|
|
1854
|
+
return /* @__PURE__ */ jsxs20(BaseToast.Provider, { timeout, limit, children: [
|
|
1855
|
+
children,
|
|
1856
|
+
/* @__PURE__ */ jsx23(BaseToast.Portal, { children: /* @__PURE__ */ jsx23(Viewport, {}) })
|
|
1857
|
+
] });
|
|
1858
|
+
}
|
|
1859
|
+
function Viewport() {
|
|
1860
|
+
const { toasts, close } = BaseToast.useToastManager();
|
|
1861
|
+
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: [
|
|
1862
|
+
/* @__PURE__ */ jsxs20(BaseToast.Content, { className: "sc-toast__content", children: [
|
|
1863
|
+
/* @__PURE__ */ jsx23(BaseToast.Title, { className: "sc-toast__title" }),
|
|
1864
|
+
toast.description != null ? /* @__PURE__ */ jsx23(BaseToast.Description, { className: "sc-toast__description" }) : null
|
|
1865
|
+
] }),
|
|
1866
|
+
toast.actionProps ? /* @__PURE__ */ jsx23(
|
|
1867
|
+
BaseToast.Action,
|
|
1868
|
+
{
|
|
1869
|
+
className: "sc-toast__action",
|
|
1870
|
+
render: /* @__PURE__ */ jsx23(Button, { variant: "secondary", size: "sm" })
|
|
1871
|
+
}
|
|
1872
|
+
) : null,
|
|
1873
|
+
/* @__PURE__ */ jsx23(IconButton, { label: "Dismiss", size: "sm", className: "sc-toast__close", onClick: () => close(toast.id), children: /* @__PURE__ */ jsx23(XIcon, {}) })
|
|
1874
|
+
] }, toast.id)) });
|
|
1875
|
+
}
|
|
1876
|
+
function useToast() {
|
|
1877
|
+
const manager = BaseToast.useToastManager();
|
|
1878
|
+
return useMemo2(
|
|
1879
|
+
() => ({
|
|
1880
|
+
add: ({ title, description, tone = "neutral", action, timeout, priority }) => {
|
|
1881
|
+
let id = "";
|
|
1882
|
+
id = manager.add({
|
|
1883
|
+
title,
|
|
1884
|
+
description,
|
|
1885
|
+
type: tone,
|
|
1886
|
+
...timeout !== void 0 ? { timeout } : {},
|
|
1887
|
+
...priority ? { priority } : {},
|
|
1888
|
+
...action ? {
|
|
1889
|
+
actionProps: {
|
|
1890
|
+
children: action.label,
|
|
1891
|
+
onClick: () => {
|
|
1892
|
+
action.onClick();
|
|
1893
|
+
manager.close(id);
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
} : {}
|
|
1897
|
+
});
|
|
1898
|
+
return id;
|
|
1899
|
+
},
|
|
1900
|
+
close: manager.close
|
|
1901
|
+
}),
|
|
1902
|
+
[manager]
|
|
1903
|
+
);
|
|
1904
|
+
}
|
|
1905
|
+
var Toast = { Provider: Provider2 };
|
|
1414
1906
|
|
|
1415
1907
|
// src/components/Stat/Stat.tsx
|
|
1416
1908
|
import { createElement as createElement5 } from "react";
|
|
1417
|
-
import { Fragment as
|
|
1909
|
+
import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1418
1910
|
var trendIcons = {
|
|
1419
|
-
up: /* @__PURE__ */
|
|
1420
|
-
down: /* @__PURE__ */
|
|
1421
|
-
flat: /* @__PURE__ */
|
|
1911
|
+
up: /* @__PURE__ */ jsx24(ArrowUpIcon, { size: "xs" }),
|
|
1912
|
+
down: /* @__PURE__ */ jsx24(ArrowDownIcon, { size: "xs" }),
|
|
1913
|
+
flat: /* @__PURE__ */ jsx24(ArrowRightIcon, { size: "xs" })
|
|
1422
1914
|
};
|
|
1423
1915
|
function Stat({
|
|
1424
1916
|
label,
|
|
@@ -1442,23 +1934,1712 @@ function Stat({
|
|
|
1442
1934
|
"data-size": size,
|
|
1443
1935
|
...rest
|
|
1444
1936
|
},
|
|
1445
|
-
/* @__PURE__ */
|
|
1446
|
-
/* @__PURE__ */
|
|
1447
|
-
icon ? /* @__PURE__ */
|
|
1448
|
-
/* @__PURE__ */
|
|
1449
|
-
delta != null ? /* @__PURE__ */
|
|
1450
|
-
trend ? /* @__PURE__ */
|
|
1451
|
-
trend ? /* @__PURE__ */
|
|
1937
|
+
/* @__PURE__ */ jsxs21(Fragment6, { children: [
|
|
1938
|
+
/* @__PURE__ */ jsx24("div", { className: "sc-stat__label", children: label }),
|
|
1939
|
+
icon ? /* @__PURE__ */ jsx24("span", { className: "sc-stat__icon", "aria-hidden": "true", children: icon }) : null,
|
|
1940
|
+
/* @__PURE__ */ jsx24("div", { className: "sc-stat__value", children: value }),
|
|
1941
|
+
delta != null ? /* @__PURE__ */ jsxs21("div", { className: "sc-stat__delta", "data-tone": deltaTone, children: [
|
|
1942
|
+
trend ? /* @__PURE__ */ jsx24("span", { className: "sc-stat__trend", "aria-hidden": "true", children: trendIcons[trend] }) : null,
|
|
1943
|
+
trend ? /* @__PURE__ */ jsxs21("span", { className: "sc-visually-hidden", children: [
|
|
1452
1944
|
trend === "flat" ? "unchanged" : trend,
|
|
1453
1945
|
" "
|
|
1454
1946
|
] }) : null,
|
|
1455
1947
|
delta
|
|
1456
1948
|
] }) : null,
|
|
1457
|
-
hint != null ? /* @__PURE__ */
|
|
1949
|
+
hint != null ? /* @__PURE__ */ jsx24("div", { className: "sc-stat__hint", children: hint }) : null
|
|
1458
1950
|
] })
|
|
1459
1951
|
);
|
|
1460
1952
|
}
|
|
1461
1953
|
|
|
1954
|
+
// src/components/Chip/Chip.tsx
|
|
1955
|
+
import { Fragment as Fragment7, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1956
|
+
function Chip({
|
|
1957
|
+
children,
|
|
1958
|
+
icon,
|
|
1959
|
+
tone = "neutral",
|
|
1960
|
+
size = "md",
|
|
1961
|
+
selected = false,
|
|
1962
|
+
onClick,
|
|
1963
|
+
onRemove,
|
|
1964
|
+
removeLabel,
|
|
1965
|
+
disabled = false,
|
|
1966
|
+
className,
|
|
1967
|
+
...rest
|
|
1968
|
+
}) {
|
|
1969
|
+
const interactive = onClick !== void 0;
|
|
1970
|
+
const removeName = removeLabel ?? (typeof children === "string" ? `Remove ${children}` : "Remove");
|
|
1971
|
+
const handleRemoveKey = (event) => {
|
|
1972
|
+
if (onRemove && !disabled && (event.key === "Backspace" || event.key === "Delete")) {
|
|
1973
|
+
event.preventDefault();
|
|
1974
|
+
onRemove();
|
|
1975
|
+
}
|
|
1976
|
+
};
|
|
1977
|
+
const shared = {
|
|
1978
|
+
className: cx("sc-chip", className),
|
|
1979
|
+
"data-tone": tone,
|
|
1980
|
+
"data-size": size,
|
|
1981
|
+
"data-selected": selected || void 0,
|
|
1982
|
+
"data-removable": onRemove ? "" : void 0,
|
|
1983
|
+
"data-disabled": disabled || void 0
|
|
1984
|
+
};
|
|
1985
|
+
const body = /* @__PURE__ */ jsxs22(Fragment7, { children: [
|
|
1986
|
+
icon ? /* @__PURE__ */ jsx25("span", { className: "sc-chip__icon", "aria-hidden": "true", children: icon }) : null,
|
|
1987
|
+
/* @__PURE__ */ jsx25("span", { className: "sc-chip__label", children })
|
|
1988
|
+
] });
|
|
1989
|
+
const remove = onRemove ? /* @__PURE__ */ jsx25(
|
|
1990
|
+
"button",
|
|
1991
|
+
{
|
|
1992
|
+
type: "button",
|
|
1993
|
+
className: "sc-chip__remove",
|
|
1994
|
+
"aria-label": removeName,
|
|
1995
|
+
disabled,
|
|
1996
|
+
onClick: (event) => {
|
|
1997
|
+
event.stopPropagation();
|
|
1998
|
+
onRemove();
|
|
1999
|
+
},
|
|
2000
|
+
onKeyDown: handleRemoveKey,
|
|
2001
|
+
children: /* @__PURE__ */ jsx25(XIcon, { size: "xs" })
|
|
2002
|
+
}
|
|
2003
|
+
) : null;
|
|
2004
|
+
if (interactive) {
|
|
2005
|
+
return /* @__PURE__ */ jsxs22("span", { ...shared, ...rest, children: [
|
|
2006
|
+
/* @__PURE__ */ jsx25(
|
|
2007
|
+
"button",
|
|
2008
|
+
{
|
|
2009
|
+
type: "button",
|
|
2010
|
+
className: "sc-chip__action",
|
|
2011
|
+
"aria-pressed": selected,
|
|
2012
|
+
disabled,
|
|
2013
|
+
onClick,
|
|
2014
|
+
onKeyDown: handleRemoveKey,
|
|
2015
|
+
children: body
|
|
2016
|
+
}
|
|
2017
|
+
),
|
|
2018
|
+
remove
|
|
2019
|
+
] });
|
|
2020
|
+
}
|
|
2021
|
+
return /* @__PURE__ */ jsxs22("span", { ...shared, ...rest, children: [
|
|
2022
|
+
body,
|
|
2023
|
+
remove
|
|
2024
|
+
] });
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// src/components/Disclosure/Disclosure.tsx
|
|
2028
|
+
import {
|
|
2029
|
+
useEffect as useEffect2,
|
|
2030
|
+
useRef as useRef2,
|
|
2031
|
+
useState as useState4
|
|
2032
|
+
} from "react";
|
|
2033
|
+
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2034
|
+
function Disclosure({
|
|
2035
|
+
summary,
|
|
2036
|
+
summaryOpen,
|
|
2037
|
+
open,
|
|
2038
|
+
defaultOpen = false,
|
|
2039
|
+
onOpenChange,
|
|
2040
|
+
previewLines,
|
|
2041
|
+
summaryPosition,
|
|
2042
|
+
className,
|
|
2043
|
+
style,
|
|
2044
|
+
children,
|
|
2045
|
+
ref,
|
|
2046
|
+
...rest
|
|
2047
|
+
}) {
|
|
2048
|
+
const controlled = open !== void 0;
|
|
2049
|
+
const [internal, setInternal] = useState4(defaultOpen);
|
|
2050
|
+
const isOpen = controlled ? open : internal;
|
|
2051
|
+
const inner = useRef2(null);
|
|
2052
|
+
useEffect2(() => {
|
|
2053
|
+
if (controlled && inner.current && inner.current.open !== open) inner.current.open = open;
|
|
2054
|
+
});
|
|
2055
|
+
const onToggle = (event) => {
|
|
2056
|
+
const next = event.currentTarget.open;
|
|
2057
|
+
if (next === isOpen) return;
|
|
2058
|
+
if (!controlled) setInternal(next);
|
|
2059
|
+
onOpenChange?.(next);
|
|
2060
|
+
};
|
|
2061
|
+
const position = summaryPosition ?? (previewLines ? "end" : "start");
|
|
2062
|
+
return /* @__PURE__ */ jsxs23(
|
|
2063
|
+
"details",
|
|
2064
|
+
{
|
|
2065
|
+
ref: (node) => {
|
|
2066
|
+
inner.current = node;
|
|
2067
|
+
if (typeof ref === "function") ref(node);
|
|
2068
|
+
else if (ref) ref.current = node;
|
|
2069
|
+
},
|
|
2070
|
+
className: cx("sc-disclosure", className),
|
|
2071
|
+
open: isOpen,
|
|
2072
|
+
onToggle,
|
|
2073
|
+
"data-summary-position": position,
|
|
2074
|
+
"data-preview": previewLines ? "" : void 0,
|
|
2075
|
+
style: previewLines ? { ...style, "--_lines": previewLines } : style,
|
|
2076
|
+
...rest,
|
|
2077
|
+
children: [
|
|
2078
|
+
/* @__PURE__ */ jsxs23("summary", { className: "sc-disclosure__summary", children: [
|
|
2079
|
+
/* @__PURE__ */ jsx26(ChevronDownIcon, { className: "sc-disclosure__chevron" }),
|
|
2080
|
+
/* @__PURE__ */ jsx26("span", { className: "sc-disclosure__summary-text", children: isOpen && summaryOpen != null ? summaryOpen : summary })
|
|
2081
|
+
] }),
|
|
2082
|
+
/* @__PURE__ */ jsx26("div", { className: "sc-disclosure__content", children })
|
|
2083
|
+
]
|
|
2084
|
+
}
|
|
2085
|
+
);
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
// src/components/EmptyState/EmptyState.tsx
|
|
2089
|
+
import { createElement as createElement6 } from "react";
|
|
2090
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
2091
|
+
function EmptyState({
|
|
2092
|
+
title,
|
|
2093
|
+
description,
|
|
2094
|
+
icon,
|
|
2095
|
+
children,
|
|
2096
|
+
size = "md",
|
|
2097
|
+
as = "div",
|
|
2098
|
+
className,
|
|
2099
|
+
...rest
|
|
2100
|
+
}) {
|
|
2101
|
+
return createElement6(
|
|
2102
|
+
as,
|
|
2103
|
+
{ className: cx("sc-empty-state", className), "data-size": size, ...rest },
|
|
2104
|
+
icon ? /* @__PURE__ */ jsx27("span", { className: "sc-empty-state__icon", "aria-hidden": "true", children: icon }) : null,
|
|
2105
|
+
/* @__PURE__ */ jsx27("p", { className: "sc-empty-state__title", children: title }),
|
|
2106
|
+
description != null ? /* @__PURE__ */ jsx27("p", { className: "sc-empty-state__description", children: description }) : null,
|
|
2107
|
+
children != null ? /* @__PURE__ */ jsx27("div", { className: "sc-empty-state__actions", children }) : null
|
|
2108
|
+
);
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
// src/components/Skeleton/Skeleton.tsx
|
|
2112
|
+
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
2113
|
+
function Skeleton({
|
|
2114
|
+
variant = "text",
|
|
2115
|
+
width,
|
|
2116
|
+
height,
|
|
2117
|
+
lines = 1,
|
|
2118
|
+
still = false,
|
|
2119
|
+
className,
|
|
2120
|
+
style,
|
|
2121
|
+
...rest
|
|
2122
|
+
}) {
|
|
2123
|
+
const size = {
|
|
2124
|
+
...style,
|
|
2125
|
+
...width !== void 0 ? { inlineSize: width } : {},
|
|
2126
|
+
...height !== void 0 ? { blockSize: height } : {}
|
|
2127
|
+
};
|
|
2128
|
+
if (variant === "text" && lines > 1) {
|
|
2129
|
+
return /* @__PURE__ */ jsx28("span", { className: cx("sc-skeleton-lines", className), "aria-hidden": "true", style, ...rest, children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx28(
|
|
2130
|
+
"span",
|
|
2131
|
+
{
|
|
2132
|
+
className: "sc-skeleton",
|
|
2133
|
+
"data-variant": "text",
|
|
2134
|
+
"data-still": still || void 0,
|
|
2135
|
+
"data-last": i === lines - 1 || void 0,
|
|
2136
|
+
style: width !== void 0 ? { inlineSize: width } : void 0
|
|
2137
|
+
},
|
|
2138
|
+
i
|
|
2139
|
+
)) });
|
|
2140
|
+
}
|
|
2141
|
+
return /* @__PURE__ */ jsx28(
|
|
2142
|
+
"span",
|
|
2143
|
+
{
|
|
2144
|
+
className: cx("sc-skeleton", className),
|
|
2145
|
+
"data-variant": variant,
|
|
2146
|
+
"data-still": still || void 0,
|
|
2147
|
+
"aria-hidden": "true",
|
|
2148
|
+
style: size,
|
|
2149
|
+
...rest
|
|
2150
|
+
}
|
|
2151
|
+
);
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
// src/components/FileInput/FileInput.tsx
|
|
2155
|
+
import { useEffect as useEffect4, useId as useId3, useRef as useRef4, useState as useState6 } from "react";
|
|
2156
|
+
|
|
2157
|
+
// src/components/FilePreviewDialog/FilePreviewDialog.tsx
|
|
2158
|
+
import { useEffect as useEffect3, useRef as useRef3, useState as useState5 } from "react";
|
|
2159
|
+
|
|
2160
|
+
// src/components/FileInput/accept.ts
|
|
2161
|
+
function parseAccept(accept) {
|
|
2162
|
+
if (accept == null) return [];
|
|
2163
|
+
const list = typeof accept === "string" ? accept.split(",") : accept;
|
|
2164
|
+
return list.map((entry) => entry.trim().toLowerCase()).filter(Boolean);
|
|
2165
|
+
}
|
|
2166
|
+
function matchesAccept(file, accept) {
|
|
2167
|
+
if (accept.length === 0) return true;
|
|
2168
|
+
const name = file.name.toLowerCase();
|
|
2169
|
+
const type = file.type.toLowerCase();
|
|
2170
|
+
return accept.some((entry) => {
|
|
2171
|
+
if (entry.startsWith(".")) return name.endsWith(entry);
|
|
2172
|
+
if (entry.endsWith("/*")) return type.startsWith(entry.slice(0, -1));
|
|
2173
|
+
return type === entry;
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
var UNITS = { b: 1, kb: 1e3, mb: 1e6, gb: 1e9 };
|
|
2177
|
+
function parseSize(size) {
|
|
2178
|
+
if (size == null) return void 0;
|
|
2179
|
+
if (typeof size === "number") return size;
|
|
2180
|
+
const match = /^\s*(\d+(?:\.\d+)?)\s*(b|kb|mb|gb)\s*$/i.exec(size);
|
|
2181
|
+
if (!match) throw new Error(`FileInput: maxFileSize "${size}" is not a size like "10MB".`);
|
|
2182
|
+
return Math.round(Number(match[1]) * UNITS[match[2].toLowerCase()]);
|
|
2183
|
+
}
|
|
2184
|
+
function formatSize(bytes) {
|
|
2185
|
+
const [unit, base] = bytes >= 1e9 ? ["GB", 1e9] : bytes >= 1e6 ? ["MB", 1e6] : bytes >= 1e3 ? ["KB", 1e3] : ["bytes", 1];
|
|
2186
|
+
const value = bytes / base;
|
|
2187
|
+
return `${Number.isInteger(value) ? value : Number(value.toFixed(1))} ${unit}`;
|
|
2188
|
+
}
|
|
2189
|
+
function formatListSize(bytes) {
|
|
2190
|
+
const n = Math.round(Math.abs(bytes));
|
|
2191
|
+
const trim = (value, decimals) => value.toFixed(decimals).replace(/\.0+$/, "");
|
|
2192
|
+
if (n < 1e3) return `${n} bytes`;
|
|
2193
|
+
if (n < 1e6) return `${Math.floor(n / 1e3)} KB`;
|
|
2194
|
+
if (n < 1e9) return `${trim(n / 1e6, 1)} MB`;
|
|
2195
|
+
return `${trim(n / 1e9, 2)} GB`;
|
|
2196
|
+
}
|
|
2197
|
+
var MIME_NAMES = {
|
|
2198
|
+
"application/pdf": "PDF",
|
|
2199
|
+
"application/msword": "DOC",
|
|
2200
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "DOCX",
|
|
2201
|
+
"application/json": "JSON",
|
|
2202
|
+
"text/plain": "plain text",
|
|
2203
|
+
"text/markdown": "Markdown",
|
|
2204
|
+
"text/csv": "CSV",
|
|
2205
|
+
"image/png": "PNG",
|
|
2206
|
+
"image/jpeg": "JPEG"
|
|
2207
|
+
};
|
|
2208
|
+
function describeAccept(accept) {
|
|
2209
|
+
const names = accept.map((entry) => {
|
|
2210
|
+
if (entry.startsWith(".")) return entry.slice(1).toUpperCase();
|
|
2211
|
+
if (entry.endsWith("/*")) return `any ${entry.slice(0, -2)}`;
|
|
2212
|
+
return MIME_NAMES[entry] ?? entry.split("/").pop().toUpperCase();
|
|
2213
|
+
});
|
|
2214
|
+
const unique = [...new Set(names)];
|
|
2215
|
+
if (unique.length <= 1) return unique[0] ?? "";
|
|
2216
|
+
return `${unique.slice(0, -1).join(", ")} or ${unique.at(-1)}`;
|
|
2217
|
+
}
|
|
2218
|
+
function rejectionMessage(reason, detail) {
|
|
2219
|
+
switch (reason) {
|
|
2220
|
+
case "type":
|
|
2221
|
+
return `${detail.name} is not an accepted file type. Use ${detail.acceptLabel}.`;
|
|
2222
|
+
case "size":
|
|
2223
|
+
return `${detail.name} is ${formatSize(detail.size ?? 0)}, over the ${formatSize(detail.maxFileSize ?? 0)} limit.`;
|
|
2224
|
+
case "count":
|
|
2225
|
+
return detail.maxFiles === 1 ? "Choose one file." : `Up to ${detail.maxFiles} files. Remove one to add another.`;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
function escapeHtml(text) {
|
|
2229
|
+
return text.replace(
|
|
2230
|
+
/[&<>"']/g,
|
|
2231
|
+
(ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[ch]
|
|
2232
|
+
);
|
|
2233
|
+
}
|
|
2234
|
+
var extensionOf = (name) => {
|
|
2235
|
+
const dot = name.lastIndexOf(".");
|
|
2236
|
+
return dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
|
|
2237
|
+
};
|
|
2238
|
+
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set(["txt", "text", "md", "markdown"]);
|
|
2239
|
+
var TEXT_TYPES = /* @__PURE__ */ new Set(["text/plain", "text/markdown", "text/x-markdown"]);
|
|
2240
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "avif", "svg", "bmp"]);
|
|
2241
|
+
var UNDRAWABLE_IMAGE_TYPES = /* @__PURE__ */ new Set(["image/heic", "image/heif", "image/tiff"]);
|
|
2242
|
+
function previewKind(file) {
|
|
2243
|
+
const ext = extensionOf(file.name);
|
|
2244
|
+
const type = file.type.toLowerCase();
|
|
2245
|
+
if (ext === "pdf" || type === "application/pdf") return "pdf";
|
|
2246
|
+
if (TEXT_EXTENSIONS.has(ext) || TEXT_TYPES.has(type)) return "text";
|
|
2247
|
+
if (UNDRAWABLE_IMAGE_TYPES.has(type)) return null;
|
|
2248
|
+
if (IMAGE_EXTENSIONS.has(ext) || type.startsWith("image/")) return "image";
|
|
2249
|
+
return null;
|
|
2250
|
+
}
|
|
2251
|
+
function fileTypeLabel(file) {
|
|
2252
|
+
const ext = extensionOf(file.name);
|
|
2253
|
+
if (ext) return ext.toUpperCase();
|
|
2254
|
+
return MIME_NAMES[file.type.toLowerCase()] ?? (file.type.split("/").pop()?.toUpperCase() || "File");
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
// src/utils/useMediaQuery.ts
|
|
2258
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
2259
|
+
function useMediaQuery(query) {
|
|
2260
|
+
const subscribe = useCallback(
|
|
2261
|
+
(onChange) => {
|
|
2262
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return () => {
|
|
2263
|
+
};
|
|
2264
|
+
const list = window.matchMedia(query);
|
|
2265
|
+
list.addEventListener?.("change", onChange);
|
|
2266
|
+
return () => list.removeEventListener?.("change", onChange);
|
|
2267
|
+
},
|
|
2268
|
+
[query]
|
|
2269
|
+
);
|
|
2270
|
+
return useSyncExternalStore(
|
|
2271
|
+
subscribe,
|
|
2272
|
+
() => typeof window.matchMedia === "function" && window.matchMedia(query).matches,
|
|
2273
|
+
() => false
|
|
2274
|
+
);
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
// src/components/FilePreviewDialog/FilePreviewDialog.tsx
|
|
2278
|
+
import { Fragment as Fragment8, jsx as jsx29, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2279
|
+
var TEXT_LIMIT = 1e6;
|
|
2280
|
+
var NARROW = "(max-width: 48rem)";
|
|
2281
|
+
function FilePreviewDialog({ file, open, onOpenChange, finalFocus }) {
|
|
2282
|
+
const kind = file ? previewKind(file) : null;
|
|
2283
|
+
const narrow = useMediaQuery(NARROW);
|
|
2284
|
+
const pdfInTab = kind === "pdf" && narrow;
|
|
2285
|
+
return /* @__PURE__ */ jsx29(Dialog.Root, { open, onOpenChange, children: /* @__PURE__ */ jsxs24(
|
|
2286
|
+
Dialog.Content,
|
|
2287
|
+
{
|
|
2288
|
+
size: "lg",
|
|
2289
|
+
className: "sc-file-preview",
|
|
2290
|
+
"data-kind": kind ?? "none",
|
|
2291
|
+
finalFocus,
|
|
2292
|
+
children: [
|
|
2293
|
+
/* @__PURE__ */ jsx29(Dialog.Close, {}),
|
|
2294
|
+
file ? /* @__PURE__ */ jsxs24(Fragment8, { children: [
|
|
2295
|
+
/* @__PURE__ */ jsx29(Dialog.Title, { children: file.name }),
|
|
2296
|
+
/* @__PURE__ */ jsxs24(Dialog.Description, { children: [
|
|
2297
|
+
fileTypeLabel(file),
|
|
2298
|
+
", ",
|
|
2299
|
+
formatListSize(file.size)
|
|
2300
|
+
] }),
|
|
2301
|
+
/* @__PURE__ */ jsx29(Dialog.Body, { children: /* @__PURE__ */ jsx29(PreviewBody, { file, kind, open, pdfInTab }) })
|
|
2302
|
+
] }) : /* @__PURE__ */ jsx29(Dialog.Title, { children: "Preview" })
|
|
2303
|
+
]
|
|
2304
|
+
}
|
|
2305
|
+
) });
|
|
2306
|
+
}
|
|
2307
|
+
function PreviewBody({
|
|
2308
|
+
file,
|
|
2309
|
+
kind,
|
|
2310
|
+
open,
|
|
2311
|
+
pdfInTab
|
|
2312
|
+
}) {
|
|
2313
|
+
const frameRef = useRef3(null);
|
|
2314
|
+
const imageRef = useRef3(null);
|
|
2315
|
+
const linkRef = useRef3(null);
|
|
2316
|
+
const [text, setText] = useState5(null);
|
|
2317
|
+
useEffect3(() => {
|
|
2318
|
+
if (!open || kind !== "pdf" && kind !== "image") return void 0;
|
|
2319
|
+
const url = URL.createObjectURL(kind === "pdf" ? new Blob([file], { type: "application/pdf" }) : file);
|
|
2320
|
+
if (frameRef.current) frameRef.current.src = url;
|
|
2321
|
+
if (imageRef.current) imageRef.current.src = url;
|
|
2322
|
+
if (linkRef.current) linkRef.current.href = url;
|
|
2323
|
+
return () => URL.revokeObjectURL(url);
|
|
2324
|
+
}, [open, file, kind, pdfInTab]);
|
|
2325
|
+
useEffect3(() => {
|
|
2326
|
+
if (!open || kind !== "text") return void 0;
|
|
2327
|
+
let cancelled = false;
|
|
2328
|
+
void file.slice(0, TEXT_LIMIT).text().then((value) => {
|
|
2329
|
+
if (!cancelled) setText({ file, value });
|
|
2330
|
+
});
|
|
2331
|
+
return () => {
|
|
2332
|
+
cancelled = true;
|
|
2333
|
+
};
|
|
2334
|
+
}, [open, file, kind]);
|
|
2335
|
+
if (kind === "pdf") {
|
|
2336
|
+
const link = (
|
|
2337
|
+
// eslint-disable-next-line jsx-a11y/anchor-is-valid -- the effect above sets href to the object URL on mount
|
|
2338
|
+
/* @__PURE__ */ jsxs24(
|
|
2339
|
+
"a",
|
|
2340
|
+
{
|
|
2341
|
+
ref: linkRef,
|
|
2342
|
+
className: "sc-button",
|
|
2343
|
+
"data-variant": pdfInTab ? "primary" : "secondary",
|
|
2344
|
+
"data-size": "md",
|
|
2345
|
+
target: "_blank",
|
|
2346
|
+
rel: "noopener",
|
|
2347
|
+
children: [
|
|
2348
|
+
"Open in a new tab",
|
|
2349
|
+
/* @__PURE__ */ jsx29(ExternalLinkIcon, {})
|
|
2350
|
+
]
|
|
2351
|
+
}
|
|
2352
|
+
)
|
|
2353
|
+
);
|
|
2354
|
+
return pdfInTab ? /* @__PURE__ */ jsxs24("div", { className: "sc-file-preview__tab", children: [
|
|
2355
|
+
/* @__PURE__ */ jsx29("p", { className: "sc-file-preview__note", children: "On a small screen the PDF reads best in its own tab." }),
|
|
2356
|
+
link
|
|
2357
|
+
] }) : /* @__PURE__ */ jsxs24(Fragment8, { children: [
|
|
2358
|
+
/* @__PURE__ */ jsx29("iframe", { ref: frameRef, className: "sc-file-preview__frame", title: `Preview of ${file.name}` }),
|
|
2359
|
+
/* @__PURE__ */ jsx29("div", { className: "sc-file-preview__actions", children: link })
|
|
2360
|
+
] });
|
|
2361
|
+
}
|
|
2362
|
+
if (kind === "text") {
|
|
2363
|
+
const value = text?.file === file ? text.value : null;
|
|
2364
|
+
return /* @__PURE__ */ jsxs24(Fragment8, { children: [
|
|
2365
|
+
/* @__PURE__ */ jsx29(
|
|
2366
|
+
"pre",
|
|
2367
|
+
{
|
|
2368
|
+
className: "sc-file-preview__text",
|
|
2369
|
+
role: "region",
|
|
2370
|
+
tabIndex: 0,
|
|
2371
|
+
"aria-label": `Contents of ${file.name}`,
|
|
2372
|
+
"aria-busy": value == null || void 0,
|
|
2373
|
+
children: value
|
|
2374
|
+
}
|
|
2375
|
+
),
|
|
2376
|
+
file.size > TEXT_LIMIT ? /* @__PURE__ */ jsxs24("p", { className: "sc-file-preview__note", children: [
|
|
2377
|
+
"Showing the first ",
|
|
2378
|
+
formatSize(TEXT_LIMIT),
|
|
2379
|
+
"."
|
|
2380
|
+
] }) : null
|
|
2381
|
+
] });
|
|
2382
|
+
}
|
|
2383
|
+
if (kind === "image") {
|
|
2384
|
+
return /* @__PURE__ */ jsx29("img", { ref: imageRef, className: "sc-file-preview__image", alt: file.name });
|
|
2385
|
+
}
|
|
2386
|
+
return /* @__PURE__ */ jsxs24("p", { className: "sc-file-preview__note", children: [
|
|
2387
|
+
"There is no preview for ",
|
|
2388
|
+
fileTypeLabel(file),
|
|
2389
|
+
" files."
|
|
2390
|
+
] });
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
// src/components/FileInput/FileInput.tsx
|
|
2394
|
+
import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
2395
|
+
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>';
|
|
2396
|
+
var sameFiles = (a, b) => a.length === b.length && a.every((file, i) => file === b[i]);
|
|
2397
|
+
function FileInput({
|
|
2398
|
+
label,
|
|
2399
|
+
hideLabel = false,
|
|
2400
|
+
description,
|
|
2401
|
+
error,
|
|
2402
|
+
invalid = false,
|
|
2403
|
+
required = false,
|
|
2404
|
+
disabled = false,
|
|
2405
|
+
name,
|
|
2406
|
+
size = "md",
|
|
2407
|
+
className,
|
|
2408
|
+
accept,
|
|
2409
|
+
acceptLabel,
|
|
2410
|
+
maxFileSize,
|
|
2411
|
+
multiple = false,
|
|
2412
|
+
maxFiles,
|
|
2413
|
+
files,
|
|
2414
|
+
defaultFiles,
|
|
2415
|
+
onFilesChange,
|
|
2416
|
+
idleLabel,
|
|
2417
|
+
browseLabel = "browse",
|
|
2418
|
+
preview = true
|
|
2419
|
+
}) {
|
|
2420
|
+
const id = useId3();
|
|
2421
|
+
const labelId = `${id}label`;
|
|
2422
|
+
const descriptionId = `${id}description`;
|
|
2423
|
+
const messagesId = `${id}messages`;
|
|
2424
|
+
const controlled = files !== void 0;
|
|
2425
|
+
const [uncontrolledFiles, setUncontrolledFiles] = useState6(defaultFiles ?? []);
|
|
2426
|
+
const current = controlled ? files : uncontrolledFiles;
|
|
2427
|
+
const [rejections, setRejections] = useState6([]);
|
|
2428
|
+
const [inputId, setInputId] = useState6();
|
|
2429
|
+
const [previewFile, setPreviewFile] = useState6(null);
|
|
2430
|
+
const [previewOpen, setPreviewOpen] = useState6(false);
|
|
2431
|
+
const previewTriggerRef = useRef4(null);
|
|
2432
|
+
const [pondVersion, setPondVersion] = useState6(0);
|
|
2433
|
+
const hostRef = useRef4(null);
|
|
2434
|
+
const pondRef = useRef4(null);
|
|
2435
|
+
const moduleRef = useRef4(null);
|
|
2436
|
+
const patchRef = useRef4(() => {
|
|
2437
|
+
});
|
|
2438
|
+
const settledRef = useRef4(current);
|
|
2439
|
+
const targetRef = useRef4(null);
|
|
2440
|
+
const acceptList = parseAccept(accept);
|
|
2441
|
+
const acceptAttr = acceptList.join(",");
|
|
2442
|
+
const maxBytes = parseSize(maxFileSize);
|
|
2443
|
+
const messages = [...rejections, ...error != null ? [error] : []];
|
|
2444
|
+
const isInvalid = invalid || messages.length > 0;
|
|
2445
|
+
const idleText = idleLabel ?? (multiple ? "Drop files here or" : current.length > 0 ? "Drop another file to replace it, or" : "Drop a file here or");
|
|
2446
|
+
const live = {
|
|
2447
|
+
acceptList,
|
|
2448
|
+
acceptLabel: acceptLabel ?? describeAccept(acceptList),
|
|
2449
|
+
maxBytes,
|
|
2450
|
+
maxFiles: multiple ? maxFiles : 1,
|
|
2451
|
+
multiple,
|
|
2452
|
+
current,
|
|
2453
|
+
controlled,
|
|
2454
|
+
onFilesChange,
|
|
2455
|
+
labelId,
|
|
2456
|
+
describedBy: [description != null ? descriptionId : null, messages.length > 0 ? messagesId : null],
|
|
2457
|
+
isInvalid,
|
|
2458
|
+
acceptAttr,
|
|
2459
|
+
preview: preview && !disabled,
|
|
2460
|
+
openPreview: (file, trigger) => {
|
|
2461
|
+
previewTriggerRef.current = trigger;
|
|
2462
|
+
setPreviewFile(file);
|
|
2463
|
+
setPreviewOpen(true);
|
|
2464
|
+
}
|
|
2465
|
+
};
|
|
2466
|
+
const liveRef = useRef4(live);
|
|
2467
|
+
useEffect4(() => {
|
|
2468
|
+
liveRef.current = live;
|
|
2469
|
+
});
|
|
2470
|
+
useEffect4(() => {
|
|
2471
|
+
let cancelled = false;
|
|
2472
|
+
let pond = null;
|
|
2473
|
+
let observer = null;
|
|
2474
|
+
const host = hostRef.current;
|
|
2475
|
+
if (!host) return void 0;
|
|
2476
|
+
const reject = (reason, file) => {
|
|
2477
|
+
const l = liveRef.current;
|
|
2478
|
+
const message = rejectionMessage(reason, {
|
|
2479
|
+
name: file?.name,
|
|
2480
|
+
size: file?.size,
|
|
2481
|
+
acceptLabel: l.acceptLabel,
|
|
2482
|
+
maxFileSize: l.maxBytes,
|
|
2483
|
+
maxFiles: l.maxFiles
|
|
2484
|
+
});
|
|
2485
|
+
setRejections((list) => list.includes(message) ? list : [...list, message]);
|
|
2486
|
+
if (file && targetRef.current) {
|
|
2487
|
+
targetRef.current = targetRef.current.filter((f) => f !== file);
|
|
2488
|
+
queueMicrotask(emit);
|
|
2489
|
+
}
|
|
2490
|
+
};
|
|
2491
|
+
const startAttempt = () => setRejections((list) => list.length ? [] : list);
|
|
2492
|
+
let removeIntent = false;
|
|
2493
|
+
const acceptedIds = /* @__PURE__ */ new Set();
|
|
2494
|
+
const noteRemove = (event) => {
|
|
2495
|
+
if (event.target?.closest?.(".filepond--action-remove-item")) removeIntent = true;
|
|
2496
|
+
};
|
|
2497
|
+
const onPreviewClick = (event) => {
|
|
2498
|
+
const button = event.target?.closest?.(
|
|
2499
|
+
".sc-file-input__preview"
|
|
2500
|
+
);
|
|
2501
|
+
const file = button?.dataset.fileId ? pond?.getFile(button.dataset.fileId)?.file : null;
|
|
2502
|
+
if (!button || !(file instanceof File)) return;
|
|
2503
|
+
event.stopPropagation();
|
|
2504
|
+
liveRef.current.openPreview(file, button);
|
|
2505
|
+
};
|
|
2506
|
+
const emit = () => {
|
|
2507
|
+
const mod = moduleRef.current;
|
|
2508
|
+
if (!pond || !mod) return;
|
|
2509
|
+
const idle = pond.getFiles().filter((item) => item.status === mod.FileStatus.IDLE).map((item) => item.file);
|
|
2510
|
+
const accepted = liveRef.current.multiple ? idle : idle.slice(-1);
|
|
2511
|
+
const target = targetRef.current;
|
|
2512
|
+
if (target) {
|
|
2513
|
+
if (!sameFiles(accepted, target)) return;
|
|
2514
|
+
targetRef.current = null;
|
|
2515
|
+
settledRef.current = accepted;
|
|
2516
|
+
if (!sameFiles(accepted, liveRef.current.current)) {
|
|
2517
|
+
if (!liveRef.current.controlled) setUncontrolledFiles(accepted);
|
|
2518
|
+
liveRef.current.onFilesChange?.(accepted);
|
|
2519
|
+
}
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
if (sameFiles(accepted, settledRef.current)) return;
|
|
2523
|
+
settledRef.current = accepted;
|
|
2524
|
+
if (!liveRef.current.controlled) setUncontrolledFiles(accepted);
|
|
2525
|
+
liveRef.current.onFilesChange?.(accepted);
|
|
2526
|
+
};
|
|
2527
|
+
const patch = () => {
|
|
2528
|
+
if (!pond) return;
|
|
2529
|
+
const l = liveRef.current;
|
|
2530
|
+
const root = pond.element;
|
|
2531
|
+
if (!root) return;
|
|
2532
|
+
const set = (el, attr, value) => {
|
|
2533
|
+
if (!el || el.getAttribute(attr) === value) return;
|
|
2534
|
+
if (value == null) el.removeAttribute(attr);
|
|
2535
|
+
else el.setAttribute(attr, value);
|
|
2536
|
+
};
|
|
2537
|
+
const input = root.querySelector("input.filepond--browser");
|
|
2538
|
+
const dropLabel = root.querySelector(".filepond--drop-label label");
|
|
2539
|
+
set(input, "aria-labelledby", l.labelId);
|
|
2540
|
+
set(input, "aria-describedby", [dropLabel?.id, ...l.describedBy].filter(Boolean).join(" ") || null);
|
|
2541
|
+
set(input, "aria-invalid", l.isInvalid ? "true" : null);
|
|
2542
|
+
set(input, "accept", l.acceptAttr || null);
|
|
2543
|
+
set(input, "multiple", l.multiple ? "" : null);
|
|
2544
|
+
set(root.querySelector(".filepond--label-action"), "tabindex", null);
|
|
2545
|
+
for (const item of root.querySelectorAll(".filepond--item")) {
|
|
2546
|
+
const fileName = item.querySelector(".filepond--file-info-main")?.textContent?.trim();
|
|
2547
|
+
const remove = item.querySelector(".filepond--action-remove-item");
|
|
2548
|
+
if (fileName) set(remove, "aria-label", `Remove ${fileName}`);
|
|
2549
|
+
patchPreview(item, remove);
|
|
2550
|
+
}
|
|
2551
|
+
setInputId(input?.id || void 0);
|
|
2552
|
+
};
|
|
2553
|
+
const patchPreview = (item, remove) => {
|
|
2554
|
+
const row = item.querySelector(".filepond--file");
|
|
2555
|
+
if (!row) return;
|
|
2556
|
+
let button = row.querySelector(":scope > .sc-file-input__preview");
|
|
2557
|
+
const id2 = item.id.replace(/^filepond--item-/, "");
|
|
2558
|
+
const file = pond?.getFile(id2)?.file;
|
|
2559
|
+
if (!liveRef.current.preview || !(file instanceof File) || previewKind(file) == null) {
|
|
2560
|
+
button?.remove();
|
|
2561
|
+
return;
|
|
2562
|
+
}
|
|
2563
|
+
if (!button) {
|
|
2564
|
+
button = document.createElement("button");
|
|
2565
|
+
button.type = "button";
|
|
2566
|
+
button.className = "sc-file-input__preview";
|
|
2567
|
+
row.insertBefore(button, remove ?? row.firstChild);
|
|
2568
|
+
}
|
|
2569
|
+
if (button.dataset.fileId !== id2) button.dataset.fileId = id2;
|
|
2570
|
+
if (button.textContent !== file.name) button.textContent = file.name;
|
|
2571
|
+
const name2 = `Preview ${file.name}`;
|
|
2572
|
+
if (button.getAttribute("aria-label") !== name2) button.setAttribute("aria-label", name2);
|
|
2573
|
+
};
|
|
2574
|
+
void import("filepond").then((mod) => {
|
|
2575
|
+
if (cancelled || !mod.supported()) return;
|
|
2576
|
+
moduleRef.current = mod;
|
|
2577
|
+
const options = {
|
|
2578
|
+
credits: false,
|
|
2579
|
+
allowPaste: false,
|
|
2580
|
+
allowReorder: false,
|
|
2581
|
+
allowProcess: false,
|
|
2582
|
+
allowRevert: false,
|
|
2583
|
+
instantUpload: false,
|
|
2584
|
+
dropOnPage: false,
|
|
2585
|
+
// Always multi: FilePond's own single mode replaces the current file *before* validating the new
|
|
2586
|
+
// one, so a rejected file would discard a good one. Replacement happens in `addfile` instead.
|
|
2587
|
+
allowMultiple: true,
|
|
2588
|
+
allowReplace: false,
|
|
2589
|
+
itemInsertLocation: "after",
|
|
2590
|
+
fileSizeBase: 1e3,
|
|
2591
|
+
iconRemove: REMOVE_ICON,
|
|
2592
|
+
labelButtonRemoveItem: "Remove",
|
|
2593
|
+
styleButtonRemoveItemPosition: "right",
|
|
2594
|
+
beforeAddFile: (item) => {
|
|
2595
|
+
const l = liveRef.current;
|
|
2596
|
+
const file = item.file;
|
|
2597
|
+
if (!matchesAccept(file, l.acceptList)) return reject("type", file), false;
|
|
2598
|
+
if (l.maxBytes != null && file.size > l.maxBytes) return reject("size", file), false;
|
|
2599
|
+
return true;
|
|
2600
|
+
}
|
|
2601
|
+
};
|
|
2602
|
+
pond = mod.create(options);
|
|
2603
|
+
const root = pond.element;
|
|
2604
|
+
if (!root) return;
|
|
2605
|
+
host.appendChild(root);
|
|
2606
|
+
pondRef.current = pond;
|
|
2607
|
+
patchRef.current = patch;
|
|
2608
|
+
pond.on("addfile", (error2, added) => {
|
|
2609
|
+
if (!error2) acceptedIds.add(added.id);
|
|
2610
|
+
if (!error2 && !liveRef.current.multiple) {
|
|
2611
|
+
for (const other of pond?.getFiles() ?? []) if (other.id !== added.id) pond?.removeFile(other.id);
|
|
2612
|
+
}
|
|
2613
|
+
emit();
|
|
2614
|
+
});
|
|
2615
|
+
pond.on("removefile", (_error, removed) => {
|
|
2616
|
+
const active = document.activeElement;
|
|
2617
|
+
const inRemovedRow = active?.closest(".filepond--item")?.id === `filepond--item-${removed.id}`;
|
|
2618
|
+
if (inRemovedRow || removeIntent && (active == null || active === document.body))
|
|
2619
|
+
root.querySelector("input.filepond--browser")?.focus();
|
|
2620
|
+
removeIntent = false;
|
|
2621
|
+
if (acceptedIds.delete(removed.id)) startAttempt();
|
|
2622
|
+
emit();
|
|
2623
|
+
});
|
|
2624
|
+
pond.on("updatefiles", emit);
|
|
2625
|
+
pond.on("warning", (warning) => {
|
|
2626
|
+
if (warning?.body === "Max files") reject("count");
|
|
2627
|
+
});
|
|
2628
|
+
observer = new MutationObserver(patch);
|
|
2629
|
+
observer.observe(root, {
|
|
2630
|
+
subtree: true,
|
|
2631
|
+
childList: true,
|
|
2632
|
+
attributes: true,
|
|
2633
|
+
attributeFilter: ["tabindex", "aria-labelledby", "aria-describedby", "accept", "id", "multiple"]
|
|
2634
|
+
});
|
|
2635
|
+
host.addEventListener("drop", startAttempt, true);
|
|
2636
|
+
host.addEventListener("change", startAttempt, true);
|
|
2637
|
+
host.addEventListener("click", noteRemove, true);
|
|
2638
|
+
host.addEventListener("click", onPreviewClick);
|
|
2639
|
+
settledRef.current = [];
|
|
2640
|
+
setPondVersion((v) => v + 1);
|
|
2641
|
+
});
|
|
2642
|
+
return () => {
|
|
2643
|
+
cancelled = true;
|
|
2644
|
+
host.removeEventListener("drop", startAttempt, true);
|
|
2645
|
+
host.removeEventListener("change", startAttempt, true);
|
|
2646
|
+
host.removeEventListener("click", noteRemove, true);
|
|
2647
|
+
host.removeEventListener("click", onPreviewClick);
|
|
2648
|
+
observer?.disconnect();
|
|
2649
|
+
if (pond) {
|
|
2650
|
+
pond.element?.remove();
|
|
2651
|
+
pond.destroy();
|
|
2652
|
+
}
|
|
2653
|
+
pondRef.current = null;
|
|
2654
|
+
patchRef.current = () => {
|
|
2655
|
+
};
|
|
2656
|
+
};
|
|
2657
|
+
}, []);
|
|
2658
|
+
useEffect4(() => {
|
|
2659
|
+
const pond = pondRef.current;
|
|
2660
|
+
if (!pond) return;
|
|
2661
|
+
pond.setOptions({
|
|
2662
|
+
name: name ?? "",
|
|
2663
|
+
storeAsFile: name != null,
|
|
2664
|
+
disabled,
|
|
2665
|
+
required,
|
|
2666
|
+
maxFiles: multiple ? maxFiles ?? null : null,
|
|
2667
|
+
allowRemove: !disabled,
|
|
2668
|
+
labelIdle: `${escapeHtml(idleText)} <span class="filepond--label-action">${escapeHtml(browseLabel)}</span>`
|
|
2669
|
+
});
|
|
2670
|
+
patchRef.current();
|
|
2671
|
+
}, [
|
|
2672
|
+
pondVersion,
|
|
2673
|
+
name,
|
|
2674
|
+
disabled,
|
|
2675
|
+
required,
|
|
2676
|
+
multiple,
|
|
2677
|
+
maxFiles,
|
|
2678
|
+
idleText,
|
|
2679
|
+
browseLabel,
|
|
2680
|
+
labelId,
|
|
2681
|
+
acceptAttr,
|
|
2682
|
+
isInvalid,
|
|
2683
|
+
description,
|
|
2684
|
+
messages.length,
|
|
2685
|
+
preview
|
|
2686
|
+
]);
|
|
2687
|
+
useEffect4(() => {
|
|
2688
|
+
const pond = pondRef.current;
|
|
2689
|
+
const mod = moduleRef.current;
|
|
2690
|
+
if (!pond || !mod) return;
|
|
2691
|
+
const items = pond.getFiles();
|
|
2692
|
+
const idle = items.filter((item) => item.status === mod.FileStatus.IDLE);
|
|
2693
|
+
const inPond = idle.map((item) => item.file);
|
|
2694
|
+
if (sameFiles(inPond, current)) {
|
|
2695
|
+
settledRef.current = current;
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2698
|
+
targetRef.current = current;
|
|
2699
|
+
for (const item of idle) if (!current.includes(item.file)) pond.removeFile(item.id);
|
|
2700
|
+
const toAdd = current.filter((file) => !inPond.includes(file));
|
|
2701
|
+
if (toAdd.length > 0) void pond.addFiles(toAdd);
|
|
2702
|
+
}, [current, pondVersion]);
|
|
2703
|
+
const ready = pondVersion > 0;
|
|
2704
|
+
return /* @__PURE__ */ jsxs25(
|
|
2705
|
+
"div",
|
|
2706
|
+
{
|
|
2707
|
+
className: cx("sc-field", "sc-file-input-field", className),
|
|
2708
|
+
"data-size": size,
|
|
2709
|
+
"data-disabled": disabled ? "" : void 0,
|
|
2710
|
+
"data-invalid": isInvalid ? "" : void 0,
|
|
2711
|
+
children: [
|
|
2712
|
+
/* @__PURE__ */ jsxs25(
|
|
2713
|
+
"label",
|
|
2714
|
+
{
|
|
2715
|
+
id: labelId,
|
|
2716
|
+
htmlFor: inputId,
|
|
2717
|
+
className: cx("sc-field__label", hideLabel && "sc-visually-hidden"),
|
|
2718
|
+
children: [
|
|
2719
|
+
label,
|
|
2720
|
+
required ? /* @__PURE__ */ jsx30("span", { className: "sc-field__required", "aria-hidden": "true", children: "*" }) : null
|
|
2721
|
+
]
|
|
2722
|
+
}
|
|
2723
|
+
),
|
|
2724
|
+
/* @__PURE__ */ jsxs25(
|
|
2725
|
+
"div",
|
|
2726
|
+
{
|
|
2727
|
+
className: "sc-file-input",
|
|
2728
|
+
"data-ready": ready ? "" : void 0,
|
|
2729
|
+
"data-disabled": disabled ? "" : void 0,
|
|
2730
|
+
"data-invalid": isInvalid ? "" : void 0,
|
|
2731
|
+
"data-multiple": multiple ? "" : void 0,
|
|
2732
|
+
children: [
|
|
2733
|
+
ready ? null : (
|
|
2734
|
+
// Server render and first paint: the same drop zone, inert until FilePond takes over.
|
|
2735
|
+
/* @__PURE__ */ jsxs25("div", { className: "sc-file-input__placeholder", "aria-hidden": "true", children: [
|
|
2736
|
+
idleText,
|
|
2737
|
+
" ",
|
|
2738
|
+
/* @__PURE__ */ jsx30("span", { className: "sc-file-input__browse", children: browseLabel })
|
|
2739
|
+
] })
|
|
2740
|
+
),
|
|
2741
|
+
/* @__PURE__ */ jsx30("div", { ref: hostRef, className: "sc-file-input__pond" })
|
|
2742
|
+
]
|
|
2743
|
+
}
|
|
2744
|
+
),
|
|
2745
|
+
description != null ? /* @__PURE__ */ jsx30("p", { id: descriptionId, className: "sc-field__description", children: description }) : null,
|
|
2746
|
+
/* @__PURE__ */ jsx30("div", { id: messagesId, className: "sc-file-input__messages", "aria-live": "polite", children: messages.map((message, i) => /* @__PURE__ */ jsx30("p", { className: "sc-field__error", children: message }, i)) }),
|
|
2747
|
+
previewFile ? /* @__PURE__ */ jsx30(
|
|
2748
|
+
FilePreviewDialog,
|
|
2749
|
+
{
|
|
2750
|
+
file: previewFile,
|
|
2751
|
+
open: previewOpen,
|
|
2752
|
+
onOpenChange: setPreviewOpen,
|
|
2753
|
+
finalFocus: () => {
|
|
2754
|
+
const trigger = previewTriggerRef.current;
|
|
2755
|
+
if (trigger?.isConnected) return trigger;
|
|
2756
|
+
return hostRef.current?.querySelector("input.filepond--browser") ?? true;
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
) : null
|
|
2760
|
+
]
|
|
2761
|
+
}
|
|
2762
|
+
);
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
// src/components/PriorityNav/PriorityNav.tsx
|
|
2766
|
+
import {
|
|
2767
|
+
useEffect as useEffect5,
|
|
2768
|
+
useId as useId4,
|
|
2769
|
+
useLayoutEffect as useLayoutEffect2,
|
|
2770
|
+
useRef as useRef5,
|
|
2771
|
+
useState as useState7
|
|
2772
|
+
} from "react";
|
|
2773
|
+
|
|
2774
|
+
// src/components/PriorityNav/fit.ts
|
|
2775
|
+
var EPSILON = 0.5;
|
|
2776
|
+
function rowWidth(widths, gap) {
|
|
2777
|
+
let total = 0;
|
|
2778
|
+
for (const w of widths) total += w;
|
|
2779
|
+
return widths.length > 1 ? total + gap * (widths.length - 1) : total;
|
|
2780
|
+
}
|
|
2781
|
+
function fitCount({ widths, current, available, more, gap }) {
|
|
2782
|
+
const n = widths.length;
|
|
2783
|
+
const hasCurrent = current >= 0 && current < n;
|
|
2784
|
+
const others = hasCurrent ? n - 1 : n;
|
|
2785
|
+
if (rowWidth(widths, gap) <= available + EPSILON) return others;
|
|
2786
|
+
let used = more + (hasCurrent ? widths[current] + gap : 0);
|
|
2787
|
+
let count = 0;
|
|
2788
|
+
for (let i = 0; i < n; i++) {
|
|
2789
|
+
if (i === current) continue;
|
|
2790
|
+
const next = used + widths[i] + gap;
|
|
2791
|
+
if (next > available + EPSILON) break;
|
|
2792
|
+
used = next;
|
|
2793
|
+
count++;
|
|
2794
|
+
}
|
|
2795
|
+
return count;
|
|
2796
|
+
}
|
|
2797
|
+
function inlineFlags(length, current, count) {
|
|
2798
|
+
const flags = [];
|
|
2799
|
+
let seen = 0;
|
|
2800
|
+
for (let i = 0; i < length; i++) {
|
|
2801
|
+
if (i === current) flags.push(true);
|
|
2802
|
+
else flags.push(seen++ < count);
|
|
2803
|
+
}
|
|
2804
|
+
return flags;
|
|
2805
|
+
}
|
|
2806
|
+
function isOverflowing({ widths, gap, available, was, hysteresis }) {
|
|
2807
|
+
const total = rowWidth(widths, gap);
|
|
2808
|
+
return was ? total + Math.max(0, hysteresis) > available + EPSILON : total > available + EPSILON;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
// src/components/PriorityNav/place.ts
|
|
2812
|
+
var clamp = (value, min, max) => Math.max(min, Math.min(value, max));
|
|
2813
|
+
function placePanel({ anchor, panel, viewport, gutter, offset, rtl = false }) {
|
|
2814
|
+
const endAligned = rtl ? anchor.left : anchor.right - panel.width;
|
|
2815
|
+
const startAligned = rtl ? anchor.right - panel.width : anchor.left;
|
|
2816
|
+
const fitsX = (x2) => x2 >= gutter && x2 + panel.width <= viewport.width - gutter;
|
|
2817
|
+
const x = fitsX(endAligned) ? endAligned : fitsX(startAligned) ? startAligned : endAligned;
|
|
2818
|
+
const left = clamp(x, gutter, Math.max(gutter, viewport.width - gutter - panel.width));
|
|
2819
|
+
const below = anchor.bottom + offset;
|
|
2820
|
+
const above = anchor.top - offset - panel.height;
|
|
2821
|
+
const fitsBelow = below + panel.height <= viewport.height - gutter;
|
|
2822
|
+
const top = fitsBelow || above < gutter ? below : above;
|
|
2823
|
+
return { left, top };
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
// src/components/PriorityNav/PriorityNav.tsx
|
|
2827
|
+
import { Fragment as Fragment9, jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2828
|
+
var defaultCountLabel2 = (n) => n === 1 ? "1 link" : `${n} links`;
|
|
2829
|
+
var defaultLink = ({ children, ...props }) => /* @__PURE__ */ jsx31("a", { ...props, children });
|
|
2830
|
+
var keyOf = (item) => item.id ?? item.href;
|
|
2831
|
+
var badgeOf = (item) => item.badge === "dot" ? "dot" : typeof item.badge === "number" && item.badge > 0 && Number.isFinite(item.badge) ? item.badge : null;
|
|
2832
|
+
var badgeTextOf = (item) => {
|
|
2833
|
+
const badge = badgeOf(item);
|
|
2834
|
+
if (badge === null) return null;
|
|
2835
|
+
return item.badgeLabel ?? (badge === "dot" ? null : String(badge));
|
|
2836
|
+
};
|
|
2837
|
+
function Badge2({ value }) {
|
|
2838
|
+
return /* @__PURE__ */ jsx31("span", { className: "sc-priority-nav__badge", "data-kind": value === "dot" ? "dot" : "count", "aria-hidden": "true", children: value === "dot" ? null : value });
|
|
2839
|
+
}
|
|
2840
|
+
var supportsAnchor = () => typeof CSS !== "undefined" && typeof CSS.supports === "function" && CSS.supports("anchor-name: --a");
|
|
2841
|
+
var supportsPopover = (el) => typeof el.showPopover === "function";
|
|
2842
|
+
function signatureOf(items) {
|
|
2843
|
+
return items.map((item) => {
|
|
2844
|
+
const text = typeof item.label === "string" || typeof item.label === "number" ? item.label : "";
|
|
2845
|
+
return `${keyOf(item)}${text}${badgeOf(item) ?? ""}`;
|
|
2846
|
+
}).join("");
|
|
2847
|
+
}
|
|
2848
|
+
function PriorityNav({
|
|
2849
|
+
items,
|
|
2850
|
+
moreLabel = "More",
|
|
2851
|
+
moreCountLabel = defaultCountLabel2,
|
|
2852
|
+
renderLink = defaultLink,
|
|
2853
|
+
onOverflowChange,
|
|
2854
|
+
overflowHysteresis = 0,
|
|
2855
|
+
className,
|
|
2856
|
+
style,
|
|
2857
|
+
...rest
|
|
2858
|
+
}) {
|
|
2859
|
+
const signature = signatureOf(items);
|
|
2860
|
+
const current = items.findIndex((item) => item.current);
|
|
2861
|
+
const [fit, setFit] = useState7({ signature: null, current: -1, count: 0, overflowing: false });
|
|
2862
|
+
const [open, setOpen] = useState7(false);
|
|
2863
|
+
const panelId = useId4();
|
|
2864
|
+
const listRef = useRef5(null);
|
|
2865
|
+
const moreRef = useRef5(null);
|
|
2866
|
+
const toggleRef = useRef5(null);
|
|
2867
|
+
const panelRef = useRef5(null);
|
|
2868
|
+
const measured = useRef5(null);
|
|
2869
|
+
const currentRef = useRef5(current);
|
|
2870
|
+
const fitRef = useRef5(fit);
|
|
2871
|
+
const hysteresisRef = useRef5(overflowHysteresis);
|
|
2872
|
+
const onOverflowRef = useRef5(onOverflowChange);
|
|
2873
|
+
const solve = (m, cur, was) => ({
|
|
2874
|
+
count: fitCount({ ...m, current: cur }),
|
|
2875
|
+
overflowing: isOverflowing({ ...m, was, hysteresis: hysteresisRef.current })
|
|
2876
|
+
});
|
|
2877
|
+
const measuring = fit.signature !== signature;
|
|
2878
|
+
useLayoutEffect2(() => {
|
|
2879
|
+
currentRef.current = current;
|
|
2880
|
+
fitRef.current = fit;
|
|
2881
|
+
hysteresisRef.current = overflowHysteresis;
|
|
2882
|
+
onOverflowRef.current = onOverflowChange;
|
|
2883
|
+
});
|
|
2884
|
+
useLayoutEffect2(() => {
|
|
2885
|
+
const list = listRef.current;
|
|
2886
|
+
const more = moreRef.current;
|
|
2887
|
+
if (!list || !more) return;
|
|
2888
|
+
if (measuring) {
|
|
2889
|
+
const widths = Array.from(
|
|
2890
|
+
list.querySelectorAll(":scope > .sc-priority-nav__item"),
|
|
2891
|
+
(el) => el.getBoundingClientRect().width
|
|
2892
|
+
);
|
|
2893
|
+
measured.current = {
|
|
2894
|
+
widths,
|
|
2895
|
+
more: more.getBoundingClientRect().width,
|
|
2896
|
+
gap: parseFloat(getComputedStyle(list).columnGap) || 0,
|
|
2897
|
+
available: list.clientWidth
|
|
2898
|
+
};
|
|
2899
|
+
} else if (fit.current === current) return;
|
|
2900
|
+
const m = measured.current;
|
|
2901
|
+
if (!m) return;
|
|
2902
|
+
setFit({ signature, current, ...solve(m, current, fit.overflowing) });
|
|
2903
|
+
}, [measuring, signature, current, fit]);
|
|
2904
|
+
useEffect5(() => {
|
|
2905
|
+
const list = listRef.current;
|
|
2906
|
+
const more = moreRef.current;
|
|
2907
|
+
if (!list || !more || typeof ResizeObserver === "undefined") return;
|
|
2908
|
+
const observer = new ResizeObserver((entries) => {
|
|
2909
|
+
const m = measured.current;
|
|
2910
|
+
if (!m) return;
|
|
2911
|
+
for (const entry of entries) {
|
|
2912
|
+
if (entry.target === list)
|
|
2913
|
+
m.available = entry.contentBoxSize?.[0]?.inlineSize ?? entry.contentRect.width;
|
|
2914
|
+
else {
|
|
2915
|
+
const width = entry.borderBoxSize?.[0]?.inlineSize ?? 0;
|
|
2916
|
+
if (width > 0) m.more = width;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
const prev = fitRef.current;
|
|
2920
|
+
if (prev.signature === null) return;
|
|
2921
|
+
const next = solve(m, currentRef.current, prev.overflowing);
|
|
2922
|
+
if (prev.count !== next.count || prev.overflowing !== next.overflowing) setFit({ ...prev, ...next });
|
|
2923
|
+
});
|
|
2924
|
+
observer.observe(list);
|
|
2925
|
+
observer.observe(more);
|
|
2926
|
+
return () => observer.disconnect();
|
|
2927
|
+
}, []);
|
|
2928
|
+
const reported = useRef5(false);
|
|
2929
|
+
useEffect5(() => {
|
|
2930
|
+
if (reported.current === fit.overflowing) return;
|
|
2931
|
+
reported.current = fit.overflowing;
|
|
2932
|
+
onOverflowRef.current?.(fit.overflowing);
|
|
2933
|
+
}, [fit.overflowing]);
|
|
2934
|
+
useEffect5(() => {
|
|
2935
|
+
const fonts = typeof document === "undefined" ? void 0 : document.fonts;
|
|
2936
|
+
if (!fonts || fonts.status === "loaded") return;
|
|
2937
|
+
let live = true;
|
|
2938
|
+
void fonts.ready.then(() => {
|
|
2939
|
+
if (live) setFit((prev) => ({ ...prev, signature: null }));
|
|
2940
|
+
});
|
|
2941
|
+
return () => {
|
|
2942
|
+
live = false;
|
|
2943
|
+
};
|
|
2944
|
+
}, []);
|
|
2945
|
+
const flags = measuring ? null : inlineFlags(items.length, current, fit.count);
|
|
2946
|
+
const overflow = flags ? items.filter((_, i) => !flags[i]) : [];
|
|
2947
|
+
const expanded = open && overflow.length > 0;
|
|
2948
|
+
const overflowBadges = overflow.map(badgeOf).filter((b) => b !== null);
|
|
2949
|
+
const overflowCount = overflowBadges.reduce((sum, b) => sum + (b === "dot" ? 0 : b), 0);
|
|
2950
|
+
const moreBadge = overflowCount > 0 ? overflowCount : overflowBadges.length > 0 ? "dot" : null;
|
|
2951
|
+
const moreBadgeText = overflow.map(badgeTextOf).filter((text) => text !== null).map((text) => `, ${text}`).join("");
|
|
2952
|
+
useLayoutEffect2(() => {
|
|
2953
|
+
const panel = panelRef.current;
|
|
2954
|
+
if (!panel || !supportsPopover(panel)) return;
|
|
2955
|
+
if (!panel.hasAttribute("popover")) panel.setAttribute("popover", "manual");
|
|
2956
|
+
const shown = panel.matches(":popover-open");
|
|
2957
|
+
if (expanded && !shown) panel.showPopover();
|
|
2958
|
+
else if (!expanded && shown) panel.hidePopover();
|
|
2959
|
+
}, [expanded]);
|
|
2960
|
+
useLayoutEffect2(() => {
|
|
2961
|
+
const panel = panelRef.current;
|
|
2962
|
+
const toggle2 = toggleRef.current;
|
|
2963
|
+
if (!expanded || !panel || !toggle2 || supportsAnchor()) return;
|
|
2964
|
+
const place = () => {
|
|
2965
|
+
const anchor = toggle2.getBoundingClientRect();
|
|
2966
|
+
const box = panel.getBoundingClientRect();
|
|
2967
|
+
const css = getComputedStyle(panel);
|
|
2968
|
+
const { left, top } = placePanel({
|
|
2969
|
+
anchor,
|
|
2970
|
+
panel: { width: box.width, height: box.height },
|
|
2971
|
+
viewport: { width: document.documentElement.clientWidth, height: window.innerHeight },
|
|
2972
|
+
gutter: parseFloat(css.getPropertyValue("--sc-spacing-md")) || 16,
|
|
2973
|
+
offset: parseFloat(css.getPropertyValue("--sc-spacing-2xs")) || 4,
|
|
2974
|
+
rtl: css.direction === "rtl"
|
|
2975
|
+
});
|
|
2976
|
+
panel.style.left = `${left}px`;
|
|
2977
|
+
panel.style.top = `${top}px`;
|
|
2978
|
+
};
|
|
2979
|
+
place();
|
|
2980
|
+
window.addEventListener("resize", place, { passive: true });
|
|
2981
|
+
window.addEventListener("scroll", place, { passive: true, capture: true });
|
|
2982
|
+
return () => {
|
|
2983
|
+
window.removeEventListener("resize", place);
|
|
2984
|
+
window.removeEventListener("scroll", place, { capture: true });
|
|
2985
|
+
panel.style.left = "";
|
|
2986
|
+
panel.style.top = "";
|
|
2987
|
+
};
|
|
2988
|
+
}, [expanded]);
|
|
2989
|
+
useEffect5(() => {
|
|
2990
|
+
if (!expanded) return;
|
|
2991
|
+
const onPointerDown = (event) => {
|
|
2992
|
+
if (!moreRef.current?.contains(event.target)) setOpen(false);
|
|
2993
|
+
};
|
|
2994
|
+
const onKeyDown = (event) => {
|
|
2995
|
+
if (event.key !== "Escape") return;
|
|
2996
|
+
const active = document.activeElement;
|
|
2997
|
+
setOpen(false);
|
|
2998
|
+
if (!active || active === document.body || moreRef.current?.contains(active))
|
|
2999
|
+
toggleRef.current?.focus();
|
|
3000
|
+
};
|
|
3001
|
+
document.addEventListener("pointerdown", onPointerDown);
|
|
3002
|
+
document.addEventListener("keydown", onKeyDown);
|
|
3003
|
+
return () => {
|
|
3004
|
+
document.removeEventListener("pointerdown", onPointerDown);
|
|
3005
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
3006
|
+
};
|
|
3007
|
+
}, [expanded]);
|
|
3008
|
+
const onBlur = (event) => {
|
|
3009
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setOpen(false);
|
|
3010
|
+
};
|
|
3011
|
+
const link = (item, inPanel) => {
|
|
3012
|
+
const badge = badgeOf(item);
|
|
3013
|
+
const badgeText = badgeTextOf(item);
|
|
3014
|
+
return renderLink(
|
|
3015
|
+
{
|
|
3016
|
+
href: item.href,
|
|
3017
|
+
className: "sc-priority-nav__link",
|
|
3018
|
+
"aria-current": item.current ? "page" : void 0,
|
|
3019
|
+
onClick: inPanel ? () => setOpen(false) : void 0,
|
|
3020
|
+
children: /* @__PURE__ */ jsxs26(Fragment9, { children: [
|
|
3021
|
+
/* @__PURE__ */ jsx31("span", { className: "sc-priority-nav__label", children: item.label }),
|
|
3022
|
+
badge !== null ? /* @__PURE__ */ jsx31(Badge2, { value: badge }) : null,
|
|
3023
|
+
badgeText !== null ? /* @__PURE__ */ jsxs26("span", { className: "sc-visually-hidden", children: [
|
|
3024
|
+
", ",
|
|
3025
|
+
badgeText
|
|
3026
|
+
] }) : null
|
|
3027
|
+
] })
|
|
3028
|
+
},
|
|
3029
|
+
item
|
|
3030
|
+
);
|
|
3031
|
+
};
|
|
3032
|
+
return /* @__PURE__ */ jsx31(
|
|
3033
|
+
"nav",
|
|
3034
|
+
{
|
|
3035
|
+
className: cx("sc-priority-nav", className),
|
|
3036
|
+
"data-measuring": measuring || void 0,
|
|
3037
|
+
"data-overflowing": fit.overflowing || void 0,
|
|
3038
|
+
style: { ...style, "--_anchor": `--sc-priority-nav${panelId.replace(/[^\w-]/g, "")}` },
|
|
3039
|
+
...rest,
|
|
3040
|
+
children: /* @__PURE__ */ jsxs26("ul", { ref: listRef, className: "sc-priority-nav__list", children: [
|
|
3041
|
+
items.map(
|
|
3042
|
+
(item, i) => flags && !flags[i] ? null : /* @__PURE__ */ jsx31("li", { className: "sc-priority-nav__item", "data-current": item.current || void 0, children: link(item, false) }, keyOf(item))
|
|
3043
|
+
),
|
|
3044
|
+
/* @__PURE__ */ jsxs26(
|
|
3045
|
+
"li",
|
|
3046
|
+
{
|
|
3047
|
+
ref: moreRef,
|
|
3048
|
+
className: "sc-priority-nav__more",
|
|
3049
|
+
hidden: measuring || overflow.length === 0,
|
|
3050
|
+
onBlur,
|
|
3051
|
+
children: [
|
|
3052
|
+
/* @__PURE__ */ jsxs26(
|
|
3053
|
+
"button",
|
|
3054
|
+
{
|
|
3055
|
+
ref: toggleRef,
|
|
3056
|
+
type: "button",
|
|
3057
|
+
className: "sc-priority-nav__toggle",
|
|
3058
|
+
"aria-expanded": expanded,
|
|
3059
|
+
"aria-controls": panelId,
|
|
3060
|
+
onClick: () => setOpen((o) => !o),
|
|
3061
|
+
children: [
|
|
3062
|
+
/* @__PURE__ */ jsx31(MoreHorizontalIcon, { className: "sc-priority-nav__ellipsis" }),
|
|
3063
|
+
/* @__PURE__ */ jsx31("span", { className: "sc-priority-nav__toggle-label", children: moreLabel }),
|
|
3064
|
+
/* @__PURE__ */ jsxs26("span", { className: "sc-visually-hidden", children: [
|
|
3065
|
+
", ",
|
|
3066
|
+
moreCountLabel(overflow.length),
|
|
3067
|
+
moreBadgeText
|
|
3068
|
+
] }),
|
|
3069
|
+
moreBadge !== null ? /* @__PURE__ */ jsx31(Badge2, { value: moreBadge }) : null,
|
|
3070
|
+
/* @__PURE__ */ jsx31(ChevronDownIcon, { size: "sm", className: "sc-priority-nav__chevron" })
|
|
3071
|
+
]
|
|
3072
|
+
}
|
|
3073
|
+
),
|
|
3074
|
+
/* @__PURE__ */ jsx31("ul", { ref: panelRef, id: panelId, className: "sc-priority-nav__panel", hidden: !expanded, children: overflow.map((item) => /* @__PURE__ */ jsx31("li", { children: link(item, true) }, keyOf(item))) })
|
|
3075
|
+
]
|
|
3076
|
+
}
|
|
3077
|
+
)
|
|
3078
|
+
] })
|
|
3079
|
+
}
|
|
3080
|
+
);
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
// src/components/Popover/Popover.tsx
|
|
3084
|
+
import { Popover as BasePopover } from "@base-ui/react/popover";
|
|
3085
|
+
import { jsx as jsx32, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3086
|
+
function Root6({ open, defaultOpen, onOpenChange, modal = false, children }) {
|
|
3087
|
+
return /* @__PURE__ */ jsx32(
|
|
3088
|
+
BasePopover.Root,
|
|
3089
|
+
{
|
|
3090
|
+
open,
|
|
3091
|
+
defaultOpen,
|
|
3092
|
+
onOpenChange: onOpenChange ? (next) => onOpenChange(next) : void 0,
|
|
3093
|
+
modal,
|
|
3094
|
+
children
|
|
3095
|
+
}
|
|
3096
|
+
);
|
|
3097
|
+
}
|
|
3098
|
+
function Trigger3({ render, className, children, ...rest }) {
|
|
3099
|
+
return /* @__PURE__ */ jsx32(
|
|
3100
|
+
BasePopover.Trigger,
|
|
3101
|
+
{
|
|
3102
|
+
render: render ?? /* @__PURE__ */ jsx32(Button, { variant: "secondary", className }),
|
|
3103
|
+
className: render ? className : void 0,
|
|
3104
|
+
...rest,
|
|
3105
|
+
children
|
|
3106
|
+
}
|
|
3107
|
+
);
|
|
3108
|
+
}
|
|
3109
|
+
function Content3({
|
|
3110
|
+
side = "bottom",
|
|
3111
|
+
align = "center",
|
|
3112
|
+
sideOffset,
|
|
3113
|
+
arrow = false,
|
|
3114
|
+
className,
|
|
3115
|
+
children,
|
|
3116
|
+
...rest
|
|
3117
|
+
}) {
|
|
3118
|
+
return /* @__PURE__ */ jsx32(BasePopover.Portal, { children: /* @__PURE__ */ jsx32(
|
|
3119
|
+
BasePopover.Positioner,
|
|
3120
|
+
{
|
|
3121
|
+
side,
|
|
3122
|
+
align,
|
|
3123
|
+
sideOffset: sideOffset ?? (arrow ? 8 : 4),
|
|
3124
|
+
className: "sc-popover__positioner",
|
|
3125
|
+
children: /* @__PURE__ */ jsxs27(BasePopover.Popup, { className: cx("sc-popover", className), ...rest, children: [
|
|
3126
|
+
arrow ? /* @__PURE__ */ jsx32(BasePopover.Arrow, { className: "sc-popover__arrow" }) : null,
|
|
3127
|
+
children
|
|
3128
|
+
] })
|
|
3129
|
+
}
|
|
3130
|
+
) });
|
|
3131
|
+
}
|
|
3132
|
+
function Title2({ className, ...rest }) {
|
|
3133
|
+
return /* @__PURE__ */ jsx32(BasePopover.Title, { className: cx("sc-popover__title", className), ...rest });
|
|
3134
|
+
}
|
|
3135
|
+
function Description2({ className, ...rest }) {
|
|
3136
|
+
return /* @__PURE__ */ jsx32(BasePopover.Description, { className: cx("sc-popover__description", className), ...rest });
|
|
3137
|
+
}
|
|
3138
|
+
function Close2({ className, children, render, ...rest }) {
|
|
3139
|
+
if (children === void 0 && render === void 0) {
|
|
3140
|
+
return /* @__PURE__ */ jsx32(BasePopover.Close, { className: cx("sc-popover__close", className), "aria-label": "Close", ...rest, children: /* @__PURE__ */ jsx32(XIcon, {}) });
|
|
3141
|
+
}
|
|
3142
|
+
return /* @__PURE__ */ jsx32(BasePopover.Close, { className, render, ...rest, children });
|
|
3143
|
+
}
|
|
3144
|
+
var Popover = { Root: Root6, Trigger: Trigger3, Content: Content3, Title: Title2, Description: Description2, Close: Close2 };
|
|
3145
|
+
|
|
3146
|
+
// src/components/BroomIcon/BroomIcon.tsx
|
|
3147
|
+
import { jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3148
|
+
function BroomIcon({ sweeping = false, size = "lg", title, className, ...rest }) {
|
|
3149
|
+
return /* @__PURE__ */ jsxs28(
|
|
3150
|
+
"svg",
|
|
3151
|
+
{
|
|
3152
|
+
className: cx("sc-icon", "sc-broom", className),
|
|
3153
|
+
"data-size": size,
|
|
3154
|
+
"data-sweeping": sweeping || void 0,
|
|
3155
|
+
viewBox: "0 0 24 24",
|
|
3156
|
+
fill: "none",
|
|
3157
|
+
focusable: "false",
|
|
3158
|
+
"aria-hidden": title ? void 0 : true,
|
|
3159
|
+
role: title ? "img" : void 0,
|
|
3160
|
+
"aria-label": title,
|
|
3161
|
+
...rest,
|
|
3162
|
+
children: [
|
|
3163
|
+
/* @__PURE__ */ jsxs28(
|
|
3164
|
+
"g",
|
|
3165
|
+
{
|
|
3166
|
+
className: "sc-broom__body",
|
|
3167
|
+
fill: "none",
|
|
3168
|
+
stroke: "currentColor",
|
|
3169
|
+
strokeLinecap: "round",
|
|
3170
|
+
strokeLinejoin: "round",
|
|
3171
|
+
children: [
|
|
3172
|
+
/* @__PURE__ */ jsx33("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" }),
|
|
3173
|
+
/* @__PURE__ */ jsx33("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" }),
|
|
3174
|
+
/* @__PURE__ */ jsx33("path", { className: "sc-broom__band", d: "M13.47 12.13 L18.4 13.5 L18.33 14.1 L13.27 12.77 Z" }),
|
|
3175
|
+
/* @__PURE__ */ jsx33("path", { d: "M12.87 13.73 L14.4 14.47 M16.2 15.27 L18.47 15.87" }),
|
|
3176
|
+
/* @__PURE__ */ jsx33("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" })
|
|
3177
|
+
]
|
|
3178
|
+
}
|
|
3179
|
+
),
|
|
3180
|
+
/* @__PURE__ */ jsxs28("g", { className: "sc-broom__dust", fill: "none", stroke: "currentColor", children: [
|
|
3181
|
+
/* @__PURE__ */ jsx33("circle", { cx: "4.77", cy: "13.53", r: "0.5" }),
|
|
3182
|
+
/* @__PURE__ */ jsx33("circle", { cx: "2.7", cy: "15.53", r: "0.87" }),
|
|
3183
|
+
/* @__PURE__ */ jsx33("circle", { cx: "4.1", cy: "18.27", r: "0.5" })
|
|
3184
|
+
] })
|
|
3185
|
+
]
|
|
3186
|
+
}
|
|
3187
|
+
);
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
// src/components/FullScreenFlow/FullScreenFlow.tsx
|
|
3191
|
+
import {
|
|
3192
|
+
Children as Children2,
|
|
3193
|
+
createContext as createContext2,
|
|
3194
|
+
useCallback as useCallback2,
|
|
3195
|
+
useContext as useContext2,
|
|
3196
|
+
useEffect as useEffect6,
|
|
3197
|
+
useId as useId5,
|
|
3198
|
+
useMemo as useMemo3,
|
|
3199
|
+
useRef as useRef6,
|
|
3200
|
+
useState as useState8
|
|
3201
|
+
} from "react";
|
|
3202
|
+
import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
3203
|
+
var FlowContext = createContext2({ announce: () => {
|
|
3204
|
+
} });
|
|
3205
|
+
var FrameContext = createContext2(void 0);
|
|
3206
|
+
var ENTER_IGNORES = 'textarea, button, a[href], summary, select, [contenteditable], [role="combobox"], [data-flow-keys="local"]';
|
|
3207
|
+
var ARROW_IGNORES = 'input, textarea, select, button, a[href], summary, [contenteditable], [role="radiogroup"], [role="slider"], [role="listbox"], [role="tablist"], [role="menu"], [role="grid"], [role="combobox"], [data-flow-keys="local"]';
|
|
3208
|
+
function Root7({
|
|
3209
|
+
open = true,
|
|
3210
|
+
onRequestClose,
|
|
3211
|
+
onNext,
|
|
3212
|
+
onBack,
|
|
3213
|
+
decoration,
|
|
3214
|
+
className,
|
|
3215
|
+
children
|
|
3216
|
+
}) {
|
|
3217
|
+
const popupRef = useRef6(null);
|
|
3218
|
+
const [message, setMessage] = useState8("");
|
|
3219
|
+
const timer = useRef6(void 0);
|
|
3220
|
+
const announce = useCallback2((next) => {
|
|
3221
|
+
setMessage("");
|
|
3222
|
+
clearTimeout(timer.current);
|
|
3223
|
+
timer.current = setTimeout(() => setMessage(next), 30);
|
|
3224
|
+
}, []);
|
|
3225
|
+
useEffect6(() => () => clearTimeout(timer.current), []);
|
|
3226
|
+
const context = useMemo3(() => ({ announce }), [announce]);
|
|
3227
|
+
const handleKeyDown = (event) => {
|
|
3228
|
+
if (event.defaultPrevented || event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return;
|
|
3229
|
+
if (event.nativeEvent.isComposing) return;
|
|
3230
|
+
const target = event.target;
|
|
3231
|
+
if (!event.currentTarget.contains(target)) return;
|
|
3232
|
+
if (event.key === "Enter") {
|
|
3233
|
+
if (!onNext || target.closest(ENTER_IGNORES)) return;
|
|
3234
|
+
event.preventDefault();
|
|
3235
|
+
onNext();
|
|
3236
|
+
return;
|
|
3237
|
+
}
|
|
3238
|
+
if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return;
|
|
3239
|
+
if (target.closest(ARROW_IGNORES)) return;
|
|
3240
|
+
const rtl = getComputedStyle(event.currentTarget).direction === "rtl";
|
|
3241
|
+
const forward = event.key === "ArrowRight" !== rtl;
|
|
3242
|
+
const handler = forward ? onNext : onBack;
|
|
3243
|
+
if (!handler) return;
|
|
3244
|
+
event.preventDefault();
|
|
3245
|
+
handler();
|
|
3246
|
+
};
|
|
3247
|
+
return /* @__PURE__ */ jsx34(
|
|
3248
|
+
Dialog.Root,
|
|
3249
|
+
{
|
|
3250
|
+
open,
|
|
3251
|
+
onRequestClose: (reason) => {
|
|
3252
|
+
if (reason !== "outside-press") onRequestClose(reason);
|
|
3253
|
+
},
|
|
3254
|
+
children: /* @__PURE__ */ jsx34(
|
|
3255
|
+
Dialog.Content,
|
|
3256
|
+
{
|
|
3257
|
+
ref: popupRef,
|
|
3258
|
+
variant: "fullscreen",
|
|
3259
|
+
className: cx("sc-flow", className),
|
|
3260
|
+
initialFocus: () => popupRef.current?.querySelector(".sc-flow__step-title") ?? true,
|
|
3261
|
+
onKeyDown: handleKeyDown,
|
|
3262
|
+
children: /* @__PURE__ */ jsxs29(FlowContext.Provider, { value: context, children: [
|
|
3263
|
+
decoration ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__decoration", "aria-hidden": "true", children: decoration }) : null,
|
|
3264
|
+
children,
|
|
3265
|
+
/* @__PURE__ */ jsx34("div", { className: "sc-visually-hidden", "aria-live": "polite", "aria-atomic": "true", children: message })
|
|
3266
|
+
] })
|
|
3267
|
+
}
|
|
3268
|
+
)
|
|
3269
|
+
}
|
|
3270
|
+
);
|
|
3271
|
+
}
|
|
3272
|
+
function Header2({
|
|
3273
|
+
title,
|
|
3274
|
+
logo,
|
|
3275
|
+
compactTitle,
|
|
3276
|
+
status,
|
|
3277
|
+
closeLabel = "Close",
|
|
3278
|
+
className,
|
|
3279
|
+
children,
|
|
3280
|
+
...rest
|
|
3281
|
+
}) {
|
|
3282
|
+
return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__header", className), ...rest, children: [
|
|
3283
|
+
/* @__PURE__ */ jsxs29("div", { className: "sc-flow__heading", "data-compact": compactTitle ? "" : void 0, children: [
|
|
3284
|
+
logo ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__logo", "aria-hidden": "true", children: logo }) : null,
|
|
3285
|
+
/* @__PURE__ */ jsx34(Dialog.Title, { className: "sc-flow__title", children: title }),
|
|
3286
|
+
compactTitle ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__compact-title", children: compactTitle }) : null
|
|
3287
|
+
] }),
|
|
3288
|
+
children,
|
|
3289
|
+
status ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__status", children: status }) : null,
|
|
3290
|
+
/* @__PURE__ */ jsx34(
|
|
3291
|
+
Dialog.Close,
|
|
3292
|
+
{
|
|
3293
|
+
className: "sc-flow__close",
|
|
3294
|
+
render: /* @__PURE__ */ jsx34(IconButton, { label: closeLabel, "aria-keyshortcuts": "Escape" }),
|
|
3295
|
+
children: /* @__PURE__ */ jsx34(XIcon, { size: "lg" })
|
|
3296
|
+
}
|
|
3297
|
+
)
|
|
3298
|
+
] });
|
|
3299
|
+
}
|
|
3300
|
+
function Progress2({
|
|
3301
|
+
chapters,
|
|
3302
|
+
step,
|
|
3303
|
+
label,
|
|
3304
|
+
listLabel = "Progress",
|
|
3305
|
+
className,
|
|
3306
|
+
...rest
|
|
3307
|
+
}) {
|
|
3308
|
+
const starts = chapters.reduce(
|
|
3309
|
+
(acc, chapter, i) => [...acc, i === 0 ? 0 : acc[i - 1] + chapters[i - 1].steps],
|
|
3310
|
+
[]
|
|
3311
|
+
);
|
|
3312
|
+
return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__progress", className), ...rest, children: [
|
|
3313
|
+
label ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__progress-label", children: label }) : null,
|
|
3314
|
+
/* @__PURE__ */ jsx34("ol", { className: "sc-flow__segments", "aria-label": listLabel, children: chapters.map((chapter, i) => {
|
|
3315
|
+
const from = starts[i];
|
|
3316
|
+
const current = step > from && step <= from + chapter.steps;
|
|
3317
|
+
const done = Math.min(chapter.steps, Math.max(0, step - 1 - from)) + (current ? 0.5 : 0);
|
|
3318
|
+
const percent = chapter.steps > 0 ? Math.min(100, done / chapter.steps * 100) : 0;
|
|
3319
|
+
return /* @__PURE__ */ jsxs29(
|
|
3320
|
+
"li",
|
|
3321
|
+
{
|
|
3322
|
+
className: "sc-flow__segment",
|
|
3323
|
+
style: { flexGrow: chapter.steps },
|
|
3324
|
+
"aria-current": current ? "step" : void 0,
|
|
3325
|
+
children: [
|
|
3326
|
+
/* @__PURE__ */ jsx34("span", { className: "sc-flow__segment-fill", style: { inlineSize: `${percent}%` } }),
|
|
3327
|
+
/* @__PURE__ */ jsx34("span", { className: "sc-visually-hidden", children: chapter.label })
|
|
3328
|
+
]
|
|
3329
|
+
},
|
|
3330
|
+
chapter.label
|
|
3331
|
+
);
|
|
3332
|
+
}) })
|
|
3333
|
+
] });
|
|
3334
|
+
}
|
|
3335
|
+
function Body3({ className, ...rest }) {
|
|
3336
|
+
return /* @__PURE__ */ jsx34("div", { className: cx("sc-flow__body", className), ...rest });
|
|
3337
|
+
}
|
|
3338
|
+
function Rail({
|
|
3339
|
+
"aria-label": ariaLabel = "Steps",
|
|
3340
|
+
footer,
|
|
3341
|
+
className,
|
|
3342
|
+
children,
|
|
3343
|
+
...rest
|
|
3344
|
+
}) {
|
|
3345
|
+
return /* @__PURE__ */ jsxs29("nav", { className: cx("sc-flow__rail", className), "aria-label": ariaLabel, ...rest, children: [
|
|
3346
|
+
children,
|
|
3347
|
+
footer ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__rail-note", children: footer }) : null
|
|
3348
|
+
] });
|
|
3349
|
+
}
|
|
3350
|
+
function RailGroup({ label, className, children, ...rest }) {
|
|
3351
|
+
const id = useId5();
|
|
3352
|
+
return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__rail-group", className), ...rest, children: [
|
|
3353
|
+
/* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-label", id, children: label }),
|
|
3354
|
+
/* @__PURE__ */ jsx34("ol", { className: "sc-flow__rail-list", "aria-labelledby": id, children })
|
|
3355
|
+
] });
|
|
3356
|
+
}
|
|
3357
|
+
function RailItem({
|
|
3358
|
+
current = false,
|
|
3359
|
+
done = false,
|
|
3360
|
+
doneLabel = "done",
|
|
3361
|
+
adornment,
|
|
3362
|
+
type = "button",
|
|
3363
|
+
className,
|
|
3364
|
+
children,
|
|
3365
|
+
...rest
|
|
3366
|
+
}) {
|
|
3367
|
+
return /* @__PURE__ */ jsx34("li", { className: "sc-flow__rail-entry", children: /* @__PURE__ */ jsxs29(
|
|
3368
|
+
"button",
|
|
3369
|
+
{
|
|
3370
|
+
type,
|
|
3371
|
+
className: cx("sc-flow__rail-item", className),
|
|
3372
|
+
"aria-current": current ? "step" : void 0,
|
|
3373
|
+
"data-done": done || void 0,
|
|
3374
|
+
...rest,
|
|
3375
|
+
children: [
|
|
3376
|
+
/* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-mark", "aria-hidden": "true", children: done ? /* @__PURE__ */ jsx34(CheckIcon, { size: "sm" }) : null }),
|
|
3377
|
+
/* @__PURE__ */ jsxs29("span", { className: "sc-flow__rail-text", children: [
|
|
3378
|
+
children,
|
|
3379
|
+
done ? /* @__PURE__ */ jsxs29("span", { className: "sc-visually-hidden", children: [
|
|
3380
|
+
", ",
|
|
3381
|
+
doneLabel
|
|
3382
|
+
] }) : null
|
|
3383
|
+
] }),
|
|
3384
|
+
adornment ? /* @__PURE__ */ jsx34("span", { className: "sc-flow__rail-adornment", children: adornment }) : null
|
|
3385
|
+
]
|
|
3386
|
+
}
|
|
3387
|
+
) });
|
|
3388
|
+
}
|
|
3389
|
+
function Viewport2({ direction = "forward", className, children, ...rest }) {
|
|
3390
|
+
const element = Children2.only(children);
|
|
3391
|
+
const key = String(element.key ?? "");
|
|
3392
|
+
const [state, setState] = useState8({
|
|
3393
|
+
current: { key, element, direction },
|
|
3394
|
+
leaving: null,
|
|
3395
|
+
moved: false
|
|
3396
|
+
});
|
|
3397
|
+
if (state.current.key !== key) {
|
|
3398
|
+
setState({
|
|
3399
|
+
current: { key, element, direction },
|
|
3400
|
+
leaving: { ...state.current, direction },
|
|
3401
|
+
moved: true
|
|
3402
|
+
});
|
|
3403
|
+
} else if (state.current.element !== element) {
|
|
3404
|
+
setState((s) => ({ ...s, current: { ...s.current, element } }));
|
|
3405
|
+
}
|
|
3406
|
+
const finishExit = useCallback2((leftKey) => {
|
|
3407
|
+
setState((s) => s.leaving?.key === leftKey ? { ...s, leaving: null } : s);
|
|
3408
|
+
}, []);
|
|
3409
|
+
const ref = useRef6(null);
|
|
3410
|
+
useEffect6(() => {
|
|
3411
|
+
if (state.moved && ref.current) ref.current.scrollTop = 0;
|
|
3412
|
+
}, [key, state.moved]);
|
|
3413
|
+
const frames = [];
|
|
3414
|
+
if (state.leaving && state.leaving.key !== key) frames.push({ frame: state.leaving, phase: "exit" });
|
|
3415
|
+
frames.push({
|
|
3416
|
+
frame: { key, element, direction: state.current.direction },
|
|
3417
|
+
phase: state.moved ? "enter" : void 0
|
|
3418
|
+
});
|
|
3419
|
+
return /* @__PURE__ */ jsx34("div", { ref, className: cx("sc-flow__viewport", className), ...rest, children: frames.map(({ frame, phase }) => /* @__PURE__ */ jsx34(
|
|
3420
|
+
FrameView,
|
|
3421
|
+
{
|
|
3422
|
+
frameKey: frame.key,
|
|
3423
|
+
phase,
|
|
3424
|
+
direction: frame.direction,
|
|
3425
|
+
onExited: finishExit,
|
|
3426
|
+
children: frame.element
|
|
3427
|
+
},
|
|
3428
|
+
frame.key
|
|
3429
|
+
)) });
|
|
3430
|
+
}
|
|
3431
|
+
function FrameView({
|
|
3432
|
+
frameKey,
|
|
3433
|
+
phase,
|
|
3434
|
+
direction,
|
|
3435
|
+
onExited,
|
|
3436
|
+
children
|
|
3437
|
+
}) {
|
|
3438
|
+
const ref = useRef6(null);
|
|
3439
|
+
useEffect6(() => {
|
|
3440
|
+
if (phase !== "exit") return;
|
|
3441
|
+
let cancelled = false;
|
|
3442
|
+
const el = ref.current;
|
|
3443
|
+
const animations = el && typeof el.getAnimations === "function" ? el.getAnimations() : [];
|
|
3444
|
+
const done = () => {
|
|
3445
|
+
if (!cancelled) onExited(frameKey);
|
|
3446
|
+
};
|
|
3447
|
+
Promise.all(animations.map((a) => a.finished)).then(done, done);
|
|
3448
|
+
return () => {
|
|
3449
|
+
cancelled = true;
|
|
3450
|
+
};
|
|
3451
|
+
}, [phase, frameKey, onExited]);
|
|
3452
|
+
return /* @__PURE__ */ jsx34(
|
|
3453
|
+
"div",
|
|
3454
|
+
{
|
|
3455
|
+
ref,
|
|
3456
|
+
className: "sc-flow__frame",
|
|
3457
|
+
"data-phase": phase,
|
|
3458
|
+
"data-direction": direction,
|
|
3459
|
+
inert: phase === "exit",
|
|
3460
|
+
children: /* @__PURE__ */ jsx34(FrameContext.Provider, { value: phase, children })
|
|
3461
|
+
}
|
|
3462
|
+
);
|
|
3463
|
+
}
|
|
3464
|
+
function Step({
|
|
3465
|
+
title,
|
|
3466
|
+
eyebrow,
|
|
3467
|
+
description,
|
|
3468
|
+
announcement,
|
|
3469
|
+
className,
|
|
3470
|
+
children,
|
|
3471
|
+
...rest
|
|
3472
|
+
}) {
|
|
3473
|
+
const id = useId5();
|
|
3474
|
+
const titleRef = useRef6(null);
|
|
3475
|
+
const phase = useContext2(FrameContext);
|
|
3476
|
+
const { announce } = useContext2(FlowContext);
|
|
3477
|
+
const message = announcement ?? (typeof title === "string" ? title : void 0);
|
|
3478
|
+
const latest = useRef6({ message, announce });
|
|
3479
|
+
useEffect6(() => {
|
|
3480
|
+
latest.current = { message, announce };
|
|
3481
|
+
});
|
|
3482
|
+
useEffect6(() => {
|
|
3483
|
+
if (phase !== "enter") return;
|
|
3484
|
+
titleRef.current?.focus({ preventScroll: true });
|
|
3485
|
+
if (latest.current.message) latest.current.announce(latest.current.message);
|
|
3486
|
+
}, [phase]);
|
|
3487
|
+
return /* @__PURE__ */ jsxs29("section", { className: cx("sc-flow__step", className), "aria-labelledby": id, ...rest, children: [
|
|
3488
|
+
/* @__PURE__ */ jsxs29("div", { className: "sc-flow__step-head", children: [
|
|
3489
|
+
eyebrow ? /* @__PURE__ */ jsx34("p", { className: "sc-flow__eyebrow", children: eyebrow }) : null,
|
|
3490
|
+
/* @__PURE__ */ jsx34("h2", { className: "sc-flow__step-title", id, ref: titleRef, tabIndex: -1, children: title }),
|
|
3491
|
+
description ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__step-description", children: description }) : null
|
|
3492
|
+
] }),
|
|
3493
|
+
children
|
|
3494
|
+
] });
|
|
3495
|
+
}
|
|
3496
|
+
function Footer({ back, hint, className, children, ...rest }) {
|
|
3497
|
+
return /* @__PURE__ */ jsxs29("div", { className: cx("sc-flow__footer", className), ...rest, children: [
|
|
3498
|
+
back ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-back", children: back }) : null,
|
|
3499
|
+
hint ? /* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-hint", children: hint }) : null,
|
|
3500
|
+
/* @__PURE__ */ jsx34("div", { className: "sc-flow__footer-actions", children })
|
|
3501
|
+
] });
|
|
3502
|
+
}
|
|
3503
|
+
var FullScreenFlow = {
|
|
3504
|
+
Root: Root7,
|
|
3505
|
+
Header: Header2,
|
|
3506
|
+
Progress: Progress2,
|
|
3507
|
+
Body: Body3,
|
|
3508
|
+
Rail,
|
|
3509
|
+
RailGroup,
|
|
3510
|
+
RailItem,
|
|
3511
|
+
Viewport: Viewport2,
|
|
3512
|
+
Step,
|
|
3513
|
+
Footer
|
|
3514
|
+
};
|
|
3515
|
+
|
|
3516
|
+
// src/components/Score/Score.tsx
|
|
3517
|
+
import { jsx as jsx35, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
3518
|
+
function Score({
|
|
3519
|
+
value,
|
|
3520
|
+
max = 100,
|
|
3521
|
+
tone = "accent",
|
|
3522
|
+
variant = "tile",
|
|
3523
|
+
size = "sm",
|
|
3524
|
+
caption,
|
|
3525
|
+
label = "Score",
|
|
3526
|
+
valueText,
|
|
3527
|
+
selected = false,
|
|
3528
|
+
className,
|
|
3529
|
+
style,
|
|
3530
|
+
...rest
|
|
3531
|
+
}) {
|
|
3532
|
+
const scored = value !== null;
|
|
3533
|
+
const fraction = scored && max > 0 ? Math.min(1, Math.max(0, value / max)) : 0;
|
|
3534
|
+
return /* @__PURE__ */ jsxs30(
|
|
3535
|
+
"span",
|
|
3536
|
+
{
|
|
3537
|
+
className: cx("sc-score", className),
|
|
3538
|
+
"data-variant": variant,
|
|
3539
|
+
"data-size": variant === "tile" ? size : void 0,
|
|
3540
|
+
"data-tone": scored ? tone : void 0,
|
|
3541
|
+
"data-unscored": scored ? void 0 : true,
|
|
3542
|
+
"data-selected": selected || void 0,
|
|
3543
|
+
style: variant === "ring" ? { ...style, "--sc-score-fill": (fraction * 100).toFixed(2) } : style,
|
|
3544
|
+
...rest,
|
|
3545
|
+
children: [
|
|
3546
|
+
/* @__PURE__ */ jsx35("span", { className: "sc-visually-hidden", children: valueText ?? (scored ? `${label} ${value} out of ${max}` : `${label}: not scored`) }),
|
|
3547
|
+
variant === "ring" ? /* @__PURE__ */ jsxs30("svg", { className: "sc-score__ring", viewBox: "0 0 64 64", "aria-hidden": "true", focusable: "false", children: [
|
|
3548
|
+
/* @__PURE__ */ jsx35("circle", { className: "sc-score__track", cx: "32", cy: "32", r: "29", pathLength: 100 }),
|
|
3549
|
+
fraction > 0 ? /* @__PURE__ */ jsx35("circle", { className: "sc-score__arc", cx: "32", cy: "32", r: "29", pathLength: 100 }) : null
|
|
3550
|
+
] }) : null,
|
|
3551
|
+
/* @__PURE__ */ jsxs30("span", { className: "sc-score__body", "aria-hidden": "true", children: [
|
|
3552
|
+
/* @__PURE__ */ jsx35("span", { className: "sc-score__value", children: scored ? value : "\u2013" }),
|
|
3553
|
+
caption != null ? /* @__PURE__ */ jsx35("span", { className: "sc-score__caption", children: caption }) : null
|
|
3554
|
+
] })
|
|
3555
|
+
]
|
|
3556
|
+
}
|
|
3557
|
+
);
|
|
3558
|
+
}
|
|
3559
|
+
|
|
3560
|
+
// src/components/ReasonList/ReasonList.tsx
|
|
3561
|
+
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
3562
|
+
function ReasonListRoot({ tone, size = "md", divider = false, className, ...rest }) {
|
|
3563
|
+
return /* @__PURE__ */ jsx36(
|
|
3564
|
+
"ul",
|
|
3565
|
+
{
|
|
3566
|
+
className: cx("sc-reason-list", className),
|
|
3567
|
+
"data-tone": tone,
|
|
3568
|
+
"data-size": size,
|
|
3569
|
+
"data-divider": divider || void 0,
|
|
3570
|
+
...rest
|
|
3571
|
+
}
|
|
3572
|
+
);
|
|
3573
|
+
}
|
|
3574
|
+
function ReasonListItem({ className, ...rest }) {
|
|
3575
|
+
return /* @__PURE__ */ jsx36("li", { className: cx("sc-reason-list__item", className), ...rest });
|
|
3576
|
+
}
|
|
3577
|
+
var ReasonList = Object.assign(ReasonListRoot, { Item: ReasonListItem });
|
|
3578
|
+
|
|
3579
|
+
// src/components/WordDiff/WordDiff.tsx
|
|
3580
|
+
import { createElement as createElement7, Fragment as Fragment10 } from "react";
|
|
3581
|
+
import { Fragment as Fragment11, jsx as jsx37, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
3582
|
+
var edges = /^(\s*)([\s\S]*?)(\s*)$/;
|
|
3583
|
+
function Change({ kind, text, label }) {
|
|
3584
|
+
const [, lead = "", core = "", trail = ""] = edges.exec(text) ?? [];
|
|
3585
|
+
if (!core) return /* @__PURE__ */ jsx37(Fragment11, { children: text });
|
|
3586
|
+
const Tag = kind === "added" ? "ins" : "del";
|
|
3587
|
+
return /* @__PURE__ */ jsxs31(Fragment11, { children: [
|
|
3588
|
+
lead,
|
|
3589
|
+
/* @__PURE__ */ jsxs31(Tag, { className: `sc-word-diff__${kind}`, children: [
|
|
3590
|
+
/* @__PURE__ */ jsxs31("span", { className: "sc-visually-hidden", children: [
|
|
3591
|
+
"[",
|
|
3592
|
+
label,
|
|
3593
|
+
": "
|
|
3594
|
+
] }),
|
|
3595
|
+
core,
|
|
3596
|
+
/* @__PURE__ */ jsx37("span", { className: "sc-visually-hidden", children: "]" })
|
|
3597
|
+
] }),
|
|
3598
|
+
trail
|
|
3599
|
+
] });
|
|
3600
|
+
}
|
|
3601
|
+
function WordDiff({
|
|
3602
|
+
parts,
|
|
3603
|
+
as = "p",
|
|
3604
|
+
size = "sm",
|
|
3605
|
+
family = "sans",
|
|
3606
|
+
addedLabel = "added",
|
|
3607
|
+
removedLabel = "removed",
|
|
3608
|
+
className,
|
|
3609
|
+
...rest
|
|
3610
|
+
}) {
|
|
3611
|
+
const children = parts.map(
|
|
3612
|
+
(part, i) => part.kind === "same" ? /* @__PURE__ */ jsx37(Fragment10, { children: part.text }, i) : /* @__PURE__ */ jsx37(
|
|
3613
|
+
Change,
|
|
3614
|
+
{
|
|
3615
|
+
kind: part.kind,
|
|
3616
|
+
text: part.text,
|
|
3617
|
+
label: part.kind === "added" ? addedLabel : removedLabel
|
|
3618
|
+
},
|
|
3619
|
+
i
|
|
3620
|
+
)
|
|
3621
|
+
);
|
|
3622
|
+
return createElement7(
|
|
3623
|
+
as,
|
|
3624
|
+
{
|
|
3625
|
+
className: cx("sc-word-diff", className),
|
|
3626
|
+
"data-size": size,
|
|
3627
|
+
...family === "mono" ? { "data-family": "mono" } : {},
|
|
3628
|
+
...rest
|
|
3629
|
+
},
|
|
3630
|
+
children
|
|
3631
|
+
);
|
|
3632
|
+
}
|
|
3633
|
+
|
|
3634
|
+
// src/components/Quote/Quote.tsx
|
|
3635
|
+
import { jsx as jsx38, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
3636
|
+
function Quote({ label, className, children, ...rest }) {
|
|
3637
|
+
return /* @__PURE__ */ jsxs32("figure", { className: cx("sc-quote", className), ...rest, children: [
|
|
3638
|
+
/* @__PURE__ */ jsx38("figcaption", { className: "sc-quote__label", children: label }),
|
|
3639
|
+
/* @__PURE__ */ jsx38("blockquote", { className: "sc-quote__text", children })
|
|
3640
|
+
] });
|
|
3641
|
+
}
|
|
3642
|
+
|
|
1462
3643
|
// src/index.ts
|
|
1463
3644
|
var version = "0.1.1";
|
|
1464
3645
|
export {
|
|
@@ -1471,6 +3652,7 @@ export {
|
|
|
1471
3652
|
Banner,
|
|
1472
3653
|
BellIcon,
|
|
1473
3654
|
BriefcaseIcon,
|
|
3655
|
+
BroomIcon,
|
|
1474
3656
|
Button,
|
|
1475
3657
|
CalendarIcon,
|
|
1476
3658
|
Card,
|
|
@@ -1480,18 +3662,24 @@ export {
|
|
|
1480
3662
|
ChevronLeftIcon,
|
|
1481
3663
|
ChevronRightIcon,
|
|
1482
3664
|
ChevronUpIcon,
|
|
3665
|
+
Chip,
|
|
1483
3666
|
CircleCheckIcon,
|
|
1484
3667
|
CircleXIcon,
|
|
1485
3668
|
ClockIcon,
|
|
1486
3669
|
CopyIcon,
|
|
1487
3670
|
Dialog,
|
|
3671
|
+
Disclosure,
|
|
1488
3672
|
DocumentIcon,
|
|
1489
3673
|
DownloadIcon,
|
|
1490
3674
|
EditIcon,
|
|
3675
|
+
EmptyState,
|
|
1491
3676
|
ExternalLinkIcon,
|
|
1492
3677
|
EyeIcon,
|
|
3678
|
+
FileInput,
|
|
3679
|
+
FilePreviewDialog,
|
|
1493
3680
|
FilterIcon,
|
|
1494
3681
|
FlagIcon,
|
|
3682
|
+
FullScreenFlow,
|
|
1495
3683
|
Heading,
|
|
1496
3684
|
Icon,
|
|
1497
3685
|
IconButton,
|
|
@@ -1512,11 +3700,18 @@ export {
|
|
|
1512
3700
|
PauseIcon,
|
|
1513
3701
|
PlayIcon,
|
|
1514
3702
|
PlusIcon,
|
|
3703
|
+
Popover,
|
|
3704
|
+
PriorityNav,
|
|
1515
3705
|
Progress,
|
|
3706
|
+
Quote,
|
|
3707
|
+
ReasonList,
|
|
1516
3708
|
RefreshIcon,
|
|
3709
|
+
Score,
|
|
1517
3710
|
SearchIcon,
|
|
1518
3711
|
Select,
|
|
3712
|
+
SelectionBar,
|
|
1519
3713
|
SettingsIcon,
|
|
3714
|
+
Skeleton,
|
|
1520
3715
|
Spinner,
|
|
1521
3716
|
Stack,
|
|
1522
3717
|
StarIcon,
|
|
@@ -1529,14 +3724,18 @@ export {
|
|
|
1529
3724
|
Textarea,
|
|
1530
3725
|
ThumbsDownIcon,
|
|
1531
3726
|
ThumbsUpIcon,
|
|
3727
|
+
Toast,
|
|
1532
3728
|
Toolbar,
|
|
1533
3729
|
Tooltip,
|
|
1534
3730
|
TrashIcon,
|
|
1535
3731
|
UndoIcon,
|
|
1536
3732
|
UserIcon,
|
|
1537
3733
|
WarningIcon,
|
|
3734
|
+
WordDiff,
|
|
1538
3735
|
XIcon,
|
|
1539
3736
|
iconNames,
|
|
3737
|
+
useRowSelection,
|
|
3738
|
+
useToast,
|
|
1540
3739
|
version
|
|
1541
3740
|
};
|
|
1542
3741
|
//# sourceMappingURL=index.js.map
|