@flytedan/flytebot-design-system 0.27.1 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2714,20 +2714,780 @@ function DataTable({
2714
2714
  }
2715
2715
 
2716
2716
  // src/components/data/FilterBar.tsx
2717
+ import * as React23 from "react";
2718
+
2719
+ // src/components/forms/NumberInput.tsx
2720
+ import * as React21 from "react";
2721
+
2722
+ // src/components/forms/field.tsx
2717
2723
  import * as React20 from "react";
2718
2724
  import { jsx as jsx41, jsxs as jsxs35 } from "react/jsx-runtime";
2725
+ function useFieldId(id) {
2726
+ const generated = React20.useId();
2727
+ return id || generated;
2728
+ }
2729
+ function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
2730
+ return /* @__PURE__ */ jsxs35("label", { className: "fd-field-label", htmlFor, id, onClick, children: [
2731
+ children,
2732
+ required ? /* @__PURE__ */ jsx41("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
2733
+ ] });
2734
+ }
2735
+ function useTriggerLabelling(label, id) {
2736
+ const fieldId = useFieldId(id);
2737
+ const labelId = fieldId + "-label";
2738
+ return { fieldId, labelId, ariaLabelledBy: label ? labelId + " " + fieldId : void 0 };
2739
+ }
2740
+
2741
+ // src/components/forms/NumberInput.tsx
2742
+ import { jsx as jsx42, jsxs as jsxs36 } from "react/jsx-runtime";
2743
+ function NumberInput({
2744
+ label,
2745
+ help,
2746
+ error,
2747
+ prefix,
2748
+ suffix,
2749
+ required = false,
2750
+ disabled = false,
2751
+ min = -Infinity,
2752
+ max = Infinity,
2753
+ step = 1,
2754
+ bigStep,
2755
+ value,
2756
+ onChange,
2757
+ format = true,
2758
+ className = "",
2759
+ style,
2760
+ placeholder,
2761
+ id,
2762
+ "aria-label": ariaLabel
2763
+ }) {
2764
+ const fieldId = useFieldId(id);
2765
+ const num = (v) => {
2766
+ const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
2767
+ return isNaN(n) ? null : n;
2768
+ };
2769
+ const [text, setText] = React21.useState(value == null || value === "" ? "" : String(value));
2770
+ const [editing, setEditing] = React21.useState(false);
2771
+ const timer = React21.useRef(null);
2772
+ React21.useEffect(() => {
2773
+ if (!editing) setText(value == null || value === "" ? "" : String(value));
2774
+ }, [value, editing]);
2775
+ const clamp = (n) => Math.min(max, Math.max(min, n));
2776
+ const fire = (n) => onChange && onChange({ target: { value: n } });
2777
+ const bump = (dir, mult = 1) => {
2778
+ const cur = num(text) ?? num(value) ?? (min === -Infinity ? 0 : min);
2779
+ const next = clamp(cur + dir * (bigStep && mult > 1 ? bigStep : step) * (bigStep ? 1 : mult));
2780
+ setText(String(next));
2781
+ fire(next);
2782
+ };
2783
+ const hold = (dir) => {
2784
+ bump(dir);
2785
+ let n = 0;
2786
+ const tick = () => {
2787
+ n++;
2788
+ bump(dir, n > 6 ? 4 : 1);
2789
+ timer.current = setTimeout(tick, n > 12 ? 40 : n > 6 ? 70 : 120);
2790
+ };
2791
+ timer.current = setTimeout(tick, 420);
2792
+ };
2793
+ const release = () => {
2794
+ if (timer.current) clearTimeout(timer.current);
2795
+ };
2796
+ React21.useEffect(() => () => {
2797
+ if (timer.current) clearTimeout(timer.current);
2798
+ }, []);
2799
+ const shown = editing ? text : (() => {
2800
+ const n = num(text);
2801
+ return n == null ? "" : format ? n.toLocaleString() : String(n);
2802
+ })();
2803
+ const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
2804
+ const fieldName = label || ariaLabel;
2805
+ const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
2806
+ return /* @__PURE__ */ jsxs36("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
2807
+ label ? /* @__PURE__ */ jsx42(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
2808
+ /* @__PURE__ */ jsxs36("div", { className: box, style: { gap: 8 }, children: [
2809
+ prefix ? /* @__PURE__ */ jsx42("span", { className: "fd-input-affix", children: prefix }) : null,
2810
+ /* @__PURE__ */ jsx42(
2811
+ "input",
2812
+ {
2813
+ id: fieldId,
2814
+ "aria-label": ariaLabel,
2815
+ inputMode: "numeric",
2816
+ disabled,
2817
+ placeholder,
2818
+ value: shown,
2819
+ onFocus: () => setEditing(true),
2820
+ onBlur: () => {
2821
+ setEditing(false);
2822
+ const n = num(text);
2823
+ if (n != null) {
2824
+ const c = clamp(n);
2825
+ setText(String(c));
2826
+ fire(c);
2827
+ }
2828
+ },
2829
+ onChange: (e) => {
2830
+ setText(e.target.value);
2831
+ const n = num(e.target.value);
2832
+ if (n != null) fire(n);
2833
+ },
2834
+ onKeyDown: (e) => {
2835
+ if (e.key === "ArrowUp") {
2836
+ e.preventDefault();
2837
+ bump(1, e.shiftKey ? 2 : 1);
2838
+ } else if (e.key === "ArrowDown") {
2839
+ e.preventDefault();
2840
+ bump(-1, e.shiftKey ? 2 : 1);
2841
+ }
2842
+ }
2843
+ }
2844
+ ),
2845
+ suffix ? /* @__PURE__ */ jsx42("span", { className: "fd-input-affix", children: suffix }) : null,
2846
+ /* @__PURE__ */ jsxs36("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
2847
+ /* @__PURE__ */ jsx42(
2848
+ "button",
2849
+ {
2850
+ type: "button",
2851
+ className: "fd-stepbtn",
2852
+ "aria-label": stepperName("Decrease"),
2853
+ disabled: disabled || (num(text) ?? 0) <= min,
2854
+ onPointerDown: () => hold(-1),
2855
+ onPointerUp: release,
2856
+ onPointerLeave: release,
2857
+ children: /* @__PURE__ */ jsx42("i", { className: "ph ph-minus" })
2858
+ }
2859
+ ),
2860
+ /* @__PURE__ */ jsx42(
2861
+ "button",
2862
+ {
2863
+ type: "button",
2864
+ className: "fd-stepbtn",
2865
+ "aria-label": stepperName("Increase"),
2866
+ disabled: disabled || (num(text) ?? 0) >= max,
2867
+ onPointerDown: () => hold(1),
2868
+ onPointerUp: release,
2869
+ onPointerLeave: release,
2870
+ children: /* @__PURE__ */ jsx42("i", { className: "ph ph-plus" })
2871
+ }
2872
+ )
2873
+ ] })
2874
+ ] }),
2875
+ error ? /* @__PURE__ */ jsxs36("span", { className: "fd-field-error", children: [
2876
+ /* @__PURE__ */ jsx42("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
2877
+ error
2878
+ ] }) : help ? /* @__PURE__ */ jsx42("span", { className: "fd-field-help", children: help }) : null
2879
+ ] });
2880
+ }
2881
+
2882
+ // src/components/forms/DatePicker.tsx
2883
+ import * as React22 from "react";
2884
+ import { jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
2885
+ var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
2886
+ var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
2887
+ var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
2888
+ var parse = (s) => {
2889
+ if (!s) return null;
2890
+ const [y, m, d] = s.split("-").map(Number);
2891
+ return new Date(y, m - 1, d);
2892
+ };
2893
+ var fmt = (s) => {
2894
+ const d = parse(s);
2895
+ return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
2896
+ };
2897
+ function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
2898
+ const today = /* @__PURE__ */ new Date();
2899
+ const sel = range ? value || {} : { start: value, end: value };
2900
+ const anchor = parse(sel.start) || parse(initialMonth) || today;
2901
+ const [vy, setVy] = React22.useState(anchor.getFullYear());
2902
+ const [vm, setVm] = React22.useState(anchor.getMonth());
2903
+ const [mode2, setMode] = React22.useState("days");
2904
+ const [hover, setHover] = React22.useState(null);
2905
+ const s = parse(sel.start), e = parse(sel.end);
2906
+ const hoverEnd = range && s && !e && hover ? parse(hover) : null;
2907
+ const inRange = (d) => {
2908
+ const lo = s, hi = e || hoverEnd;
2909
+ return lo && hi && d > (lo < hi ? lo : hi) && d < (lo < hi ? hi : lo);
2910
+ };
2911
+ const isEdge = (d) => s && iso(d) === iso(s) || e && iso(d) === iso(e);
2912
+ const clickDay = (d) => {
2913
+ const v = iso(d);
2914
+ if (!range) {
2915
+ onPick(v);
2916
+ return;
2917
+ }
2918
+ if (!sel.start || sel.start && sel.end) onPick({ start: v, end: "" });
2919
+ else {
2920
+ const a = parse(sel.start);
2921
+ onPick(d < a ? { start: v, end: sel.start } : { start: sel.start, end: v });
2922
+ }
2923
+ };
2924
+ const nav = (d) => {
2925
+ let m = vm + d, y = vy;
2926
+ if (m < 0) {
2927
+ m = 11;
2928
+ y--;
2929
+ }
2930
+ if (m > 11) {
2931
+ m = 0;
2932
+ y++;
2933
+ }
2934
+ setVm(m);
2935
+ setVy(y);
2936
+ };
2937
+ const monthGrid = (y, m) => {
2938
+ const startPad = new Date(y, m, 1).getDay();
2939
+ const cells = [];
2940
+ for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
2941
+ return /* @__PURE__ */ jsxs37("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
2942
+ DOW.map((d) => /* @__PURE__ */ jsx43("span", { className: "fd-cal-dow", children: d }, d)),
2943
+ cells.map((d, i) => /* @__PURE__ */ jsx43(
2944
+ "button",
2945
+ {
2946
+ type: "button",
2947
+ className: ["fd-cal-day", d.getMonth() !== m ? "is-out" : "", iso(d) === iso(today) ? "is-today" : "", inRange(d) ? "in-range" : "", isEdge(d) ? "is-edge" : ""].filter(Boolean).join(" "),
2948
+ onClick: () => clickDay(d),
2949
+ onMouseEnter: () => range && setHover(iso(d)),
2950
+ children: d.getDate()
2951
+ },
2952
+ i
2953
+ ))
2954
+ ] });
2955
+ };
2956
+ const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
2957
+ return /* @__PURE__ */ jsxs37("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
2958
+ /* @__PURE__ */ jsxs37("div", { className: "fd-cal-head", children: [
2959
+ /* @__PURE__ */ jsx43("button", { type: "button", className: "fd-btn-icon", "aria-label": "Previous", onClick: () => mode2 === "years" ? setVy(vy - 12) : mode2 === "months" ? setVy(vy - 1) : nav(-1), children: /* @__PURE__ */ jsx43("i", { className: "ph ph-caret-left" }) }),
2960
+ /* @__PURE__ */ jsxs37("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
2961
+ mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
2962
+ /* @__PURE__ */ jsx43("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
2963
+ ] }),
2964
+ months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx43("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
2965
+ /* @__PURE__ */ jsx43("button", { type: "button", className: "fd-btn-icon", "aria-label": "Next", onClick: () => mode2 === "years" ? setVy(vy + 12) : mode2 === "months" ? setVy(vy + 1) : nav(1), children: /* @__PURE__ */ jsx43("i", { className: "ph ph-caret-right" }) })
2966
+ ] }),
2967
+ mode2 === "days" ? /* @__PURE__ */ jsxs37("div", { style: { display: "flex", gap: 18 }, children: [
2968
+ monthGrid(vy, vm),
2969
+ months > 1 ? monthGrid(nextY, nextM) : null
2970
+ ] }) : mode2 === "months" ? /* @__PURE__ */ jsx43("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx43(
2971
+ "button",
2972
+ {
2973
+ type: "button",
2974
+ className: "fd-cal-cell" + (i === vm && s && s.getFullYear() === vy ? " is-sel" : ""),
2975
+ onClick: () => {
2976
+ setVm(i);
2977
+ setMode("days");
2978
+ },
2979
+ children: m.slice(0, 3)
2980
+ },
2981
+ m
2982
+ )) }) : /* @__PURE__ */ jsx43("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx43(
2983
+ "button",
2984
+ {
2985
+ type: "button",
2986
+ className: "fd-cal-cell" + (y === vy ? " is-sel" : ""),
2987
+ onClick: () => {
2988
+ setVy(y);
2989
+ setMode("months");
2990
+ },
2991
+ children: y
2992
+ },
2993
+ y
2994
+ )) }),
2995
+ /* @__PURE__ */ jsxs37("div", { className: "fd-cal-foot", children: [
2996
+ /* @__PURE__ */ jsx43(
2997
+ "button",
2998
+ {
2999
+ type: "button",
3000
+ className: "fd-btn fd-btn-link",
3001
+ style: { fontSize: 12.5 },
3002
+ onClick: () => {
3003
+ setVy(today.getFullYear());
3004
+ setVm(today.getMonth());
3005
+ setMode("days");
3006
+ },
3007
+ children: "Today"
3008
+ }
3009
+ ),
3010
+ /* @__PURE__ */ jsx43("span", { style: { flex: 1 } }),
3011
+ range && sel.start ? /* @__PURE__ */ jsxs37("span", { className: "fd-body-sm fd-muted", children: [
3012
+ fmt(sel.start),
3013
+ sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
3014
+ ] }) : null
3015
+ ] })
3016
+ ] });
3017
+ }
3018
+ function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
3019
+ const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
3020
+ const [open, setOpen] = React22.useState(false);
3021
+ const rootRef = React22.useRef(null);
3022
+ const boxRef = React22.useRef(null);
3023
+ const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
3024
+ const toggle = () => {
3025
+ if (!disabled) setOpen(!open);
3026
+ };
3027
+ return /* @__PURE__ */ jsxs37("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
3028
+ label ? /* @__PURE__ */ jsx43(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
3029
+ /* @__PURE__ */ jsxs37("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
3030
+ /* @__PURE__ */ jsx43("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx43("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
3031
+ /* @__PURE__ */ jsx43(
3032
+ "button",
3033
+ {
3034
+ type: "button",
3035
+ id: fieldId,
3036
+ "aria-labelledby": ariaLabelledBy,
3037
+ title: truncationTitle(display),
3038
+ disabled,
3039
+ onKeyDown: (e) => {
3040
+ if (e.key === "Enter" || e.key === " ") {
3041
+ e.preventDefault();
3042
+ toggle();
3043
+ }
3044
+ },
3045
+ style: { all: "unset", flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", cursor: "inherit", color: display ? "var(--text)" : "var(--text-muted)" },
3046
+ ...rest,
3047
+ children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
3048
+ }
3049
+ ),
3050
+ /* @__PURE__ */ jsx43("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx43("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
3051
+ ] }),
3052
+ /* @__PURE__ */ jsx43(
3053
+ Popover,
3054
+ {
3055
+ open,
3056
+ anchorRef: boxRef,
3057
+ triggerRef: rootRef,
3058
+ onClose: () => setOpen(false),
3059
+ placement: "bottom-start",
3060
+ offset: 6,
3061
+ role: "presentation",
3062
+ style: { width: "max-content" },
3063
+ children: /* @__PURE__ */ jsx43(
3064
+ Calendar,
3065
+ {
3066
+ range,
3067
+ months: range ? 2 : 1,
3068
+ value,
3069
+ onPick: (v) => {
3070
+ onChange && onChange({ target: { value: v } });
3071
+ if (!range || v.start && v.end) setOpen(false);
3072
+ }
3073
+ }
3074
+ )
3075
+ }
3076
+ ),
3077
+ error ? /* @__PURE__ */ jsxs37("span", { className: "fd-field-error", children: [
3078
+ /* @__PURE__ */ jsx43("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3079
+ error
3080
+ ] }) : help ? /* @__PURE__ */ jsx43("span", { className: "fd-field-help", children: help }) : null
3081
+ ] });
3082
+ }
3083
+
3084
+ // src/components/forms/Textarea.tsx
3085
+ import { jsx as jsx44, jsxs as jsxs38 } from "react/jsx-runtime";
3086
+ function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
3087
+ const fieldId = useFieldId(id);
3088
+ const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
3089
+ return /* @__PURE__ */ jsxs38("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
3090
+ label ? /* @__PURE__ */ jsx44(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
3091
+ /* @__PURE__ */ jsx44("div", { className: box, children: /* @__PURE__ */ jsx44("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
3092
+ error ? /* @__PURE__ */ jsxs38("span", { className: "fd-field-error", children: [
3093
+ /* @__PURE__ */ jsx44("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
3094
+ error
3095
+ ] }) : help ? /* @__PURE__ */ jsx44("span", { className: "fd-field-help", children: help }) : null
3096
+ ] });
3097
+ }
3098
+
3099
+ // src/components/data/FilterBar.tsx
3100
+ import { jsx as jsx45, jsxs as jsxs39 } from "react/jsx-runtime";
2719
3101
  var isSet = (v) => !(v == null || v === "" || v === false);
3102
+ function isFieldSet(field, value) {
3103
+ switch (field.type) {
3104
+ case "text":
3105
+ case "select":
3106
+ return isSet(value);
3107
+ case "multiSelect":
3108
+ case "pasteList": {
3109
+ const v = value;
3110
+ return !!v && Array.isArray(v.values) && v.values.length > 0;
3111
+ }
3112
+ case "range": {
3113
+ const v = value;
3114
+ return !!v && (v.min != null || v.max != null);
3115
+ }
3116
+ case "date": {
3117
+ const v = value;
3118
+ if (!v) return false;
3119
+ return v.kind === "withinDays" ? v.days != null : !!(v.from || v.to);
3120
+ }
3121
+ }
3122
+ }
3123
+ function chipLabel(field, value) {
3124
+ switch (field.type) {
3125
+ case "text":
3126
+ return String(value ?? "");
3127
+ case "select": {
3128
+ const chosen = field.options.find((o) => o.value === value);
3129
+ return chosen ? chosen.label : String(value ?? "");
3130
+ }
3131
+ case "multiSelect":
3132
+ case "pasteList": {
3133
+ const v = value;
3134
+ if (!v || !v.values.length) return "";
3135
+ const prefix = v.operator === "notIn" ? "Not " : "";
3136
+ return v.values.length <= 2 ? prefix + v.values.map((o) => o.label).join(", ") : prefix + v.values.length + " selected";
3137
+ }
3138
+ case "range": {
3139
+ const v = value;
3140
+ if (!v) return "";
3141
+ if (v.min != null && v.max != null) return v.min + "\u2013" + v.max;
3142
+ if (v.min != null) return "\u2265 " + v.min;
3143
+ if (v.max != null) return "\u2264 " + v.max;
3144
+ return "";
3145
+ }
3146
+ case "date": {
3147
+ const v = value;
3148
+ if (!v) return "";
3149
+ if (v.kind === "withinDays") return "Last " + v.days + " day" + (v.days === 1 ? "" : "s");
3150
+ return (v.from || "\u2026") + " \u2192 " + (v.to || "\u2026");
3151
+ }
3152
+ }
3153
+ }
3154
+ function OperatorToggle({
3155
+ operator,
3156
+ onChange,
3157
+ label
3158
+ }) {
3159
+ return /* @__PURE__ */ jsx45(
3160
+ SegmentedControl,
3161
+ {
3162
+ "aria-label": label + " \u2014 include or exclude",
3163
+ options: [
3164
+ { value: "in", label: "Is any of" },
3165
+ { value: "notIn", label: "Is none of" }
3166
+ ],
3167
+ value: operator,
3168
+ onChange: (v) => onChange(v)
3169
+ }
3170
+ );
3171
+ }
3172
+ function EditPopover({ zIndex, width, children }) {
3173
+ return /* @__PURE__ */ jsx45(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx45(
3174
+ "span",
3175
+ {
3176
+ className: "fd-view-enter",
3177
+ style: {
3178
+ position: "absolute",
3179
+ top: "calc(100% + 6px)",
3180
+ left: 0,
3181
+ zIndex,
3182
+ width,
3183
+ maxWidth: "calc(100vw - 32px)",
3184
+ display: "block",
3185
+ background: "var(--surface)",
3186
+ border: "1px solid var(--border)",
3187
+ borderRadius: 10,
3188
+ boxShadow: "0 16px 44px rgba(11,13,17,.18)",
3189
+ padding: "var(--s-8)"
3190
+ },
3191
+ children
3192
+ }
3193
+ ) });
3194
+ }
3195
+ function MultiSelectPanel({
3196
+ field,
3197
+ value,
3198
+ onChange,
3199
+ onClose
3200
+ }) {
3201
+ const operator = value?.operator ?? "in";
3202
+ const selected = value?.values ?? [];
3203
+ const [query, setQuery] = React23.useState("");
3204
+ const [asyncOptions, setAsyncOptions] = React23.useState(null);
3205
+ const [loading, setLoading] = React23.useState(!!field.loadOptions);
3206
+ const [active, setActive] = React23.useState(0);
3207
+ const inputRef = React23.useRef(null);
3208
+ const listId = React23.useId();
3209
+ React23.useEffect(() => {
3210
+ inputRef.current?.focus();
3211
+ }, []);
3212
+ React23.useEffect(() => {
3213
+ if (!field.loadOptions) return;
3214
+ let cancelled = false;
3215
+ setLoading(true);
3216
+ const loadOptions = field.loadOptions;
3217
+ const t = setTimeout(() => {
3218
+ loadOptions(query).then((opts) => {
3219
+ if (!cancelled) {
3220
+ setAsyncOptions(opts);
3221
+ setLoading(false);
3222
+ }
3223
+ }).catch(() => {
3224
+ if (!cancelled) {
3225
+ setAsyncOptions([]);
3226
+ setLoading(false);
3227
+ }
3228
+ });
3229
+ }, 300);
3230
+ return () => {
3231
+ cancelled = true;
3232
+ clearTimeout(t);
3233
+ };
3234
+ }, [query, field.loadOptions]);
3235
+ const options = field.loadOptions ? asyncOptions ?? [] : (field.options ?? []).filter((o) => o.label.toLowerCase().includes(query.toLowerCase()));
3236
+ React23.useEffect(() => {
3237
+ setActive(0);
3238
+ }, [query, options.length]);
3239
+ const isSelected = (o) => selected.some((s) => s.value === o.value);
3240
+ const toggle = (o) => {
3241
+ const next = isSelected(o) ? selected.filter((s) => s.value !== o.value) : [...selected, o];
3242
+ onChange({ operator, values: next });
3243
+ };
3244
+ const activeId = options[active] ? listId + "-opt-" + active : void 0;
3245
+ return /* @__PURE__ */ jsxs39("span", { className: "fd-stack", style: { gap: "var(--s-8)", width: 260 }, children: [
3246
+ /* @__PURE__ */ jsx45(OperatorToggle, { operator, onChange: (op) => onChange({ operator: op, values: selected }), label: field.label }),
3247
+ /* @__PURE__ */ jsx45(
3248
+ "input",
3249
+ {
3250
+ ref: inputRef,
3251
+ role: "combobox",
3252
+ "aria-expanded": "true",
3253
+ "aria-controls": listId,
3254
+ "aria-autocomplete": "list",
3255
+ "aria-activedescendant": activeId,
3256
+ "aria-label": field.label,
3257
+ className: "fd-input",
3258
+ style: { width: "100%", padding: "6px 10px" },
3259
+ value: query,
3260
+ placeholder: field.placeholder || "Search\u2026",
3261
+ onChange: (e) => setQuery(e.target.value),
3262
+ onKeyDown: (e) => {
3263
+ if (e.key === "ArrowDown") {
3264
+ e.preventDefault();
3265
+ setActive((a) => Math.min(a + 1, options.length - 1));
3266
+ } else if (e.key === "ArrowUp") {
3267
+ e.preventDefault();
3268
+ setActive((a) => Math.max(a - 1, 0));
3269
+ } else if (e.key === "Enter") {
3270
+ e.preventDefault();
3271
+ if (options[active]) toggle(options[active]);
3272
+ } else if (e.key === "Escape") {
3273
+ e.stopPropagation();
3274
+ onClose();
3275
+ }
3276
+ }
3277
+ }
3278
+ ),
3279
+ loading ? /* @__PURE__ */ jsxs39("span", { className: "fd-row fd-body-sm fd-muted", style: { gap: "var(--s-4)" }, children: [
3280
+ /* @__PURE__ */ jsx45("span", { className: "fd-spinner", "aria-hidden": "true" }),
3281
+ " Loading\u2026"
3282
+ ] }) : options.length === 0 ? /* @__PURE__ */ jsx45("span", { className: "fd-body-sm fd-muted", children: "No matches" }) : /* @__PURE__ */ jsx45(
3283
+ "span",
3284
+ {
3285
+ id: listId,
3286
+ role: "listbox",
3287
+ "aria-label": field.label,
3288
+ "aria-multiselectable": "true",
3289
+ className: "fd-stack",
3290
+ style: { gap: 2, maxHeight: 220, overflowY: "auto" },
3291
+ children: options.map((o, i) => {
3292
+ const on = isSelected(o);
3293
+ return /* @__PURE__ */ jsxs39(
3294
+ "button",
3295
+ {
3296
+ type: "button",
3297
+ id: listId + "-opt-" + i,
3298
+ role: "option",
3299
+ "aria-selected": on,
3300
+ className: "fd-row",
3301
+ onMouseEnter: () => setActive(i),
3302
+ onClick: () => toggle(o),
3303
+ style: {
3304
+ gap: "var(--s-8)",
3305
+ padding: "4px 8px",
3306
+ borderRadius: 7,
3307
+ border: 0,
3308
+ width: "100%",
3309
+ textAlign: "left",
3310
+ cursor: "pointer",
3311
+ background: i === active ? "var(--surface-brand)" : "transparent"
3312
+ },
3313
+ children: [
3314
+ /* @__PURE__ */ jsx45("i", { className: on ? "ph ph-check-square" : "ph ph-square", "aria-hidden": "true" }),
3315
+ /* @__PURE__ */ jsx45("span", { className: "fd-body-sm", style: { flex: 1, color: "var(--text)" }, children: o.label })
3316
+ ]
3317
+ },
3318
+ o.value
3319
+ );
3320
+ })
3321
+ }
3322
+ ),
3323
+ selected.length > 0 ? /* @__PURE__ */ jsxs39("span", { className: "fd-body-sm fd-muted", children: [
3324
+ selected.length,
3325
+ " selected"
3326
+ ] }) : null
3327
+ ] });
3328
+ }
3329
+ function RangePanel({
3330
+ field,
3331
+ value,
3332
+ onChange,
3333
+ onClose
3334
+ }) {
3335
+ const min = value?.min;
3336
+ const max = value?.max;
3337
+ const rangeError = min != null && max != null && min > max ? "Must be \u2265 " + (field.minLabel || "min").toLowerCase() : void 0;
3338
+ return /* @__PURE__ */ jsxs39("span", { className: "fd-stack", style: { gap: "var(--s-8)", width: 240 }, children: [
3339
+ /* @__PURE__ */ jsx45(
3340
+ NumberInput,
3341
+ {
3342
+ label: field.minLabel || "At least",
3343
+ value: min ?? "",
3344
+ min: field.min,
3345
+ max: field.max,
3346
+ step: field.step,
3347
+ placeholder: field.minPlaceholder,
3348
+ onChange: (e) => onChange({ min: e.target.value, max })
3349
+ }
3350
+ ),
3351
+ /* @__PURE__ */ jsx45(
3352
+ NumberInput,
3353
+ {
3354
+ label: field.maxLabel || "At most",
3355
+ value: max ?? "",
3356
+ min: field.min,
3357
+ max: field.max,
3358
+ step: field.step,
3359
+ error: rangeError,
3360
+ placeholder: field.maxPlaceholder,
3361
+ onChange: (e) => onChange({ min, max: e.target.value })
3362
+ }
3363
+ ),
3364
+ /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" })
3365
+ ] });
3366
+ }
3367
+ function DatePanel({
3368
+ field,
3369
+ value,
3370
+ onChange,
3371
+ onClose
3372
+ }) {
3373
+ const kind = value?.kind ?? "withinDays";
3374
+ return /* @__PURE__ */ jsxs39("span", { className: "fd-stack", style: { gap: "var(--s-8)", width: 300 }, children: [
3375
+ /* @__PURE__ */ jsx45(
3376
+ SegmentedControl,
3377
+ {
3378
+ "aria-label": field.label + " \u2014 relative or between dates",
3379
+ options: [
3380
+ { value: "withinDays", label: "Within last N days" },
3381
+ { value: "between", label: "Between dates" }
3382
+ ],
3383
+ value: kind,
3384
+ onChange: (k) => {
3385
+ if (k === "withinDays") {
3386
+ onChange({ kind: "withinDays", days: value?.kind === "withinDays" ? value.days : field.defaultDays ?? 30 });
3387
+ } else {
3388
+ onChange({ kind: "between", from: value?.kind === "between" ? value.from : "", to: value?.kind === "between" ? value.to : "" });
3389
+ }
3390
+ }
3391
+ }
3392
+ ),
3393
+ kind === "withinDays" ? /* @__PURE__ */ jsx45(
3394
+ NumberInput,
3395
+ {
3396
+ label: "Days",
3397
+ min: 1,
3398
+ value: value?.kind === "withinDays" ? value.days : field.defaultDays ?? 30,
3399
+ onChange: (e) => onChange({ kind: "withinDays", days: e.target.value })
3400
+ }
3401
+ ) : /* @__PURE__ */ jsx45(
3402
+ DatePicker,
3403
+ {
3404
+ range: true,
3405
+ label: "Date range",
3406
+ value: value?.kind === "between" ? { start: value.from, end: value.to } : void 0,
3407
+ onChange: (e) => onChange({ kind: "between", from: e.target.value.start || "", to: e.target.value.end || "" })
3408
+ }
3409
+ ),
3410
+ /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" })
3411
+ ] });
3412
+ }
3413
+ function PasteListPanel({
3414
+ field,
3415
+ value,
3416
+ onChange,
3417
+ onClose
3418
+ }) {
3419
+ const operator = value?.operator ?? "in";
3420
+ const selected = value?.values ?? [];
3421
+ const [text, setText] = React23.useState("");
3422
+ const [loading, setLoading] = React23.useState(false);
3423
+ const [unmatched, setUnmatched] = React23.useState([]);
3424
+ const [error, setError] = React23.useState(null);
3425
+ const wrapRef = React23.useRef(null);
3426
+ React23.useEffect(() => {
3427
+ wrapRef.current?.querySelector("textarea")?.focus();
3428
+ }, []);
3429
+ const doResolve = () => {
3430
+ const tokens = text.split(/[\n,]/).map((t) => t.trim()).filter(Boolean);
3431
+ if (!tokens.length) return;
3432
+ setLoading(true);
3433
+ setError(null);
3434
+ field.resolve(tokens).then((result) => {
3435
+ setLoading(false);
3436
+ setUnmatched(result.unmatched);
3437
+ const merged = new Map(selected.map((s) => [s.value, s]));
3438
+ for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
3439
+ onChange({ operator, values: Array.from(merged.values()) });
3440
+ setText("");
3441
+ }).catch((err) => {
3442
+ setLoading(false);
3443
+ setError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
3444
+ });
3445
+ };
3446
+ return /* @__PURE__ */ jsxs39("span", { className: "fd-stack", style: { gap: "var(--s-8)", width: 320 }, children: [
3447
+ /* @__PURE__ */ jsx45(OperatorToggle, { operator, onChange: (op) => onChange({ operator: op, values: selected }), label: field.label }),
3448
+ /* @__PURE__ */ jsx45("span", { ref: wrapRef, children: /* @__PURE__ */ jsx45(
3449
+ Textarea,
3450
+ {
3451
+ "aria-label": field.label + " \u2014 paste a list",
3452
+ rows: 4,
3453
+ placeholder: field.placeholder || "Paste names, one per line or comma-separated",
3454
+ value: text,
3455
+ disabled: loading,
3456
+ onChange: (e) => setText(e.target.value),
3457
+ onKeyDown: (e) => {
3458
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
3459
+ e.preventDefault();
3460
+ doResolve();
3461
+ }
3462
+ }
3463
+ }
3464
+ ) }),
3465
+ /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: doResolve, disabled: loading || !text.trim(), children: loading ? "Resolving\u2026" : "Resolve" }),
3466
+ error ? /* @__PURE__ */ jsx45(Banner, { tone: "danger", title: "Couldn't resolve the list", detail: error }) : null,
3467
+ unmatched.length > 0 ? /* @__PURE__ */ jsx45(Banner, { tone: "warn", title: unmatched.length + " didn't match", detail: unmatched.join(", ") }) : null,
3468
+ selected.length > 0 ? /* @__PURE__ */ jsxs39("span", { className: "fd-stack", style: { gap: "var(--s-4)" }, children: [
3469
+ /* @__PURE__ */ jsxs39("span", { className: "fd-body-sm fd-muted", children: [
3470
+ selected.length,
3471
+ " matched"
3472
+ ] }),
3473
+ /* @__PURE__ */ jsx45("span", { className: "fd-row", style: { flexWrap: "wrap", gap: "var(--s-4)" }, children: selected.map((v) => /* @__PURE__ */ jsx45(Tag, { onRemove: () => onChange({ operator, values: selected.filter((s) => s.value !== v.value) }), children: v.label }, v.value)) })
3474
+ ] }) : null,
3475
+ /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, children: "Done" })
3476
+ ] });
3477
+ }
2720
3478
  function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align = "left", className = "", ...rest }) {
2721
- const [panel, setPanel] = React20.useState(null);
3479
+ const [panel, setPanel] = React23.useState(null);
2722
3480
  const zIndex = useOverlayLayer(!!panel);
2723
- const rootRef = React20.useRef(null);
2724
- const textInputRef = React20.useRef(null);
2725
- const optionsRef = React20.useRef(null);
3481
+ const rootRef = React23.useRef(null);
3482
+ const textInputRef = React23.useRef(null);
3483
+ const optionsRef = React23.useRef(null);
2726
3484
  const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
2727
- const dismissible = !!panel && (panel.kind === "add" || panel.kind === "edit" && editingField?.type === "select");
2728
- React20.useEffect(() => {
3485
+ const dismissible = !!panel && (panel.kind === "add" || panel.kind === "edit" && editingField?.type !== "text");
3486
+ React23.useEffect(() => {
2729
3487
  if (!dismissible) return;
2730
3488
  const away = (e) => {
3489
+ const target = e.target;
3490
+ if (target.closest && target.closest(".fd-pop")) return;
2731
3491
  if (rootRef.current && !rootRef.current.contains(e.target)) setPanel(null);
2732
3492
  };
2733
3493
  const esc = (e) => {
@@ -2740,7 +3500,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2740
3500
  document.removeEventListener("keydown", esc);
2741
3501
  };
2742
3502
  }, [dismissible]);
2743
- React20.useEffect(() => {
3503
+ React23.useEffect(() => {
2744
3504
  if (!panel || panel.kind !== "edit") return;
2745
3505
  if (editingField?.type === "text") {
2746
3506
  textInputRef.current?.focus();
@@ -2749,20 +3509,20 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2749
3509
  target?.focus();
2750
3510
  }
2751
3511
  }, [panel]);
2752
- const addableFields = fields.filter((f) => !isSet(filters[f.key]));
3512
+ const addableFields = fields.filter((f) => !isFieldSet(f, filters[f.key]));
2753
3513
  const startEditing = (key) => setPanel({ kind: "edit", key });
2754
- return /* @__PURE__ */ jsxs35("span", { className, style: { position: "relative", display: "inline-flex", flexWrap: "wrap", alignItems: "center", gap: 8 }, ref: rootRef, ...rest, children: [
3514
+ return /* @__PURE__ */ jsxs39("span", { className, style: { position: "relative", display: "inline-flex", flexWrap: "wrap", alignItems: "center", gap: 8 }, ref: rootRef, ...rest, children: [
2755
3515
  fields.map((field) => {
2756
3516
  const value = filters[field.key];
2757
3517
  const editing = panel?.kind === "edit" && panel.key === field.key;
2758
3518
  if (editing && field.type === "text") {
2759
- return /* @__PURE__ */ jsxs35(
3519
+ return /* @__PURE__ */ jsxs39(
2760
3520
  "span",
2761
3521
  {
2762
3522
  className: "fd-tag",
2763
3523
  style: { background: "var(--surface-brand)", borderColor: "var(--border-brand)", cursor: "text" },
2764
3524
  children: [
2765
- /* @__PURE__ */ jsx41(
3525
+ /* @__PURE__ */ jsx45(
2766
3526
  "input",
2767
3527
  {
2768
3528
  ref: textInputRef,
@@ -2781,7 +3541,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2781
3541
  style: { all: "unset", minWidth: 90, color: "var(--text-on-surface-brand)" }
2782
3542
  }
2783
3543
  ),
2784
- isSet(value) ? /* @__PURE__ */ jsx41(
3544
+ isSet(value) ? /* @__PURE__ */ jsx45(
2785
3545
  "span",
2786
3546
  {
2787
3547
  className: "fd-tag-remove",
@@ -2792,7 +3552,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2792
3552
  onFilterRemove(field.key);
2793
3553
  setPanel(null);
2794
3554
  },
2795
- children: /* @__PURE__ */ jsx41("i", { className: "ph ph-x", "aria-hidden": "true" })
3555
+ children: /* @__PURE__ */ jsx45("i", { className: "ph ph-x", "aria-hidden": "true" })
2796
3556
  }
2797
3557
  ) : null
2798
3558
  ]
@@ -2802,22 +3562,22 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2802
3562
  }
2803
3563
  if (editing && field.type === "select") {
2804
3564
  const chosen = field.options.find((o) => o.value === value);
2805
- return /* @__PURE__ */ jsxs35("span", { style: { position: "relative", display: "inline-flex" }, children: [
2806
- /* @__PURE__ */ jsxs35(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
3565
+ return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
3566
+ /* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
2807
3567
  if (isSet(value)) onFilterRemove(field.key);
2808
3568
  setPanel(null);
2809
3569
  }, children: [
2810
3570
  field.label,
2811
3571
  chosen ? ": " + chosen.label : ""
2812
3572
  ] }),
2813
- /* @__PURE__ */ jsx41(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx41(
3573
+ /* @__PURE__ */ jsx45(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx45(
2814
3574
  "span",
2815
3575
  {
2816
3576
  className: "fd-view-enter",
2817
3577
  style: { position: "absolute", top: "calc(100% + 6px)", left: 0, zIndex, minWidth: 200, maxWidth: "calc(100vw - 32px)", display: "block", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, boxShadow: "0 16px 44px rgba(11,13,17,.18)", padding: 8 },
2818
- children: /* @__PURE__ */ jsx41("span", { className: "fd-stack", role: "listbox", "aria-label": field.label, ref: optionsRef, style: { gap: 2 }, children: field.options.map((o) => {
3578
+ children: /* @__PURE__ */ jsx45("span", { className: "fd-stack", role: "listbox", "aria-label": field.label, ref: optionsRef, style: { gap: 2 }, children: field.options.map((o) => {
2819
3579
  const on = o.value === value;
2820
- return /* @__PURE__ */ jsx41(
3580
+ return /* @__PURE__ */ jsx45(
2821
3581
  "button",
2822
3582
  {
2823
3583
  type: "button",
@@ -2829,7 +3589,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2829
3589
  setPanel(null);
2830
3590
  },
2831
3591
  style: { gap: 8, padding: "4px 8px", borderRadius: 7, border: 0, width: "100%", textAlign: "left", cursor: "pointer", background: on ? "var(--surface-brand)" : "transparent" },
2832
- children: /* @__PURE__ */ jsx41("span", { className: "fd-body-sm", style: { flex: 1, fontWeight: on ? 700 : 500, color: on ? "var(--text-on-surface-brand)" : "var(--text)" }, children: o.label })
3592
+ children: /* @__PURE__ */ jsx45("span", { className: "fd-body-sm", style: { flex: 1, fontWeight: on ? 700 : 500, color: on ? "var(--text-on-surface-brand)" : "var(--text)" }, children: o.label })
2833
3593
  },
2834
3594
  o.value
2835
3595
  );
@@ -2838,19 +3598,69 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2838
3598
  ) })
2839
3599
  ] }, field.key);
2840
3600
  }
2841
- if (isSet(value)) {
2842
- const chosen = field.type === "select" ? field.options.find((o) => o.value === value) : void 0;
2843
- const display = chosen ? chosen.label : String(value);
2844
- return /* @__PURE__ */ jsxs35(Tag, { selected: true, onClick: () => startEditing(field.key), onRemove: () => onFilterRemove(field.key), children: [
3601
+ if (editing && field.type === "multiSelect") {
3602
+ const mv = value;
3603
+ return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
3604
+ /* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
3605
+ if (isFieldSet(field, value)) onFilterRemove(field.key);
3606
+ setPanel(null);
3607
+ }, children: [
3608
+ field.label,
3609
+ isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
3610
+ ] }),
3611
+ /* @__PURE__ */ jsx45(EditPopover, { zIndex, width: 260, children: /* @__PURE__ */ jsx45(MultiSelectPanel, { field, value: mv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
3612
+ ] }, field.key);
3613
+ }
3614
+ if (editing && field.type === "range") {
3615
+ const rv = value;
3616
+ return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
3617
+ /* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
3618
+ if (isFieldSet(field, value)) onFilterRemove(field.key);
3619
+ setPanel(null);
3620
+ }, children: [
3621
+ field.label,
3622
+ isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
3623
+ ] }),
3624
+ /* @__PURE__ */ jsx45(EditPopover, { zIndex, width: 240, children: /* @__PURE__ */ jsx45(RangePanel, { field, value: rv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
3625
+ ] }, field.key);
3626
+ }
3627
+ if (editing && field.type === "date") {
3628
+ const dv = value;
3629
+ return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
3630
+ /* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
3631
+ if (isFieldSet(field, value)) onFilterRemove(field.key);
3632
+ setPanel(null);
3633
+ }, children: [
3634
+ field.label,
3635
+ isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
3636
+ ] }),
3637
+ /* @__PURE__ */ jsx45(EditPopover, { zIndex, width: 300, children: /* @__PURE__ */ jsx45(DatePanel, { field, value: dv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
3638
+ ] }, field.key);
3639
+ }
3640
+ if (editing && field.type === "pasteList") {
3641
+ const pv = value;
3642
+ return /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
3643
+ /* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => setPanel(null), onRemove: () => {
3644
+ if (isFieldSet(field, value)) onFilterRemove(field.key);
3645
+ setPanel(null);
3646
+ }, children: [
3647
+ field.label,
3648
+ isFieldSet(field, value) ? ": " + chipLabel(field, value) : ""
3649
+ ] }),
3650
+ /* @__PURE__ */ jsx45(EditPopover, { zIndex, width: 320, children: /* @__PURE__ */ jsx45(PasteListPanel, { field, value: pv, onChange: (v) => onFilterChange(field.key, v), onClose: () => setPanel(null) }) })
3651
+ ] }, field.key);
3652
+ }
3653
+ if (isFieldSet(field, value)) {
3654
+ return /* @__PURE__ */ jsxs39(Tag, { selected: true, onClick: () => startEditing(field.key), onRemove: () => onFilterRemove(field.key), children: [
2845
3655
  field.label,
2846
3656
  ": ",
2847
- display
3657
+ chipLabel(field, value)
2848
3658
  ] }, field.key);
2849
3659
  }
2850
3660
  return null;
2851
3661
  }),
2852
- addableFields.length > 0 ? /* @__PURE__ */ jsxs35("span", { style: { position: "relative", display: "inline-flex" }, children: [
2853
- /* @__PURE__ */ jsx41(
3662
+ addableFields.length > 0 ? /* @__PURE__ */ jsxs39("span", { style: { position: "relative", display: "inline-flex" }, children: [
3663
+ /* @__PURE__ */ jsx45(
2854
3664
  Button,
2855
3665
  {
2856
3666
  size: "sm",
@@ -2862,14 +3672,14 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2862
3672
  children: "Filter"
2863
3673
  }
2864
3674
  ),
2865
- panel?.kind === "add" ? /* @__PURE__ */ jsx41(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx41(
3675
+ panel?.kind === "add" ? /* @__PURE__ */ jsx45(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx45(
2866
3676
  "span",
2867
3677
  {
2868
3678
  className: "fd-view-enter",
2869
3679
  style: { position: "absolute", top: "calc(100% + 6px)", [align]: 0, zIndex, width: 220, maxWidth: "calc(100vw - 32px)", display: "block", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, boxShadow: "0 16px 44px rgba(11,13,17,.18)", padding: 8 },
2870
- children: /* @__PURE__ */ jsxs35("span", { className: "fd-stack", role: "menu", "aria-label": "Add filter", style: { gap: 2 }, children: [
2871
- /* @__PURE__ */ jsx41("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Add filter" }),
2872
- addableFields.map((f) => /* @__PURE__ */ jsx41(
3680
+ children: /* @__PURE__ */ jsxs39("span", { className: "fd-stack", role: "menu", "aria-label": "Add filter", style: { gap: 2 }, children: [
3681
+ /* @__PURE__ */ jsx45("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Add filter" }),
3682
+ addableFields.map((f) => /* @__PURE__ */ jsx45(
2873
3683
  "button",
2874
3684
  {
2875
3685
  type: "button",
@@ -2877,7 +3687,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2877
3687
  className: "fd-row",
2878
3688
  onClick: () => startEditing(f.key),
2879
3689
  style: { gap: 8, padding: "4px 8px", borderRadius: 7, border: 0, width: "100%", textAlign: "left", cursor: "pointer", background: "transparent" },
2880
- children: /* @__PURE__ */ jsx41("span", { className: "fd-body-sm", style: { flex: 1, color: "var(--text)" }, children: f.label })
3690
+ children: /* @__PURE__ */ jsx45("span", { className: "fd-body-sm", style: { flex: 1, color: "var(--text)" }, children: f.label })
2881
3691
  },
2882
3692
  f.key
2883
3693
  ))
@@ -2889,7 +3699,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
2889
3699
  }
2890
3700
 
2891
3701
  // src/components/data/StatTile.tsx
2892
- import { jsx as jsx42, jsxs as jsxs36 } from "react/jsx-runtime";
3702
+ import { jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
2893
3703
  function isZeroDelta(delta) {
2894
3704
  if (!delta) return false;
2895
3705
  const match = delta.match(/[\d.]+/);
@@ -2900,23 +3710,23 @@ function StatTile({ label, value, sub, delta, invert = false, loading = false, c
2900
3710
  const isZero = isZeroDelta(delta);
2901
3711
  const isGood = invert ? isDecrease : !isDecrease;
2902
3712
  const deltaToneClass = isZero ? "fd-stat-delta-neutral" : isGood ? "fd-stat-delta-up" : "fd-stat-delta-down";
2903
- return /* @__PURE__ */ jsxs36("div", { className: ["fd-stat", compact3 ? "fd-stat-compact" : "", className].filter(Boolean).join(" "), ...rest, children: [
2904
- loading ? /* @__PURE__ */ jsx42("span", { className: "fd-skel fd-skel-text", style: { display: "block", height: compact3 ? 20 : 28, width: "62%" } }) : /* @__PURE__ */ jsxs36("span", { className: "fd-stat-top", children: [
2905
- /* @__PURE__ */ jsx42("span", { className: "fd-stat-figure", children: value }),
2906
- delta ? /* @__PURE__ */ jsxs36("span", { className: deltaToneClass, style: { fontWeight: 600, fontSize: "var(--body-sm-size)", flex: "none" }, children: [
2907
- /* @__PURE__ */ jsx42("i", { className: "ph ph-" + (isZero ? "minus" : "arrow-" + (isDecrease ? "down" : "up") + "-right"), "aria-hidden": "true" }),
3713
+ return /* @__PURE__ */ jsxs40("div", { className: ["fd-stat", compact3 ? "fd-stat-compact" : "", className].filter(Boolean).join(" "), ...rest, children: [
3714
+ loading ? /* @__PURE__ */ jsx46("span", { className: "fd-skel fd-skel-text", style: { display: "block", height: compact3 ? 20 : 28, width: "62%" } }) : /* @__PURE__ */ jsxs40("span", { className: "fd-stat-top", children: [
3715
+ /* @__PURE__ */ jsx46("span", { className: "fd-stat-figure", children: value }),
3716
+ delta ? /* @__PURE__ */ jsxs40("span", { className: deltaToneClass, style: { fontWeight: 600, fontSize: "var(--body-sm-size)", flex: "none" }, children: [
3717
+ /* @__PURE__ */ jsx46("i", { className: "ph ph-" + (isZero ? "minus" : "arrow-" + (isDecrease ? "down" : "up") + "-right"), "aria-hidden": "true" }),
2908
3718
  " ",
2909
3719
  delta
2910
3720
  ] }) : null
2911
3721
  ] }),
2912
- !loading && sub ? /* @__PURE__ */ jsx42("span", { className: "fd-stat-sub", children: sub }) : null,
2913
- loading ? /* @__PURE__ */ jsx42("span", { className: "fd-skel fd-skel-text", style: { display: "block", height: 10, width: "40%", marginTop: 8 } }) : /* @__PURE__ */ jsx42("span", { className: "fd-stat-label", style: { display: "block" }, children: label })
3722
+ !loading && sub ? /* @__PURE__ */ jsx46("span", { className: "fd-stat-sub", children: sub }) : null,
3723
+ loading ? /* @__PURE__ */ jsx46("span", { className: "fd-skel fd-skel-text", style: { display: "block", height: 10, width: "40%", marginTop: 8 } }) : /* @__PURE__ */ jsx46("span", { className: "fd-stat-label", style: { display: "block" }, children: label })
2914
3724
  ] });
2915
3725
  }
2916
3726
 
2917
3727
  // src/components/data/CodeBlock.tsx
2918
- import * as React21 from "react";
2919
- import { Fragment as Fragment6, jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
3728
+ import * as React24 from "react";
3729
+ import { Fragment as Fragment6, jsx as jsx47, jsxs as jsxs41 } from "react/jsx-runtime";
2920
3730
  var JS_KW = /^(?:const|let|var|function|return|if|else|for|while|do|new|class|extends|import|from|export|default|await|async|try|catch|finally|throw|typeof|instanceof|of|in|switch|case|break|continue|delete|void|yield|static|get|set|this|super|interface|type|enum|implements|public|private|protected|readonly|abstract|as|satisfies|declare|namespace)$/;
2921
3731
  var RULES = {
2922
3732
  js: [
@@ -3071,13 +3881,13 @@ function tokenize(src, lang) {
3071
3881
  return out;
3072
3882
  }
3073
3883
  function Highlighted({ code, lang }) {
3074
- const toks = React21.useMemo(() => tokenize(code, lang), [code, lang]);
3075
- return /* @__PURE__ */ jsx43(Fragment6, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx43("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
3884
+ const toks = React24.useMemo(() => tokenize(code, lang), [code, lang]);
3885
+ return /* @__PURE__ */ jsx47(Fragment6, { children: toks.map((tk, i) => tk.c ? /* @__PURE__ */ jsx47("span", { className: "tok-" + tk.c, children: tk.t }, i) : tk.t) });
3076
3886
  }
3077
3887
  function useCopy() {
3078
- const [done, setDone] = React21.useState(false);
3079
- const timer = React21.useRef(null);
3080
- React21.useEffect(() => () => {
3888
+ const [done, setDone] = React24.useState(false);
3889
+ const timer = React24.useRef(null);
3890
+ React24.useEffect(() => () => {
3081
3891
  if (timer.current) clearTimeout(timer.current);
3082
3892
  }, []);
3083
3893
  const copy = (text) => {
@@ -3113,37 +3923,37 @@ function CodeBlock({
3113
3923
  actions,
3114
3924
  className = ""
3115
3925
  }) {
3116
- const [wrap, setWrap] = React21.useState(!!wrapDefault);
3117
- const [open, setOpen] = React21.useState(false);
3926
+ const [wrap, setWrap] = React24.useState(!!wrapDefault);
3927
+ const [open, setOpen] = React24.useState(false);
3118
3928
  const [copied, copy] = useCopy();
3119
3929
  const body = String(code).replace(/\n$/, "");
3120
3930
  const lines = body.split("\n");
3121
3931
  const foldable = collapseAfter > 0 && lines.length > collapseAfter + 6;
3122
3932
  const shown = foldable && !open ? lines.slice(0, collapseAfter).join("\n") : body;
3123
- return /* @__PURE__ */ jsxs37("div", { className: ["fd-code", wrap ? "is-wrap" : "", className].filter(Boolean).join(" "), children: [
3124
- /* @__PURE__ */ jsxs37("div", { className: "fd-code-head", children: [
3125
- filename ? /* @__PURE__ */ jsx43("span", { className: "fd-code-file", children: filename }) : null,
3126
- /* @__PURE__ */ jsx43("span", { className: "fd-code-lang", children: languageLabel(language) }),
3127
- /* @__PURE__ */ jsx43("span", { className: "fd-code-spacer" }),
3933
+ return /* @__PURE__ */ jsxs41("div", { className: ["fd-code", wrap ? "is-wrap" : "", className].filter(Boolean).join(" "), children: [
3934
+ /* @__PURE__ */ jsxs41("div", { className: "fd-code-head", children: [
3935
+ filename ? /* @__PURE__ */ jsx47("span", { className: "fd-code-file", children: filename }) : null,
3936
+ /* @__PURE__ */ jsx47("span", { className: "fd-code-lang", children: languageLabel(language) }),
3937
+ /* @__PURE__ */ jsx47("span", { className: "fd-code-spacer" }),
3128
3938
  actions,
3129
- /* @__PURE__ */ jsx43("button", { type: "button", className: "fd-code-act", onClick: () => setWrap((v) => !v), "aria-pressed": wrap, title: wrap ? "No wrap" : "Soft wrap", children: /* @__PURE__ */ jsx43("i", { className: "ph ph-text-" + (wrap ? "columns" : "align-left"), "aria-hidden": "true" }) }),
3130
- copyable ? /* @__PURE__ */ jsxs37("button", { type: "button", className: "fd-code-act" + (copied ? " is-done" : ""), onClick: () => copy(body), children: [
3131
- /* @__PURE__ */ jsx43("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
3132
- /* @__PURE__ */ jsx43("span", { children: copied ? "Copied" : "Copy" })
3939
+ /* @__PURE__ */ jsx47("button", { type: "button", className: "fd-code-act", onClick: () => setWrap((v) => !v), "aria-pressed": wrap, title: wrap ? "No wrap" : "Soft wrap", children: /* @__PURE__ */ jsx47("i", { className: "ph ph-text-" + (wrap ? "columns" : "align-left"), "aria-hidden": "true" }) }),
3940
+ copyable ? /* @__PURE__ */ jsxs41("button", { type: "button", className: "fd-code-act" + (copied ? " is-done" : ""), onClick: () => copy(body), children: [
3941
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
3942
+ /* @__PURE__ */ jsx47("span", { children: copied ? "Copied" : "Copy" })
3133
3943
  ] }) : null
3134
3944
  ] }),
3135
- /* @__PURE__ */ jsxs37("div", { className: "fd-code-body", children: [
3136
- lineNumbers ? /* @__PURE__ */ jsx43("pre", { className: "fd-code-gutter", "aria-hidden": "true", children: shown.split("\n").map((_, i) => i + 1 + "\n").join("") }) : null,
3137
- /* @__PURE__ */ jsx43("pre", { className: "fd-code-pre", tabIndex: 0, children: /* @__PURE__ */ jsx43("code", { children: /* @__PURE__ */ jsx43(Highlighted, { code: shown, lang: language }) }) })
3945
+ /* @__PURE__ */ jsxs41("div", { className: "fd-code-body", children: [
3946
+ lineNumbers ? /* @__PURE__ */ jsx47("pre", { className: "fd-code-gutter", "aria-hidden": "true", children: shown.split("\n").map((_, i) => i + 1 + "\n").join("") }) : null,
3947
+ /* @__PURE__ */ jsx47("pre", { className: "fd-code-pre", tabIndex: 0, children: /* @__PURE__ */ jsx47("code", { children: /* @__PURE__ */ jsx47(Highlighted, { code: shown, lang: language }) }) })
3138
3948
  ] }),
3139
- foldable ? /* @__PURE__ */ jsxs37("button", { type: "button", className: "fd-code-fold", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
3140
- /* @__PURE__ */ jsx43("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" }),
3949
+ foldable ? /* @__PURE__ */ jsxs41("button", { type: "button", className: "fd-code-fold", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
3950
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" }),
3141
3951
  open ? "Collapse" : "Show all " + lines.length + " lines"
3142
3952
  ] }) : null
3143
3953
  ] });
3144
3954
  }
3145
3955
  function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" }) {
3146
- const [open, setOpen] = React21.useState(false);
3956
+ const [open, setOpen] = React24.useState(false);
3147
3957
  const [copied, copy] = useCopy();
3148
3958
  const raw = String(diff).replace(/\n$/, "");
3149
3959
  const all = raw.split("\n").map((line) => {
@@ -3157,40 +3967,40 @@ function DiffBlock({ diff = "", filename, collapseAfter = 34, className = "" })
3157
3967
  const dels = all.filter((l) => l.k === "del").length;
3158
3968
  const foldable = collapseAfter > 0 && all.length > collapseAfter + 6;
3159
3969
  const rows = foldable && !open ? all.slice(0, collapseAfter) : all;
3160
- return /* @__PURE__ */ jsxs37("div", { className: ["fd-code", "fd-diff", className].filter(Boolean).join(" "), children: [
3161
- /* @__PURE__ */ jsxs37("div", { className: "fd-code-head", children: [
3162
- /* @__PURE__ */ jsx43("i", { className: "ph ph-git-diff fd-code-icon", "aria-hidden": "true" }),
3163
- filename ? /* @__PURE__ */ jsx43("span", { className: "fd-code-file", children: filename }) : /* @__PURE__ */ jsx43("span", { className: "fd-code-lang", children: "Diff" }),
3164
- /* @__PURE__ */ jsxs37("span", { className: "fd-diff-stat fd-tabular", children: [
3165
- /* @__PURE__ */ jsxs37("span", { className: "is-add", children: [
3970
+ return /* @__PURE__ */ jsxs41("div", { className: ["fd-code", "fd-diff", className].filter(Boolean).join(" "), children: [
3971
+ /* @__PURE__ */ jsxs41("div", { className: "fd-code-head", children: [
3972
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-git-diff fd-code-icon", "aria-hidden": "true" }),
3973
+ filename ? /* @__PURE__ */ jsx47("span", { className: "fd-code-file", children: filename }) : /* @__PURE__ */ jsx47("span", { className: "fd-code-lang", children: "Diff" }),
3974
+ /* @__PURE__ */ jsxs41("span", { className: "fd-diff-stat fd-tabular", children: [
3975
+ /* @__PURE__ */ jsxs41("span", { className: "is-add", children: [
3166
3976
  "+",
3167
3977
  adds
3168
3978
  ] }),
3169
- /* @__PURE__ */ jsxs37("span", { className: "is-del", children: [
3979
+ /* @__PURE__ */ jsxs41("span", { className: "is-del", children: [
3170
3980
  "\u2212",
3171
3981
  dels
3172
3982
  ] })
3173
3983
  ] }),
3174
- /* @__PURE__ */ jsx43("span", { className: "fd-code-spacer" }),
3175
- /* @__PURE__ */ jsxs37("button", { type: "button", className: "fd-code-act" + (copied ? " is-done" : ""), onClick: () => copy(raw), children: [
3176
- /* @__PURE__ */ jsx43("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
3177
- /* @__PURE__ */ jsx43("span", { children: copied ? "Copied" : "Copy" })
3984
+ /* @__PURE__ */ jsx47("span", { className: "fd-code-spacer" }),
3985
+ /* @__PURE__ */ jsxs41("button", { type: "button", className: "fd-code-act" + (copied ? " is-done" : ""), onClick: () => copy(raw), children: [
3986
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-" + (copied ? "check" : "copy"), "aria-hidden": "true" }),
3987
+ /* @__PURE__ */ jsx47("span", { children: copied ? "Copied" : "Copy" })
3178
3988
  ] })
3179
3989
  ] }),
3180
- /* @__PURE__ */ jsx43("div", { className: "fd-diff-body", children: rows.map((r, i) => /* @__PURE__ */ jsxs37("div", { className: "fd-diff-line is-" + r.k, children: [
3181
- /* @__PURE__ */ jsx43("span", { className: "fd-diff-mark", "aria-hidden": "true", children: r.k === "add" ? "+" : r.k === "del" ? "\u2212" : "" }),
3182
- /* @__PURE__ */ jsx43("code", { children: r.k === "add" || r.k === "del" ? r.line.slice(1) : r.line })
3990
+ /* @__PURE__ */ jsx47("div", { className: "fd-diff-body", children: rows.map((r, i) => /* @__PURE__ */ jsxs41("div", { className: "fd-diff-line is-" + r.k, children: [
3991
+ /* @__PURE__ */ jsx47("span", { className: "fd-diff-mark", "aria-hidden": "true", children: r.k === "add" ? "+" : r.k === "del" ? "\u2212" : "" }),
3992
+ /* @__PURE__ */ jsx47("code", { children: r.k === "add" || r.k === "del" ? r.line.slice(1) : r.line })
3183
3993
  ] }, i)) }),
3184
- foldable ? /* @__PURE__ */ jsxs37("button", { type: "button", className: "fd-code-fold", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
3185
- /* @__PURE__ */ jsx43("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" }),
3994
+ foldable ? /* @__PURE__ */ jsxs41("button", { type: "button", className: "fd-code-fold", onClick: () => setOpen((v) => !v), "aria-expanded": open, children: [
3995
+ /* @__PURE__ */ jsx47("i", { className: "ph ph-caret-" + (open ? "up" : "down"), "aria-hidden": "true" }),
3186
3996
  open ? "Collapse" : "Show all " + all.length + " lines"
3187
3997
  ] }) : null
3188
3998
  ] });
3189
3999
  }
3190
4000
 
3191
4001
  // src/components/data/Markdown.tsx
3192
- import * as React22 from "react";
3193
- import { jsx as jsx44, jsxs as jsxs38 } from "react/jsx-runtime";
4002
+ import * as React25 from "react";
4003
+ import { jsx as jsx48, jsxs as jsxs42 } from "react/jsx-runtime";
3194
4004
  var SAFE = /^(?:https?:|mailto:|tel:|#|\/|\.{1,2}\/)/i;
3195
4005
  var safeHref = (h) => SAFE.test(String(h || "").trim()) ? String(h).trim() : null;
3196
4006
  var INLINE = [
@@ -3220,22 +4030,22 @@ function inlineNodes(src, ctx, keyBase) {
3220
4030
  const { kind, m } = best;
3221
4031
  if (m.index > 0) out.push(rest.slice(0, m.index));
3222
4032
  const g = (i) => m[i];
3223
- if (kind === "code") out.push(/* @__PURE__ */ jsx44("code", { className: "fd-md-code", children: g(1) }, key()));
4033
+ if (kind === "code") out.push(/* @__PURE__ */ jsx48("code", { className: "fd-md-code", children: g(1) }, key()));
3224
4034
  else if (kind === "image") {
3225
4035
  const src2 = safeHref(g(2));
3226
- out.push(ctx.allowImages && src2 ? /* @__PURE__ */ jsx44("img", { className: "fd-md-img", src: src2, alt: g(1) || "", title: g(3) || void 0, loading: "lazy" }, key()) : /* @__PURE__ */ jsx44("span", { className: "fd-md-imgalt", children: g(1) || "image" }, key()));
4036
+ out.push(ctx.allowImages && src2 ? /* @__PURE__ */ jsx48("img", { className: "fd-md-img", src: src2, alt: g(1) || "", title: g(3) || void 0, loading: "lazy" }, key()) : /* @__PURE__ */ jsx48("span", { className: "fd-md-imgalt", children: g(1) || "image" }, key()));
3227
4037
  } else if (kind === "link") {
3228
4038
  const href = safeHref(g(2));
3229
- out.push(href ? /* @__PURE__ */ jsx44("a", { href, title: g(3) || void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: inlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ jsx44("span", { children: g(1) }, key()));
4039
+ out.push(href ? /* @__PURE__ */ jsx48("a", { href, title: g(3) || void 0, target: /^https?:/i.test(href) ? "_blank" : void 0, rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: inlineNodes(g(1), ctx, key()) }, key()) : /* @__PURE__ */ jsx48("span", { children: g(1) }, key()));
3230
4040
  } else if (kind === "cite") {
3231
- out.push(ctx.renderCitation ? /* @__PURE__ */ jsx44(React22.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ jsx44("sup", { className: "fd-md-cite", children: g(1) }, key()));
3232
- } else if (kind === "strongem") out.push(/* @__PURE__ */ jsx44("strong", { children: /* @__PURE__ */ jsx44("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
3233
- else if (kind === "strong") out.push(/* @__PURE__ */ jsx44("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
3234
- else if (kind === "em") out.push(/* @__PURE__ */ jsx44("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
3235
- else if (kind === "del") out.push(/* @__PURE__ */ jsx44("del", { children: inlineNodes(g(1), ctx, key()) }, key()));
4041
+ out.push(ctx.renderCitation ? /* @__PURE__ */ jsx48(React25.Fragment, { children: ctx.renderCitation(g(1)) }, key()) : /* @__PURE__ */ jsx48("sup", { className: "fd-md-cite", children: g(1) }, key()));
4042
+ } else if (kind === "strongem") out.push(/* @__PURE__ */ jsx48("strong", { children: /* @__PURE__ */ jsx48("em", { children: inlineNodes(g(1), ctx, key()) }) }, key()));
4043
+ else if (kind === "strong") out.push(/* @__PURE__ */ jsx48("strong", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
4044
+ else if (kind === "em") out.push(/* @__PURE__ */ jsx48("em", { children: inlineNodes(g(1) || g(2), ctx, key()) }, key()));
4045
+ else if (kind === "del") out.push(/* @__PURE__ */ jsx48("del", { children: inlineNodes(g(1), ctx, key()) }, key()));
3236
4046
  else if (kind === "autolink" || kind === "bare") {
3237
4047
  const href = safeHref(g(1));
3238
- out.push(href ? /* @__PURE__ */ jsx44("a", { href, target: "_blank", rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: g(1).replace(/^mailto:/, "") }, key()) : g(1));
4048
+ out.push(href ? /* @__PURE__ */ jsx48("a", { href, target: "_blank", rel: "noopener noreferrer", onClick: ctx.onLinkClick, children: g(1).replace(/^mailto:/, "") }, key()) : g(1));
3239
4049
  }
3240
4050
  rest = rest.slice(m.index + m[0].length);
3241
4051
  }
@@ -3353,33 +4163,33 @@ function renderBlocks(blocks, ctx, path) {
3353
4163
  const k = path + "-" + i;
3354
4164
  switch (b.t) {
3355
4165
  case "code": {
3356
- if ((b.lang || "").toLowerCase() === "diff") return /* @__PURE__ */ jsx44(DiffBlock, { diff: b.code, filename: b.file || void 0 }, k);
3357
- return /* @__PURE__ */ jsx44(CodeBlock, { code: b.code, language: b.lang, filename: b.file || void 0, ...ctx.codeProps || {} }, k);
4166
+ if ((b.lang || "").toLowerCase() === "diff") return /* @__PURE__ */ jsx48(DiffBlock, { diff: b.code, filename: b.file || void 0 }, k);
4167
+ return /* @__PURE__ */ jsx48(CodeBlock, { code: b.code, language: b.lang, filename: b.file || void 0, ...ctx.codeProps || {} }, k);
3358
4168
  }
3359
4169
  case "h": {
3360
4170
  const lvl = Math.min(6, Math.max(1, b.level + (ctx.headingOffset || 0)));
3361
4171
  const Tag2 = "h" + lvl;
3362
- return /* @__PURE__ */ jsx44(Tag2, { className: "fd-md-h fd-md-h" + lvl, children: inlineNodes(b.text, ctx, k) }, k);
4172
+ return /* @__PURE__ */ jsx48(Tag2, { className: "fd-md-h fd-md-h" + lvl, children: inlineNodes(b.text, ctx, k) }, k);
3363
4173
  }
3364
4174
  case "hr":
3365
- return /* @__PURE__ */ jsx44("hr", { className: "fd-md-hr" }, k);
4175
+ return /* @__PURE__ */ jsx48("hr", { className: "fd-md-hr" }, k);
3366
4176
  case "quote":
3367
- return /* @__PURE__ */ jsx44("blockquote", { className: "fd-md-quote", children: renderBlocks(b.children, ctx, k) }, k);
4177
+ return /* @__PURE__ */ jsx48("blockquote", { className: "fd-md-quote", children: renderBlocks(b.children, ctx, k) }, k);
3368
4178
  case "list": {
3369
4179
  const Tag2 = b.ordered ? "ol" : "ul";
3370
4180
  const isTask = b.items.some((it) => it.checked != null);
3371
- return /* @__PURE__ */ jsx44(Tag2, { className: "fd-md-list" + (isTask ? " is-task" : ""), start: b.ordered && b.start !== 1 ? b.start : void 0, children: b.items.map((it, j) => /* @__PURE__ */ jsxs38("li", { className: it.checked != null ? it.checked ? "is-done" : "is-todo" : void 0, children: [
3372
- it.checked != null ? /* @__PURE__ */ jsx44("span", { className: "fd-md-task", "aria-hidden": "true", children: /* @__PURE__ */ jsx44("i", { className: "ph ph-" + (it.checked ? "check-square" : "square") }) }) : null,
3373
- /* @__PURE__ */ jsx44("span", { className: "fd-md-li", children: renderBlocks(it.children, ctx, k + "-" + j) })
4181
+ return /* @__PURE__ */ jsx48(Tag2, { className: "fd-md-list" + (isTask ? " is-task" : ""), start: b.ordered && b.start !== 1 ? b.start : void 0, children: b.items.map((it, j) => /* @__PURE__ */ jsxs42("li", { className: it.checked != null ? it.checked ? "is-done" : "is-todo" : void 0, children: [
4182
+ it.checked != null ? /* @__PURE__ */ jsx48("span", { className: "fd-md-task", "aria-hidden": "true", children: /* @__PURE__ */ jsx48("i", { className: "ph ph-" + (it.checked ? "check-square" : "square") }) }) : null,
4183
+ /* @__PURE__ */ jsx48("span", { className: "fd-md-li", children: renderBlocks(it.children, ctx, k + "-" + j) })
3374
4184
  ] }, k + "-" + j)) }, k);
3375
4185
  }
3376
4186
  case "table":
3377
- return /* @__PURE__ */ jsx44("div", { className: "fd-md-tablewrap", children: /* @__PURE__ */ jsxs38("table", { className: "fd-md-table", children: [
3378
- /* @__PURE__ */ jsx44("thead", { children: /* @__PURE__ */ jsx44("tr", { children: b.head.map((c, j) => /* @__PURE__ */ jsx44("th", { style: { textAlign: b.align[j] || "left" }, children: inlineNodes(c, ctx, k + "h" + j) }, j)) }) }),
3379
- /* @__PURE__ */ jsx44("tbody", { children: b.rows.map((r, ri) => /* @__PURE__ */ jsx44("tr", { children: b.head.map((_, ci) => /* @__PURE__ */ jsx44("td", { style: { textAlign: b.align[ci] || "left" }, children: inlineNodes(r[ci] || "", ctx, k + ri + "c" + ci) }, ci)) }, ri)) })
4187
+ return /* @__PURE__ */ jsx48("div", { className: "fd-md-tablewrap", children: /* @__PURE__ */ jsxs42("table", { className: "fd-md-table", children: [
4188
+ /* @__PURE__ */ jsx48("thead", { children: /* @__PURE__ */ jsx48("tr", { children: b.head.map((c, j) => /* @__PURE__ */ jsx48("th", { style: { textAlign: b.align[j] || "left" }, children: inlineNodes(c, ctx, k + "h" + j) }, j)) }) }),
4189
+ /* @__PURE__ */ jsx48("tbody", { children: b.rows.map((r, ri) => /* @__PURE__ */ jsx48("tr", { children: b.head.map((_, ci) => /* @__PURE__ */ jsx48("td", { style: { textAlign: b.align[ci] || "left" }, children: inlineNodes(r[ci] || "", ctx, k + ri + "c" + ci) }, ci)) }, ri)) })
3380
4190
  ] }) }, k);
3381
4191
  default:
3382
- return /* @__PURE__ */ jsx44("p", { className: "fd-md-p", children: inlineNodes(b.text, ctx, k) }, k);
4192
+ return /* @__PURE__ */ jsx48("p", { className: "fd-md-p", children: inlineNodes(b.text, ctx, k) }, k);
3383
4193
  }
3384
4194
  });
3385
4195
  }
@@ -3393,25 +4203,25 @@ function Markdown({
3393
4203
  onLinkClick
3394
4204
  }) {
3395
4205
  const ctx = { allowImages, headingOffset, renderCitation, onLinkClick, codeProps };
3396
- const blocks = React22.useMemo(() => parseBlocks(source), [source]);
3397
- return /* @__PURE__ */ jsx44("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
4206
+ const blocks = React25.useMemo(() => parseBlocks(source), [source]);
4207
+ return /* @__PURE__ */ jsx48("div", { className: ["fd-md", className].filter(Boolean).join(" "), children: renderBlocks(blocks, ctx, "b") });
3398
4208
  }
3399
4209
  function MarkdownInline({ source = "", className = "", onLinkClick }) {
3400
- return /* @__PURE__ */ jsx44("span", { className: ["fd-md-inline", className].filter(Boolean).join(" "), children: inlineNodes(source, { allowImages: false, onLinkClick }, "i") });
4210
+ return /* @__PURE__ */ jsx48("span", { className: ["fd-md-inline", className].filter(Boolean).join(" "), children: inlineNodes(source, { allowImages: false, onLinkClick }, "i") });
3401
4211
  }
3402
4212
  function markdownToText(src) {
3403
4213
  return String(src == null ? "" : src).replace(/```[\w+#-]*\n?([\s\S]*?)```/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1").replace(/\[([^\]]+)\]\([^)]*\)/g, "$1").replace(/^\s{0,3}#{1,6}\s+/gm, "").replace(/\*\*\*([^*]+)\*\*\*|\*\*([^*]+)\*\*|__([^_]+)__/g, "$1$2$3").replace(/(^|\W)[*_]([^*_\n]+)[*_](\W|$)/g, "$1$2$3").replace(/~~([^~]+)~~/g, "$1").replace(/^\s*>\s?/gm, "").trim();
3404
4214
  }
3405
4215
 
3406
4216
  // src/components/data/Meter.tsx
3407
- import { jsx as jsx45, jsxs as jsxs39 } from "react/jsx-runtime";
4217
+ import { jsx as jsx49, jsxs as jsxs43 } from "react/jsx-runtime";
3408
4218
  function Meter({ segments = [], unallocated = 0, height = 8, label, legend = false, className = "" }) {
3409
4219
  const total = segments.reduce((s, x) => s + x.value, 0) + unallocated;
3410
4220
  const pct = (v) => total ? v / total * 100 : 0;
3411
- return /* @__PURE__ */ jsxs39("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 8 }, children: [
3412
- label ? /* @__PURE__ */ jsx45("span", { className: "fd-label-lg fd-secondary", children: label }) : null,
3413
- /* @__PURE__ */ jsxs39("div", { className: "fd-meterbar", style: { height }, children: [
3414
- segments.map((s, i) => /* @__PURE__ */ jsx45(
4221
+ return /* @__PURE__ */ jsxs43("div", { className: ["fd-stack", className].filter(Boolean).join(" "), style: { gap: 8 }, children: [
4222
+ label ? /* @__PURE__ */ jsx49("span", { className: "fd-label-lg fd-secondary", children: label }) : null,
4223
+ /* @__PURE__ */ jsxs43("div", { className: "fd-meterbar", style: { height }, children: [
4224
+ segments.map((s, i) => /* @__PURE__ */ jsx49(
3415
4225
  "span",
3416
4226
  {
3417
4227
  className: "fd-meterbar-seg",
@@ -3420,15 +4230,15 @@ function Meter({ segments = [], unallocated = 0, height = 8, label, legend = fal
3420
4230
  },
3421
4231
  i
3422
4232
  )),
3423
- unallocated > 0 ? /* @__PURE__ */ jsx45("span", { className: "fd-meterbar-seg fd-meterbar-unallocated", title: "Unallocated", style: { width: pct(unallocated) + "%" } }) : null
4233
+ unallocated > 0 ? /* @__PURE__ */ jsx49("span", { className: "fd-meterbar-seg fd-meterbar-unallocated", title: "Unallocated", style: { width: pct(unallocated) + "%" } }) : null
3424
4234
  ] }),
3425
- legend ? /* @__PURE__ */ jsxs39("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap" }, children: [
3426
- segments.map((s, i) => /* @__PURE__ */ jsxs39("span", { className: "fd-row fd-body-sm fd-secondary", style: { gap: 7 }, children: [
3427
- /* @__PURE__ */ jsx45("span", { style: { width: 9, height: 9, borderRadius: 2, background: s.color || "var(--chart-" + (i % 8 + 1) + ")" } }),
4235
+ legend ? /* @__PURE__ */ jsxs43("div", { className: "fd-row", style: { gap: 16, flexWrap: "wrap" }, children: [
4236
+ segments.map((s, i) => /* @__PURE__ */ jsxs43("span", { className: "fd-row fd-body-sm fd-secondary", style: { gap: 7 }, children: [
4237
+ /* @__PURE__ */ jsx49("span", { style: { width: 9, height: 9, borderRadius: 2, background: s.color || "var(--chart-" + (i % 8 + 1) + ")" } }),
3428
4238
  s.label
3429
4239
  ] }, i)),
3430
- unallocated > 0 ? /* @__PURE__ */ jsxs39("span", { className: "fd-row fd-body-sm fd-secondary", style: { gap: 7 }, children: [
3431
- /* @__PURE__ */ jsx45("span", { className: "fd-meterbar-unallocated", style: { width: 9, height: 9, borderRadius: 2 } }),
4240
+ unallocated > 0 ? /* @__PURE__ */ jsxs43("span", { className: "fd-row fd-body-sm fd-secondary", style: { gap: 7 }, children: [
4241
+ /* @__PURE__ */ jsx49("span", { className: "fd-meterbar-unallocated", style: { width: 9, height: 9, borderRadius: 2 } }),
3432
4242
  "Unallocated"
3433
4243
  ] }) : null
3434
4244
  ] }) : null
@@ -3436,7 +4246,7 @@ function Meter({ segments = [], unallocated = 0, height = 8, label, legend = fal
3436
4246
  }
3437
4247
 
3438
4248
  // src/components/data/Pagination.tsx
3439
- import { Fragment as Fragment8, jsx as jsx46, jsxs as jsxs40 } from "react/jsx-runtime";
4249
+ import { Fragment as Fragment8, jsx as jsx50, jsxs as jsxs44 } from "react/jsx-runtime";
3440
4250
  var unitPluralRules = new Intl.PluralRules("en-US");
3441
4251
  function pluralizeUnit(n, singular, irregularPlural) {
3442
4252
  return unitPluralRules.select(n) === "one" ? singular : irregularPlural ?? `${singular}s`;
@@ -3467,12 +4277,12 @@ function Pagination({
3467
4277
  if (i === 1 || i === totalPages || Math.abs(i - page) <= span) nums.push(i);
3468
4278
  else if (nums[nums.length - 1] !== "\u2026") nums.push("\u2026");
3469
4279
  }
3470
- return /* @__PURE__ */ jsxs40("div", { className: ["fd-pag", className].filter(Boolean).join(" "), ...rest, children: [
3471
- /* @__PURE__ */ jsx46("span", { className: "fd-pag-count", children: loading ? /* @__PURE__ */ jsx46("span", { className: "fd-skel fd-skel-text", style: { display: "inline-block", height: 12, width: 108 } }) : total === 0 ? /* @__PURE__ */ jsxs40(Fragment8, { children: [
4280
+ return /* @__PURE__ */ jsxs44("div", { className: ["fd-pag", className].filter(Boolean).join(" "), ...rest, children: [
4281
+ /* @__PURE__ */ jsx50("span", { className: "fd-pag-count", children: loading ? /* @__PURE__ */ jsx50("span", { className: "fd-skel fd-skel-text", style: { display: "inline-block", height: 12, width: 108 } }) : total === 0 ? /* @__PURE__ */ jsxs44(Fragment8, { children: [
3472
4282
  "No ",
3473
4283
  unitLabel
3474
- ] }) : /* @__PURE__ */ jsxs40(Fragment8, { children: [
3475
- /* @__PURE__ */ jsxs40("strong", { children: [
4284
+ ] }) : /* @__PURE__ */ jsxs44(Fragment8, { children: [
4285
+ /* @__PURE__ */ jsxs44("strong", { children: [
3476
4286
  from.toLocaleString(),
3477
4287
  "\u2013",
3478
4288
  to.toLocaleString()
@@ -3482,14 +4292,14 @@ function Pagination({
3482
4292
  " ",
3483
4293
  unitLabel
3484
4294
  ] }) }),
3485
- onPageSizeChange ? /* @__PURE__ */ jsxs40("label", { className: "fd-pag-size", children: [
3486
- /* @__PURE__ */ jsx46("span", { children: "Rows" }),
3487
- /* @__PURE__ */ jsx46("select", { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), "aria-label": "Rows per page", children: pageSizes.map((n) => /* @__PURE__ */ jsx46("option", { value: n, children: n }, n)) })
4295
+ onPageSizeChange ? /* @__PURE__ */ jsxs44("label", { className: "fd-pag-size", children: [
4296
+ /* @__PURE__ */ jsx50("span", { children: "Rows" }),
4297
+ /* @__PURE__ */ jsx50("select", { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), "aria-label": "Rows per page", children: pageSizes.map((n) => /* @__PURE__ */ jsx50("option", { value: n, children: n }, n)) })
3488
4298
  ] }) : null,
3489
- /* @__PURE__ */ jsxs40("span", { className: "fd-pag-nav", children: [
3490
- /* @__PURE__ */ jsx46("button", { type: "button", onClick: () => go(1), disabled: page <= 1, "aria-label": "First page", children: /* @__PURE__ */ jsx46("i", { className: "ph ph-caret-double-left" }) }),
3491
- /* @__PURE__ */ jsx46("button", { type: "button", onClick: () => go(page - 1), disabled: page <= 1, "aria-label": "Previous page", children: /* @__PURE__ */ jsx46("i", { className: "ph ph-caret-left" }) }),
3492
- nums.map((n, i) => n === "\u2026" ? /* @__PURE__ */ jsx46("span", { className: "fd-pag-gap", "aria-hidden": "true", children: "\u2026" }, "e" + i) : /* @__PURE__ */ jsx46(
4299
+ /* @__PURE__ */ jsxs44("span", { className: "fd-pag-nav", children: [
4300
+ /* @__PURE__ */ jsx50("button", { type: "button", onClick: () => go(1), disabled: page <= 1, "aria-label": "First page", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-double-left" }) }),
4301
+ /* @__PURE__ */ jsx50("button", { type: "button", onClick: () => go(page - 1), disabled: page <= 1, "aria-label": "Previous page", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-left" }) }),
4302
+ nums.map((n, i) => n === "\u2026" ? /* @__PURE__ */ jsx50("span", { className: "fd-pag-gap", "aria-hidden": "true", children: "\u2026" }, "e" + i) : /* @__PURE__ */ jsx50(
3493
4303
  "button",
3494
4304
  {
3495
4305
  type: "button",
@@ -3500,15 +4310,15 @@ function Pagination({
3500
4310
  },
3501
4311
  n
3502
4312
  )),
3503
- /* @__PURE__ */ jsx46("button", { type: "button", onClick: () => go(page + 1), disabled: page >= totalPages, "aria-label": "Next page", children: /* @__PURE__ */ jsx46("i", { className: "ph ph-caret-right" }) }),
3504
- /* @__PURE__ */ jsx46("button", { type: "button", onClick: () => go(totalPages), disabled: page >= totalPages, "aria-label": "Last page", children: /* @__PURE__ */ jsx46("i", { className: "ph ph-caret-double-right" }) })
4313
+ /* @__PURE__ */ jsx50("button", { type: "button", onClick: () => go(page + 1), disabled: page >= totalPages, "aria-label": "Next page", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-right" }) }),
4314
+ /* @__PURE__ */ jsx50("button", { type: "button", onClick: () => go(totalPages), disabled: page >= totalPages, "aria-label": "Last page", children: /* @__PURE__ */ jsx50("i", { className: "ph ph-caret-double-right" }) })
3505
4315
  ] })
3506
4316
  ] });
3507
4317
  }
3508
4318
 
3509
4319
  // src/components/data/RelativeTime.tsx
3510
- import * as React23 from "react";
3511
- import { jsxs as jsxs41 } from "react/jsx-runtime";
4320
+ import * as React26 from "react";
4321
+ import { jsxs as jsxs45 } from "react/jsx-runtime";
3512
4322
  var MIN = 6e4;
3513
4323
  var HOUR = 36e5;
3514
4324
  var DAY = 864e5;
@@ -3559,9 +4369,9 @@ function formatDuration(ms) {
3559
4369
  return h + "h" + (m % 60 ? " " + m % 60 + "m" : "");
3560
4370
  }
3561
4371
  function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true, ...rest }) {
3562
- const [, force] = React23.useState(0);
4372
+ const [, force] = React26.useState(0);
3563
4373
  const t = value instanceof Date ? value.getTime() : Date.parse(value);
3564
- React23.useEffect(() => {
4374
+ React26.useEffect(() => {
3565
4375
  if (!refresh2 || !t || isNaN(t)) return;
3566
4376
  const abs = Math.abs(t - Date.now());
3567
4377
  if (abs > DAY) return;
@@ -3570,15 +4380,15 @@ function RelativeTime({ value, prefix, className = "", refresh: refresh2 = true,
3570
4380
  return () => clearInterval(id);
3571
4381
  }, [t, refresh2]);
3572
4382
  if (!t || isNaN(t)) return null;
3573
- return /* @__PURE__ */ jsxs41("time", { className, dateTime: new Date(t).toISOString(), title: formatAbsolute(new Date(t)), ...rest, children: [
4383
+ return /* @__PURE__ */ jsxs45("time", { className, dateTime: new Date(t).toISOString(), title: formatAbsolute(new Date(t)), ...rest, children: [
3574
4384
  prefix ? prefix + " " : "",
3575
4385
  formatRelative(new Date(t))
3576
4386
  ] });
3577
4387
  }
3578
4388
 
3579
4389
  // src/components/data/ScoreMeter.tsx
3580
- import * as React24 from "react";
3581
- import { jsx as jsx47, jsxs as jsxs42 } from "react/jsx-runtime";
4390
+ import * as React27 from "react";
4391
+ import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
3582
4392
  function ScoreMeter({
3583
4393
  score,
3584
4394
  segments,
@@ -3592,15 +4402,15 @@ function ScoreMeter({
3592
4402
  breakdownWidth = 280,
3593
4403
  className = ""
3594
4404
  }) {
3595
- const [open, setOpen] = React24.useState(false);
3596
- const ref = React24.useRef(null);
4405
+ const [open, setOpen] = React27.useState(false);
4406
+ const ref = React27.useRef(null);
3597
4407
  const value = Math.max(0, Math.min(100, Math.round(Number(score) || 0)));
3598
- const body = /* @__PURE__ */ jsxs42(React24.Fragment, { children: [
3599
- /* @__PURE__ */ jsx47("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ jsx47(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
3600
- showScore ? /* @__PURE__ */ jsx47("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
4408
+ const body = /* @__PURE__ */ jsxs46(React27.Fragment, { children: [
4409
+ /* @__PURE__ */ jsx51("span", { className: "fd-scoremeter-rail", style: { width }, "aria-hidden": "true", children: /* @__PURE__ */ jsx51(SegmentedMeter, { total: 100, segments, height, showTotal: false, showPercent: false, legend: false }) }),
4410
+ showScore ? /* @__PURE__ */ jsx51("span", { className: "fd-scoremeter-value fd-tabular", "aria-hidden": "true", children: value }) : null
3601
4411
  ] });
3602
4412
  if (!breakdown) {
3603
- return /* @__PURE__ */ jsx47(
4413
+ return /* @__PURE__ */ jsx51(
3604
4414
  "span",
3605
4415
  {
3606
4416
  className: ["fd-scoremeter", className].filter(Boolean).join(" "),
@@ -3614,8 +4424,8 @@ function ScoreMeter({
3614
4424
  }
3615
4425
  );
3616
4426
  }
3617
- return /* @__PURE__ */ jsxs42(React24.Fragment, { children: [
3618
- /* @__PURE__ */ jsx47(
4427
+ return /* @__PURE__ */ jsxs46(React27.Fragment, { children: [
4428
+ /* @__PURE__ */ jsx51(
3619
4429
  "button",
3620
4430
  {
3621
4431
  type: "button",
@@ -3628,7 +4438,7 @@ function ScoreMeter({
3628
4438
  children: body
3629
4439
  }
3630
4440
  ),
3631
- /* @__PURE__ */ jsx47(
4441
+ /* @__PURE__ */ jsx51(
3632
4442
  Popover,
3633
4443
  {
3634
4444
  open,
@@ -3645,13 +4455,13 @@ function ScoreMeter({
3645
4455
  }
3646
4456
 
3647
4457
  // src/components/data/SortMenu.tsx
3648
- import * as React25 from "react";
3649
- import { jsx as jsx48, jsxs as jsxs43 } from "react/jsx-runtime";
4458
+ import * as React28 from "react";
4459
+ import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
3650
4460
  function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", className = "", ...rest }) {
3651
- const [open, setOpen] = React25.useState(false);
4461
+ const [open, setOpen] = React28.useState(false);
3652
4462
  const zIndex = useOverlayLayer(open);
3653
- const ref = React25.useRef(null);
3654
- React25.useEffect(() => {
4463
+ const ref = React28.useRef(null);
4464
+ React28.useEffect(() => {
3655
4465
  if (!open) return;
3656
4466
  const away = (e) => {
3657
4467
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
@@ -3671,7 +4481,7 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
3671
4481
  const arrow = (f, d) => {
3672
4482
  const on = cur && cur.key === f.key && dir === d;
3673
4483
  const label = d === "asc" ? f.numeric ? "lowest first" : "A to Z" : f.numeric ? "highest first" : "Z to A";
3674
- return /* @__PURE__ */ jsx48(
4484
+ return /* @__PURE__ */ jsx52(
3675
4485
  "button",
3676
4486
  {
3677
4487
  type: "button",
@@ -3689,21 +4499,21 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
3689
4499
  background: on ? "var(--brand)" : "var(--surface)",
3690
4500
  color: on ? "#fff" : "var(--text-muted)"
3691
4501
  },
3692
- children: /* @__PURE__ */ jsx48("i", { className: "ph ph-arrow-" + (d === "asc" ? "up" : "down"), style: { fontSize: 13 } })
4502
+ children: /* @__PURE__ */ jsx52("i", { className: "ph ph-arrow-" + (d === "asc" ? "up" : "down"), style: { fontSize: 13 } })
3693
4503
  }
3694
4504
  );
3695
4505
  };
3696
- return /* @__PURE__ */ jsxs43("span", { className, style: { position: "relative", display: "inline-flex" }, ref, ...rest, children: [
3697
- /* @__PURE__ */ jsxs43(Button, { size, variant: "secondary", icon: dir === "asc" ? "sort-ascending" : "sort-descending", onClick: () => setOpen(!open), children: [
4506
+ return /* @__PURE__ */ jsxs47("span", { className, style: { position: "relative", display: "inline-flex" }, ref, ...rest, children: [
4507
+ /* @__PURE__ */ jsxs47(Button, { size, variant: "secondary", icon: dir === "asc" ? "sort-ascending" : "sort-descending", onClick: () => setOpen(!open), children: [
3698
4508
  cur ? cur.label : "Unsorted",
3699
- /* @__PURE__ */ jsx48("i", { className: "ph ph-" + (dir === "asc" ? "arrow-up" : "arrow-down"), style: { fontSize: 12, marginLeft: 6, opacity: 0.75 } })
4509
+ /* @__PURE__ */ jsx52("i", { className: "ph ph-" + (dir === "asc" ? "arrow-up" : "arrow-down"), style: { fontSize: 12, marginLeft: 6, opacity: 0.75 } })
3700
4510
  ] }),
3701
- open ? /* @__PURE__ */ jsx48(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx48("span", { className: "fd-view-enter", style: { position: "absolute", top: "calc(100% + 6px)", [align]: 0, zIndex, width: 280, maxWidth: "calc(100vw - 32px)", display: "block", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, boxShadow: "0 16px 44px rgba(11,13,17,.18)", padding: 8 }, children: /* @__PURE__ */ jsxs43("span", { className: "fd-stack", style: { gap: 2 }, children: [
3702
- /* @__PURE__ */ jsx48("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Sort by" }),
4511
+ open ? /* @__PURE__ */ jsx52(LayerProvider, { zIndex, children: /* @__PURE__ */ jsx52("span", { className: "fd-view-enter", style: { position: "absolute", top: "calc(100% + 6px)", [align]: 0, zIndex, width: 280, maxWidth: "calc(100vw - 32px)", display: "block", background: "var(--surface)", border: "1px solid var(--border)", borderRadius: 10, boxShadow: "0 16px 44px rgba(11,13,17,.18)", padding: 8 }, children: /* @__PURE__ */ jsxs47("span", { className: "fd-stack", style: { gap: 2 }, children: [
4512
+ /* @__PURE__ */ jsx52("span", { className: "fd-overline fd-muted", style: { padding: "4px 8px 6px" }, children: "Sort by" }),
3703
4513
  fields.map((f) => {
3704
4514
  const active = cur && cur.key === f.key;
3705
- return /* @__PURE__ */ jsxs43("span", { className: "fd-row", style: { gap: 8, padding: "4px 8px", borderRadius: 7, background: active ? "var(--surface-brand)" : "transparent" }, children: [
3706
- /* @__PURE__ */ jsx48("span", { className: "fd-body-sm", style: { flex: 1, fontWeight: active ? 700 : 500, color: active ? "var(--text-on-surface-brand)" : "var(--text)" }, children: f.label }),
4515
+ return /* @__PURE__ */ jsxs47("span", { className: "fd-row", style: { gap: 8, padding: "4px 8px", borderRadius: 7, background: active ? "var(--surface-brand)" : "transparent" }, children: [
4516
+ /* @__PURE__ */ jsx52("span", { className: "fd-body-sm", style: { flex: 1, fontWeight: active ? 700 : 500, color: active ? "var(--text-on-surface-brand)" : "var(--text)" }, children: f.label }),
3707
4517
  arrow(f, "asc"),
3708
4518
  arrow(f, "desc")
3709
4519
  ] }, f.key);
@@ -3713,8 +4523,8 @@ function SortMenu({ fields = [], sort, onSort, align = "right", size = "md", cla
3713
4523
  }
3714
4524
 
3715
4525
  // src/components/data/StepList.tsx
3716
- import * as React26 from "react";
3717
- import { jsx as jsx49, jsxs as jsxs44 } from "react/jsx-runtime";
4526
+ import * as React29 from "react";
4527
+ import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
3718
4528
  var KIND_ICON = { tool: "wrench", search: "magnifying-glass", read: "file-text", write: "pencil-simple", reasoning: "brain", run: "terminal", fetch: "cloud-arrow-down" };
3719
4529
  function StepList({
3720
4530
  steps = [],
@@ -3726,9 +4536,9 @@ function StepList({
3726
4536
  dense = false,
3727
4537
  className = ""
3728
4538
  }) {
3729
- const [openState, setOpenState] = React26.useState(defaultOpen);
4539
+ const [openState, setOpenState] = React29.useState(defaultOpen);
3730
4540
  const open = openProp == null ? openState : openProp;
3731
- const [expanded, setExpanded] = React26.useState({});
4541
+ const [expanded, setExpanded] = React29.useState({});
3732
4542
  if (!steps.length) return null;
3733
4543
  const running = steps.some((s) => s.status === "running");
3734
4544
  const failed = steps.filter((s) => s.status === "error").length;
@@ -3740,30 +4550,30 @@ function StepList({
3740
4550
  if (openProp == null) setOpenState(next);
3741
4551
  onToggle && onToggle(next);
3742
4552
  };
3743
- return /* @__PURE__ */ jsxs44("div", { className: ["fd-steps", dense ? "is-dense" : "", open ? "is-open" : "", className].filter(Boolean).join(" "), children: [
3744
- /* @__PURE__ */ jsxs44("button", { type: "button", className: "fd-steps-head", onClick: toggle, "aria-expanded": open, children: [
3745
- running ? /* @__PURE__ */ jsx49("span", { className: "fd-steps-spin", "aria-hidden": "true" }) : /* @__PURE__ */ jsx49("i", { className: "ph ph-" + (failed ? "warning-circle" : "check-circle"), "aria-hidden": "true" }),
3746
- /* @__PURE__ */ jsx49("span", { className: "fd-steps-title", title: truncationTitle(summary), children: summary }),
3747
- /* @__PURE__ */ jsxs44("span", { className: "fd-steps-count fd-tabular", children: [
4553
+ return /* @__PURE__ */ jsxs48("div", { className: ["fd-steps", dense ? "is-dense" : "", open ? "is-open" : "", className].filter(Boolean).join(" "), children: [
4554
+ /* @__PURE__ */ jsxs48("button", { type: "button", className: "fd-steps-head", onClick: toggle, "aria-expanded": open, children: [
4555
+ running ? /* @__PURE__ */ jsx53("span", { className: "fd-steps-spin", "aria-hidden": "true" }) : /* @__PURE__ */ jsx53("i", { className: "ph ph-" + (failed ? "warning-circle" : "check-circle"), "aria-hidden": "true" }),
4556
+ /* @__PURE__ */ jsx53("span", { className: "fd-steps-title", title: truncationTitle(summary), children: summary }),
4557
+ /* @__PURE__ */ jsxs48("span", { className: "fd-steps-count fd-tabular", children: [
3748
4558
  steps.length,
3749
4559
  " step",
3750
4560
  steps.length === 1 ? "" : "s",
3751
- failed ? /* @__PURE__ */ jsxs44("span", { className: "fd-steps-failed", children: [
4561
+ failed ? /* @__PURE__ */ jsxs48("span", { className: "fd-steps-failed", children: [
3752
4562
  " \xB7 ",
3753
4563
  failed,
3754
4564
  " failed"
3755
4565
  ] }) : null
3756
4566
  ] }),
3757
- /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-" + (open ? "up" : "down") + " fd-steps-caret", "aria-hidden": "true" })
4567
+ /* @__PURE__ */ jsx53("i", { className: "ph ph-caret-" + (open ? "up" : "down") + " fd-steps-caret", "aria-hidden": "true" })
3758
4568
  ] }),
3759
- open ? /* @__PURE__ */ jsx49("ol", { className: "fd-steps-list", children: steps.map((s, i) => {
4569
+ open ? /* @__PURE__ */ jsx53("ol", { className: "fd-steps-list", children: steps.map((s, i) => {
3760
4570
  const id = s.id || i;
3761
4571
  const isOpen = !!expanded[id];
3762
4572
  const icon = KIND_ICON[s.kind || ""] || "dot-outline";
3763
- return /* @__PURE__ */ jsxs44("li", { className: "fd-step is-" + (s.status || "ok"), children: [
3764
- /* @__PURE__ */ jsxs44("div", { className: "fd-step-row", children: [
3765
- /* @__PURE__ */ jsx49("span", { className: "fd-step-icon", "aria-hidden": "true", children: s.status === "running" ? /* @__PURE__ */ jsx49("span", { className: "fd-steps-spin" }) : /* @__PURE__ */ jsx49("i", { className: "ph ph-" + icon }) }),
3766
- s.detail ? /* @__PURE__ */ jsxs44(
4573
+ return /* @__PURE__ */ jsxs48("li", { className: "fd-step is-" + (s.status || "ok"), children: [
4574
+ /* @__PURE__ */ jsxs48("div", { className: "fd-step-row", children: [
4575
+ /* @__PURE__ */ jsx53("span", { className: "fd-step-icon", "aria-hidden": "true", children: s.status === "running" ? /* @__PURE__ */ jsx53("span", { className: "fd-steps-spin" }) : /* @__PURE__ */ jsx53("i", { className: "ph ph-" + icon }) }),
4576
+ s.detail ? /* @__PURE__ */ jsxs48(
3767
4577
  "button",
3768
4578
  {
3769
4579
  type: "button",
@@ -3771,23 +4581,23 @@ function StepList({
3771
4581
  "aria-expanded": isOpen,
3772
4582
  onClick: () => setExpanded((m) => Object.assign({}, m, { [id]: !isOpen })),
3773
4583
  children: [
3774
- /* @__PURE__ */ jsx49("span", { title: truncationTitle(s.label), children: s.label }),
3775
- /* @__PURE__ */ jsx49("i", { className: "ph ph-caret-" + (isOpen ? "up" : "down"), "aria-hidden": "true" })
4584
+ /* @__PURE__ */ jsx53("span", { title: truncationTitle(s.label), children: s.label }),
4585
+ /* @__PURE__ */ jsx53("i", { className: "ph ph-caret-" + (isOpen ? "up" : "down"), "aria-hidden": "true" })
3776
4586
  ]
3777
4587
  }
3778
- ) : /* @__PURE__ */ jsx49("span", { className: "fd-step-label is-static", title: truncationTitle(s.label), children: s.label }),
3779
- s.status === "error" ? /* @__PURE__ */ jsx49("span", { className: "fd-step-badge is-error", children: "failed" }) : null,
3780
- showDurations && s.durationMs ? /* @__PURE__ */ jsx49("span", { className: "fd-step-dur fd-tabular", children: formatDuration(s.durationMs) }) : null
4588
+ ) : /* @__PURE__ */ jsx53("span", { className: "fd-step-label is-static", title: truncationTitle(s.label), children: s.label }),
4589
+ s.status === "error" ? /* @__PURE__ */ jsx53("span", { className: "fd-step-badge is-error", children: "failed" }) : null,
4590
+ showDurations && s.durationMs ? /* @__PURE__ */ jsx53("span", { className: "fd-step-dur fd-tabular", children: formatDuration(s.durationMs) }) : null
3781
4591
  ] }),
3782
- s.detail && isOpen ? /* @__PURE__ */ jsx49("pre", { className: "fd-step-detail", children: s.detail }) : null
4592
+ s.detail && isOpen ? /* @__PURE__ */ jsx53("pre", { className: "fd-step-detail", children: s.detail }) : null
3783
4593
  ] }, id);
3784
4594
  }) }) : null
3785
4595
  ] });
3786
4596
  }
3787
4597
 
3788
4598
  // src/components/data/VirtualList.tsx
3789
- import * as React27 from "react";
3790
- import { jsx as jsx50, jsxs as jsxs45 } from "react/jsx-runtime";
4599
+ import * as React30 from "react";
4600
+ import { jsx as jsx54, jsxs as jsxs49 } from "react/jsx-runtime";
3791
4601
  var VIRTUAL_LIST_BUFFER_ROWS = 20;
3792
4602
  var VIRTUAL_LIST_ROW_GAP = 6;
3793
4603
  function computeVirtualWindow(opts) {
@@ -3838,35 +4648,35 @@ function VirtualList({
3838
4648
  className = "",
3839
4649
  style
3840
4650
  }) {
3841
- const [scrollTop, setScrollTop] = React27.useState(0);
3842
- const loaded = React27.useMemo(
4651
+ const [scrollTop, setScrollTop] = React30.useState(0);
4652
+ const loaded = React30.useMemo(
3843
4653
  () => ({ firstItemIndex, count: items.length }),
3844
4654
  [firstItemIndex, items.length]
3845
4655
  );
3846
4656
  const total = Math.max(totalCount == null ? 0 : totalCount, firstItemIndex + items.length);
3847
4657
  const bandKey = firstItemIndex + ":" + items.length;
3848
- const win = React27.useMemo(
4658
+ const win = React30.useMemo(
3849
4659
  () => computeVirtualWindow({ scrollTop, viewportHeight: height, itemHeight, itemCount: total, loaded }),
3850
4660
  [scrollTop, height, itemHeight, total, loaded]
3851
4661
  );
3852
- const need = React27.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
4662
+ const need = React30.useMemo(() => computeNeedMore(win, loaded), [win, loaded]);
3853
4663
  const wantStart = need.start && hasMore?.start !== false;
3854
4664
  const wantEnd = need.end && hasMore?.end !== false;
3855
4665
  const bucket2 = Math.floor(win.visibleStart / VIRTUAL_LIST_BUFFER_ROWS);
3856
4666
  const askKey = bandKey + "@" + bucket2;
3857
- const asked = React27.useRef({ start: null, end: null });
3858
- React27.useEffect(() => {
4667
+ const asked = React30.useRef({ start: null, end: null });
4668
+ React30.useEffect(() => {
3859
4669
  if (loading || !wantStart || asked.current.start === askKey) return;
3860
4670
  asked.current.start = askKey;
3861
4671
  onNeedMore("start", win);
3862
4672
  }, [wantStart, loading, askKey, onNeedMore, win]);
3863
- React27.useEffect(() => {
4673
+ React30.useEffect(() => {
3864
4674
  if (loading || !wantEnd || asked.current.end === askKey) return;
3865
4675
  asked.current.end = askKey;
3866
4676
  onNeedMore("end", win);
3867
4677
  }, [wantEnd, loading, askKey, onNeedMore, win]);
3868
- const lastKeysRef = React27.useRef(null);
3869
- const newKeys = React27.useMemo(() => {
4678
+ const lastKeysRef = React30.useRef(null);
4679
+ const newKeys = React30.useMemo(() => {
3870
4680
  const prev = lastKeysRef.current;
3871
4681
  if (!prev) return /* @__PURE__ */ new Set();
3872
4682
  const fresh = /* @__PURE__ */ new Set();
@@ -3876,12 +4686,12 @@ function VirtualList({
3876
4686
  }
3877
4687
  return fresh;
3878
4688
  }, [items]);
3879
- React27.useEffect(() => {
4689
+ React30.useEffect(() => {
3880
4690
  lastKeysRef.current = new Set(items.map(keyOf));
3881
4691
  }, [items]);
3882
4692
  const gapStyle = { "--fd-vlist-gap": rowGap + "px" };
3883
4693
  if (!items.length && !loading && !refreshing && emptyState) {
3884
- return /* @__PURE__ */ jsx50("div", { className: ["fd-vlist-wrap", className].filter(Boolean).join(" "), style: { height, position: "relative", ...style }, children: /* @__PURE__ */ jsx50("div", { className: "fd-vlist fd-scrollbar", style: { height: "100%", overflow: "auto" }, children: emptyState }) });
4694
+ return /* @__PURE__ */ jsx54("div", { className: ["fd-vlist-wrap", className].filter(Boolean).join(" "), style: { height, position: "relative", ...style }, children: /* @__PURE__ */ jsx54("div", { className: "fd-vlist fd-scrollbar", style: { height: "100%", overflow: "auto" }, children: emptyState }) });
3885
4695
  }
3886
4696
  const rows = [];
3887
4697
  for (let i = win.startIndex; i <= win.endIndex; i++) {
@@ -3889,40 +4699,40 @@ function VirtualList({
3889
4699
  if (item === void 0) continue;
3890
4700
  const key = keyOf(item);
3891
4701
  rows.push(
3892
- /* @__PURE__ */ jsx50(
4702
+ /* @__PURE__ */ jsx54(
3893
4703
  "div",
3894
4704
  {
3895
4705
  className: "fd-vlist-row",
3896
4706
  style: { height: itemHeight, boxSizing: "border-box", transform: "translateY(" + i * itemHeight + "px)" },
3897
- children: /* @__PURE__ */ jsx50("div", { className: newKeys.has(key) ? "fd-vlist-row-content fd-vlist-row-enter" : "fd-vlist-row-content", children: renderItem(item, i) })
4707
+ children: /* @__PURE__ */ jsx54("div", { className: newKeys.has(key) ? "fd-vlist-row-content fd-vlist-row-enter" : "fd-vlist-row-content", children: renderItem(item, i) })
3898
4708
  },
3899
4709
  key
3900
4710
  )
3901
4711
  );
3902
4712
  }
3903
- return /* @__PURE__ */ jsxs45("div", { className: ["fd-vlist-wrap", className].filter(Boolean).join(" "), style: { height, position: "relative", ...gapStyle, ...style }, children: [
3904
- /* @__PURE__ */ jsxs45(
4713
+ return /* @__PURE__ */ jsxs49("div", { className: ["fd-vlist-wrap", className].filter(Boolean).join(" "), style: { height, position: "relative", ...gapStyle, ...style }, children: [
4714
+ /* @__PURE__ */ jsxs49(
3905
4715
  "div",
3906
4716
  {
3907
4717
  className: "fd-vlist fd-scrollbar",
3908
4718
  style: { height: "100%", overflowY: "auto", overflowX: "hidden", position: "relative" },
3909
4719
  onScroll: (e) => setScrollTop(e.currentTarget.scrollTop),
3910
4720
  children: [
3911
- /* @__PURE__ */ jsx50("div", { style: { height: win.totalHeight, position: "relative" }, children: rows }),
3912
- loading ? /* @__PURE__ */ jsx50("div", { style: { position: "sticky", bottom: 0, left: 0, right: 0, display: "grid", placeItems: "center", padding: "8px 0", background: "var(--surface)" }, children: /* @__PURE__ */ jsx50("span", { className: "fd-spinner", "aria-hidden": "true" }) }) : null
4721
+ /* @__PURE__ */ jsx54("div", { style: { height: win.totalHeight, position: "relative" }, children: rows }),
4722
+ loading ? /* @__PURE__ */ jsx54("div", { style: { position: "sticky", bottom: 0, left: 0, right: 0, display: "grid", placeItems: "center", padding: "8px 0", background: "var(--surface)" }, children: /* @__PURE__ */ jsx54("span", { className: "fd-spinner", "aria-hidden": "true" }) }) : null
3913
4723
  ]
3914
4724
  }
3915
4725
  ),
3916
- refreshing ? /* @__PURE__ */ jsx50("div", { className: "fd-vlist-refresh-scrim", children: /* @__PURE__ */ jsxs45("div", { className: "fd-vlist-refresh-card", children: [
3917
- /* @__PURE__ */ jsx50("span", { className: "fd-spinner", "aria-hidden": "true" }),
3918
- /* @__PURE__ */ jsx50("span", { className: "fd-body-sm", children: refreshingLabel })
4726
+ refreshing ? /* @__PURE__ */ jsx54("div", { className: "fd-vlist-refresh-scrim", children: /* @__PURE__ */ jsxs49("div", { className: "fd-vlist-refresh-card", children: [
4727
+ /* @__PURE__ */ jsx54("span", { className: "fd-spinner", "aria-hidden": "true" }),
4728
+ /* @__PURE__ */ jsx54("span", { className: "fd-body-sm", children: refreshingLabel })
3919
4729
  ] }) }) : null
3920
4730
  ] });
3921
4731
  }
3922
4732
 
3923
4733
  // src/components/data/EntityRow.tsx
3924
- import * as React28 from "react";
3925
- import { jsx as jsx51, jsxs as jsxs46 } from "react/jsx-runtime";
4734
+ import * as React31 from "react";
4735
+ import { jsx as jsx55, jsxs as jsxs50 } from "react/jsx-runtime";
3926
4736
  var ENTITY_ROW_METRIC_WIDTH = 74;
3927
4737
  var METRIC_TONE_COLOR = {
3928
4738
  default: "var(--text-2)",
@@ -3930,16 +4740,16 @@ var METRIC_TONE_COLOR = {
3930
4740
  danger: "var(--danger-text)"
3931
4741
  };
3932
4742
  function EntityRowMetrics({ metrics, className = "", style }) {
3933
- return /* @__PURE__ */ jsx51("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) => {
4743
+ return /* @__PURE__ */ jsx55("span", { className: ["fd-erow-metrics", className].filter(Boolean).join(" "), style, children: metrics.map((m, i) => {
3934
4744
  const key = m.id || m.label || i;
3935
4745
  const className2 = ["fd-erow-metric", m.tone && m.tone !== "default" ? "is-" + m.tone : "", m.tooltip != null ? "is-described" : ""].filter(Boolean).join(" ");
3936
4746
  const tone = { color: METRIC_TONE_COLOR[m.tone || "default"] };
3937
- const content = /* @__PURE__ */ jsxs46(React28.Fragment, { children: [
3938
- m.icon ? /* @__PURE__ */ jsx51("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
3939
- /* @__PURE__ */ jsx51("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
3940
- /* @__PURE__ */ jsx51("span", { className: "fd-sr", children: " " + m.label })
4747
+ const content = /* @__PURE__ */ jsxs50(React31.Fragment, { children: [
4748
+ m.icon ? /* @__PURE__ */ jsx55("i", { className: "ph ph-" + m.icon, "aria-hidden": "true" }) : null,
4749
+ /* @__PURE__ */ jsx55("span", { className: "fd-erow-metric-value fd-tabular", children: m.value }),
4750
+ /* @__PURE__ */ jsx55("span", { className: "fd-sr", children: " " + m.label })
3941
4751
  ] });
3942
- return /* @__PURE__ */ jsx51("span", { className: "fd-erow-cell", style: { "--erow-metric-w": (m.width || ENTITY_ROW_METRIC_WIDTH) + "px" }, children: m.tooltip == null ? /* @__PURE__ */ jsx51("span", { className: className2, style: tone, title: m.label, children: content }) : /* @__PURE__ */ jsx51(Tooltip, { label: m.tooltip, children: /* @__PURE__ */ jsx51("button", { type: "button", className: className2, style: tone, children: content }) }) }, key);
4752
+ return /* @__PURE__ */ jsx55("span", { className: "fd-erow-cell", style: { "--erow-metric-w": (m.width || ENTITY_ROW_METRIC_WIDTH) + "px" }, children: m.tooltip == null ? /* @__PURE__ */ jsx55("span", { className: className2, style: tone, title: m.label, children: content }) : /* @__PURE__ */ jsx55(Tooltip, { label: m.tooltip, children: /* @__PURE__ */ jsx55("button", { type: "button", className: className2, style: tone, children: content }) }) }, key);
3943
4753
  }) });
3944
4754
  }
3945
4755
  function EntityRow({
@@ -3956,7 +4766,7 @@ function EntityRow({
3956
4766
  className = ""
3957
4767
  }) {
3958
4768
  const hasStrip = metrics && metrics.length > 0 || accessory != null;
3959
- return /* @__PURE__ */ jsxs46(
4769
+ return /* @__PURE__ */ jsxs50(
3960
4770
  "div",
3961
4771
  {
3962
4772
  onPointerDown,
@@ -3982,33 +4792,33 @@ function EntityRow({
3982
4792
  // font-size moved to the .fd-erow-grip stylesheet rule, same reason as the
3983
4793
  // row's own padding above: .fd-tlist-footer's indent reads it back as
3984
4794
  // --erow-grip-size.
3985
- /* @__PURE__ */ jsx51("i", { className: "ph ph-dots-six-vertical fd-erow-grip", "aria-hidden": "true", style: { flex: "none", color: "var(--text-muted)" } })
4795
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-dots-six-vertical fd-erow-grip", "aria-hidden": "true", style: { flex: "none", color: "var(--text-muted)" } })
3986
4796
  ) : null,
3987
- /* @__PURE__ */ jsxs46("span", { className: "fd-erow-body", children: [
3988
- /* @__PURE__ */ jsxs46("span", { className: "fd-erow-titleline", children: [
3989
- titleIcon ? /* @__PURE__ */ jsx51(Tooltip, { label: titleIcon.tooltip, children: /* @__PURE__ */ jsxs46(
4797
+ /* @__PURE__ */ jsxs50("span", { className: "fd-erow-body", children: [
4798
+ /* @__PURE__ */ jsxs50("span", { className: "fd-erow-titleline", children: [
4799
+ titleIcon ? /* @__PURE__ */ jsx55(Tooltip, { label: titleIcon.tooltip, children: /* @__PURE__ */ jsxs50(
3990
4800
  "button",
3991
4801
  {
3992
4802
  type: "button",
3993
4803
  className: ["fd-erow-title-icon", titleIcon.tone ? "is-" + titleIcon.tone : ""].filter(Boolean).join(" "),
3994
4804
  children: [
3995
- /* @__PURE__ */ jsx51("i", { className: "ph ph-" + titleIcon.icon, "aria-hidden": "true" }),
3996
- /* @__PURE__ */ jsx51("span", { className: "fd-erow-title fd-body-sm", children: title })
4805
+ /* @__PURE__ */ jsx55("i", { className: "ph ph-" + titleIcon.icon, "aria-hidden": "true" }),
4806
+ /* @__PURE__ */ jsx55("span", { className: "fd-erow-title fd-body-sm", children: title })
3997
4807
  ]
3998
4808
  }
3999
4809
  ) }) : (
4000
4810
  // MP-141: dense-row identifier, no Tooltip wrapper in this branch — a native
4001
4811
  // `title` is the exposure mechanism, same rule as every other identifier.
4002
- /* @__PURE__ */ jsx51("span", { className: "fd-erow-title fd-body-sm", title: truncationTitle(title), children: title })
4812
+ /* @__PURE__ */ jsx55("span", { className: "fd-erow-title fd-body-sm", title: truncationTitle(title), children: title })
4003
4813
  ),
4004
- meta ? /* @__PURE__ */ jsx51("span", { className: "fd-erow-meta", title: truncationTitle(meta), children: meta }) : null
4814
+ meta ? /* @__PURE__ */ jsx55("span", { className: "fd-erow-meta", title: truncationTitle(meta), children: meta }) : null
4005
4815
  ] }),
4006
- hasStrip ? /* @__PURE__ */ jsxs46("span", { className: "fd-erow-strip", children: [
4007
- metrics && metrics.length ? /* @__PURE__ */ jsx51(EntityRowMetrics, { metrics }) : null,
4008
- accessory ? /* @__PURE__ */ jsx51("span", { className: "fd-erow-accessory", children: accessory }) : null
4816
+ hasStrip ? /* @__PURE__ */ jsxs50("span", { className: "fd-erow-strip", children: [
4817
+ metrics && metrics.length ? /* @__PURE__ */ jsx55(EntityRowMetrics, { metrics }) : null,
4818
+ accessory ? /* @__PURE__ */ jsx55("span", { className: "fd-erow-accessory", children: accessory }) : null
4009
4819
  ] }) : null
4010
4820
  ] }),
4011
- action ? /* @__PURE__ */ jsx51(
4821
+ action ? /* @__PURE__ */ jsx55(
4012
4822
  IconButton,
4013
4823
  {
4014
4824
  icon: action.icon,
@@ -4026,30 +4836,11 @@ function EntityRow({
4026
4836
  }
4027
4837
 
4028
4838
  // src/components/data/TransferList.tsx
4029
- import * as React30 from "react";
4839
+ import * as React32 from "react";
4030
4840
  import { createPortal as createPortal4 } from "react-dom";
4031
4841
 
4032
- // src/components/forms/field.tsx
4033
- import * as React29 from "react";
4034
- import { jsx as jsx52, jsxs as jsxs47 } from "react/jsx-runtime";
4035
- function useFieldId(id) {
4036
- const generated = React29.useId();
4037
- return id || generated;
4038
- }
4039
- function FieldLabel({ htmlFor, id, required = false, onClick, children }) {
4040
- return /* @__PURE__ */ jsxs47("label", { className: "fd-field-label", htmlFor, id, onClick, children: [
4041
- children,
4042
- required ? /* @__PURE__ */ jsx52("span", { className: "fd-field-req", "aria-hidden": "true", children: "*" }) : null
4043
- ] });
4044
- }
4045
- function useTriggerLabelling(label, id) {
4046
- const fieldId = useFieldId(id);
4047
- const labelId = fieldId + "-label";
4048
- return { fieldId, labelId, ariaLabelledBy: label ? labelId + " " + fieldId : void 0 };
4049
- }
4050
-
4051
4842
  // src/components/forms/Input.tsx
4052
- import { jsx as jsx53, jsxs as jsxs48 } from "react/jsx-runtime";
4843
+ import { jsx as jsx56, jsxs as jsxs51 } from "react/jsx-runtime";
4053
4844
  function Input({
4054
4845
  label,
4055
4846
  help,
@@ -4076,24 +4867,24 @@ function Input({
4076
4867
  disabled ? "fd-input-disabled" : "",
4077
4868
  size === "lg" ? "fd-input-lg" : ""
4078
4869
  ].filter(Boolean).join(" ");
4079
- return /* @__PURE__ */ jsxs48("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
4080
- label ? /* @__PURE__ */ jsx53(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
4081
- /* @__PURE__ */ jsxs48("div", { className: box, children: [
4082
- icon ? /* @__PURE__ */ jsx53("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx53("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
4083
- prefix ? /* @__PURE__ */ jsx53("span", { className: "fd-input-affix", children: prefix }) : null,
4084
- /* @__PURE__ */ jsx53("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
4085
- loading ? /* @__PURE__ */ jsx53("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
4086
- suffix && !loading ? /* @__PURE__ */ jsx53("span", { className: "fd-input-affix", children: suffix }) : null
4870
+ return /* @__PURE__ */ jsxs51("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
4871
+ label ? /* @__PURE__ */ jsx56(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
4872
+ /* @__PURE__ */ jsxs51("div", { className: box, children: [
4873
+ icon ? /* @__PURE__ */ jsx56("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx56("i", { className: "ph ph-" + icon, "aria-hidden": "true" }) }) : null,
4874
+ prefix ? /* @__PURE__ */ jsx56("span", { className: "fd-input-affix", children: prefix }) : null,
4875
+ /* @__PURE__ */ jsx56("input", { id: fieldId, disabled, style: inputStyle, "aria-invalid": error ? "true" : void 0, ...rest }),
4876
+ loading ? /* @__PURE__ */ jsx56("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading" }) : null,
4877
+ suffix && !loading ? /* @__PURE__ */ jsx56("span", { className: "fd-input-affix", children: suffix }) : null
4087
4878
  ] }),
4088
- error ? /* @__PURE__ */ jsxs48("span", { className: "fd-field-error", children: [
4089
- /* @__PURE__ */ jsx53("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4879
+ error ? /* @__PURE__ */ jsxs51("span", { className: "fd-field-error", children: [
4880
+ /* @__PURE__ */ jsx56("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4090
4881
  error
4091
- ] }) : help ? /* @__PURE__ */ jsx53("span", { className: "fd-field-help", children: help }) : null
4882
+ ] }) : help ? /* @__PURE__ */ jsx56("span", { className: "fd-field-help", children: help }) : null
4092
4883
  ] });
4093
4884
  }
4094
4885
 
4095
4886
  // src/components/forms/SearchField.tsx
4096
- import { jsx as jsx54 } from "react/jsx-runtime";
4887
+ import { jsx as jsx57 } from "react/jsx-runtime";
4097
4888
  function SearchField({
4098
4889
  value,
4099
4890
  onChange,
@@ -4108,7 +4899,7 @@ function SearchField({
4108
4899
  ...rest
4109
4900
  }) {
4110
4901
  const clear = onClear || (() => onChange(""));
4111
- return /* @__PURE__ */ jsx54(
4902
+ return /* @__PURE__ */ jsx57(
4112
4903
  Input,
4113
4904
  {
4114
4905
  id,
@@ -4121,14 +4912,14 @@ function SearchField({
4121
4912
  style,
4122
4913
  className,
4123
4914
  onChange: (e) => onChange(e.target.value),
4124
- suffix: value ? /* @__PURE__ */ jsx54(
4915
+ suffix: value ? /* @__PURE__ */ jsx57(
4125
4916
  "button",
4126
4917
  {
4127
4918
  type: "button",
4128
4919
  "aria-label": "Clear search",
4129
4920
  onClick: clear,
4130
4921
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
4131
- children: /* @__PURE__ */ jsx54("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
4922
+ children: /* @__PURE__ */ jsx57("i", { className: "ph ph-x-circle", style: { fontSize: 15 }, "aria-hidden": "true" })
4132
4923
  }
4133
4924
  ) : void 0,
4134
4925
  ...rest
@@ -4137,7 +4928,7 @@ function SearchField({
4137
4928
  }
4138
4929
 
4139
4930
  // src/components/data/TransferList.tsx
4140
- import { jsx as jsx55, jsxs as jsxs49 } from "react/jsx-runtime";
4931
+ import { jsx as jsx58, jsxs as jsxs52 } from "react/jsx-runtime";
4141
4932
  var emptyHasMore = {};
4142
4933
  var DRAG_THRESHOLD_PX = 5;
4143
4934
  function TransferList({
@@ -4151,12 +4942,12 @@ function TransferList({
4151
4942
  listHeight = 440,
4152
4943
  className = ""
4153
4944
  }) {
4154
- const [drag, setDrag] = React30.useState(null);
4155
- const [dragOverSide, setDragOverSide] = React30.useState(null);
4156
- const dragRef = React30.useRef(null);
4157
- const armedRef = React30.useRef(null);
4158
- const sideRefs = React30.useRef({ left: null, right: null });
4159
- const hitTestSide = React30.useCallback((x, y) => {
4945
+ const [drag, setDrag] = React32.useState(null);
4946
+ const [dragOverSide, setDragOverSide] = React32.useState(null);
4947
+ const dragRef = React32.useRef(null);
4948
+ const armedRef = React32.useRef(null);
4949
+ const sideRefs = React32.useRef({ left: null, right: null });
4950
+ const hitTestSide = React32.useCallback((x, y) => {
4160
4951
  for (const side of ["left", "right"]) {
4161
4952
  const el = sideRefs.current[side];
4162
4953
  if (!el) continue;
@@ -4165,7 +4956,7 @@ function TransferList({
4165
4956
  }
4166
4957
  return null;
4167
4958
  }, []);
4168
- const findItem = React30.useCallback(
4959
+ const findItem = React32.useCallback(
4169
4960
  (side, key) => (side === "left" ? left.items : right.items).find((it) => keyOf(it) === key),
4170
4961
  [left.items, right.items, keyOf]
4171
4962
  );
@@ -4187,7 +4978,7 @@ function TransferList({
4187
4978
  height: rect.height
4188
4979
  };
4189
4980
  };
4190
- React30.useEffect(() => {
4981
+ React32.useEffect(() => {
4191
4982
  const onMovePointer = (e) => {
4192
4983
  const armed = armedRef.current;
4193
4984
  if (!armed || e.pointerId !== armed.pointerId) return;
@@ -4240,7 +5031,7 @@ function TransferList({
4240
5031
  window.removeEventListener("pointercancel", endDrag);
4241
5032
  };
4242
5033
  }, [hitTestSide, findItem, onMove]);
4243
- React30.useEffect(() => {
5034
+ React32.useEffect(() => {
4244
5035
  if (!drag || typeof document === "undefined") return;
4245
5036
  const prev = document.body.style.userSelect;
4246
5037
  document.body.style.userSelect = "none";
@@ -4250,7 +5041,7 @@ function TransferList({
4250
5041
  }, [drag]);
4251
5042
  const renderSide = (side, cfg, opposite) => {
4252
5043
  const showOverlay = drag != null && dragOverSide === side;
4253
- return /* @__PURE__ */ jsxs49(
5044
+ return /* @__PURE__ */ jsxs52(
4254
5045
  "div",
4255
5046
  {
4256
5047
  ref: (el) => {
@@ -4258,16 +5049,16 @@ function TransferList({
4258
5049
  },
4259
5050
  className: ["fd-tlist-side", dragOverSide === side ? "is-drop-target" : ""].filter(Boolean).join(" "),
4260
5051
  children: [
4261
- cfg.label ? /* @__PURE__ */ jsxs49("span", { className: "fd-overline fd-muted", children: [
5052
+ cfg.label ? /* @__PURE__ */ jsxs52("span", { className: "fd-overline fd-muted", children: [
4262
5053
  cfg.label,
4263
5054
  cfg.total != null ? " (" + cfg.total.toLocaleString() + ")" : ""
4264
5055
  ] }) : null,
4265
- cfg.header ? /* @__PURE__ */ jsx55("div", { className: "fd-tlist-header", children: cfg.header }) : null,
4266
- /* @__PURE__ */ jsxs49("span", { className: "fd-row", style: { gap: 8 }, children: [
4267
- /* @__PURE__ */ jsx55(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
4268
- /* @__PURE__ */ jsx55(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
5056
+ cfg.header ? /* @__PURE__ */ jsx58("div", { className: "fd-tlist-header", children: cfg.header }) : null,
5057
+ /* @__PURE__ */ jsxs52("span", { className: "fd-row", style: { gap: 8 }, children: [
5058
+ /* @__PURE__ */ jsx58(SearchField, { value: cfg.search, onChange: cfg.onSearchChange, placeholder: "Search", "aria-label": (cfg.label || side) + " search", style: { flex: 1 } }),
5059
+ /* @__PURE__ */ jsx58(SortMenu, { fields: cfg.sortFields, sort: cfg.sort, onSort: cfg.onSort, align: side === "left" ? "left" : "right" })
4269
5060
  ] }),
4270
- /* @__PURE__ */ jsx55(
5061
+ /* @__PURE__ */ jsx58(
4271
5062
  VirtualList,
4272
5063
  {
4273
5064
  items: cfg.items,
@@ -4281,15 +5072,15 @@ function TransferList({
4281
5072
  firstItemIndex: cfg.firstItemIndex,
4282
5073
  totalCount: cfg.totalCount,
4283
5074
  onNeedMore: cfg.onNeedMore,
4284
- emptyState: /* @__PURE__ */ jsx55(EmptyState, { icon: "tray", title: "Nothing here" }),
5075
+ emptyState: /* @__PURE__ */ jsx58(EmptyState, { icon: "tray", title: "Nothing here" }),
4285
5076
  renderItem: (item) => {
4286
5077
  const isBeingDragged = drag != null && drag.from === side && drag.key === keyOf(item);
4287
5078
  if (isBeingDragged) {
4288
- return /* @__PURE__ */ jsx55("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
5079
+ return /* @__PURE__ */ jsx58("div", { className: "fd-erow-placeholder", "aria-hidden": "true" });
4289
5080
  }
4290
5081
  const content = renderRow(item);
4291
5082
  const destination = (side === "left" ? right : left).label || "the other list";
4292
- return /* @__PURE__ */ jsx55(
5083
+ return /* @__PURE__ */ jsx58(
4293
5084
  EntityRow,
4294
5085
  {
4295
5086
  ...content,
@@ -4309,252 +5100,95 @@ function TransferList({
4309
5100
  }
4310
5101
  }
4311
5102
  ),
4312
- cfg.footer ? /* @__PURE__ */ jsx55("div", { className: "fd-tlist-footer", children: cfg.footer }) : null,
4313
- showOverlay ? /* @__PURE__ */ jsx55("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ jsxs49("span", { className: "fd-tlist-drop-card", children: [
4314
- /* @__PURE__ */ jsx55("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
4315
- /* @__PURE__ */ jsx55("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
5103
+ cfg.footer ? /* @__PURE__ */ jsx58("div", { className: "fd-tlist-footer", children: cfg.footer }) : null,
5104
+ showOverlay ? /* @__PURE__ */ jsx58("div", { className: "fd-tlist-drop-overlay", "aria-hidden": "true", children: /* @__PURE__ */ jsxs52("span", { className: "fd-tlist-drop-card", children: [
5105
+ /* @__PURE__ */ jsx58("i", { className: "ph ph-tray-arrow-down", style: { fontSize: 18 }, "aria-hidden": "true" }),
5106
+ /* @__PURE__ */ jsx58("span", { className: "fd-body-sm", style: { fontWeight: 600 }, children: cfg.dropLabel || "Drop here" + (cfg.label ? " \u2014 " + cfg.label : "") })
4316
5107
  ] }) }) : null
4317
5108
  ]
4318
5109
  }
4319
5110
  );
4320
5111
  };
4321
- return /* @__PURE__ */ jsxs49("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), children: [
4322
- /* @__PURE__ */ jsxs49("div", { className: "fd-tlist-panes", children: [
5112
+ return /* @__PURE__ */ jsxs52("div", { className: ["fd-tlist", className].filter(Boolean).join(" "), children: [
5113
+ /* @__PURE__ */ jsxs52("div", { className: "fd-tlist-panes", children: [
4323
5114
  renderSide("left", left, "right"),
4324
5115
  renderSide("right", right, "left")
4325
5116
  ] }),
4326
5117
  drag ? createPortal4(
4327
- /* @__PURE__ */ jsx55(
5118
+ /* @__PURE__ */ jsx58(
4328
5119
  "div",
4329
5120
  {
4330
- "aria-hidden": "true",
4331
- className: "fd-erow-ghost",
4332
- style: {
4333
- position: "fixed",
4334
- left: 0,
4335
- top: 0,
4336
- width: drag.width,
4337
- height: drag.height,
4338
- transform: `translate(${drag.x - drag.offsetX}px, ${drag.y - drag.offsetY}px) rotate(-3deg)`,
4339
- pointerEvents: "none",
4340
- zIndex: OVERLAY_CEILING
4341
- },
4342
- children: /* @__PURE__ */ jsx55(EntityRow, { ...renderRow(drag.item), draggable: true, className: "fd-erow-dragging" })
4343
- }
4344
- ),
4345
- document.body
4346
- ) : null
4347
- ] });
4348
- }
4349
-
4350
- // src/components/forms/Checkbox.tsx
4351
- import * as React31 from "react";
4352
- import { jsx as jsx56, jsxs as jsxs50 } from "react/jsx-runtime";
4353
- function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
4354
- const ref = React31.useRef(null);
4355
- React31.useEffect(() => {
4356
- if (ref.current) ref.current.indeterminate = indeterminate;
4357
- }, [indeterminate]);
4358
- return /* @__PURE__ */ jsxs50("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
4359
- /* @__PURE__ */ jsxs50("span", { className: "fd-choice-input", children: [
4360
- /* @__PURE__ */ jsx56("input", { ref, type: "checkbox", ...rest }),
4361
- /* @__PURE__ */ jsx56("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx56("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
4362
- ] }),
4363
- /* @__PURE__ */ jsxs50("span", { className: "fd-choice-text", children: [
4364
- /* @__PURE__ */ jsx56("span", { className: "fd-choice-title", children: label }),
4365
- description ? /* @__PURE__ */ jsx56("span", { className: "fd-choice-desc", children: description }) : null
4366
- ] })
4367
- ] });
4368
- }
4369
-
4370
- // src/components/forms/Radio.tsx
4371
- import { jsx as jsx57, jsxs as jsxs51 } from "react/jsx-runtime";
4372
- function Radio({ label, description, card = false, className = "", ...rest }) {
4373
- return /* @__PURE__ */ jsxs51("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
4374
- /* @__PURE__ */ jsxs51("span", { className: "fd-choice-input", children: [
4375
- /* @__PURE__ */ jsx57("input", { type: "radio", ...rest }),
4376
- /* @__PURE__ */ jsx57("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx57("span", { className: "fd-choice-dot" }) })
4377
- ] }),
4378
- /* @__PURE__ */ jsxs51("span", { className: "fd-choice-text", children: [
4379
- /* @__PURE__ */ jsx57("span", { className: "fd-choice-title", children: label }),
4380
- description ? /* @__PURE__ */ jsx57("span", { className: "fd-choice-desc", children: description }) : null
4381
- ] })
4382
- ] });
4383
- }
4384
-
4385
- // src/components/forms/Switch.tsx
4386
- import { jsx as jsx58, jsxs as jsxs52 } from "react/jsx-runtime";
4387
- function Switch({ label, description, className = "", ...rest }) {
4388
- return /* @__PURE__ */ jsxs52("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
4389
- /* @__PURE__ */ jsx58("input", { type: "checkbox", role: "switch", ...rest }),
4390
- /* @__PURE__ */ jsx58("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx58("span", { className: "fd-switch-thumb" }) }),
4391
- label ? /* @__PURE__ */ jsxs52("span", { className: "fd-choice-text", children: [
4392
- /* @__PURE__ */ jsx58("span", { className: "fd-switch-label", children: label }),
4393
- description ? /* @__PURE__ */ jsx58("span", { className: "fd-choice-desc", children: description }) : null
4394
- ] }) : null
4395
- ] });
4396
- }
4397
-
4398
- // src/components/forms/Textarea.tsx
4399
- import { jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
4400
- function Textarea({ label, help, error, required = false, rows = 4, disabled = false, id, className = "", style, ...rest }) {
4401
- const fieldId = useFieldId(id);
4402
- const box = ["fd-input", "fd-input-textarea", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
4403
- return /* @__PURE__ */ jsxs53("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
4404
- label ? /* @__PURE__ */ jsx59(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
4405
- /* @__PURE__ */ jsx59("div", { className: box, children: /* @__PURE__ */ jsx59("textarea", { id: fieldId, rows, disabled, "aria-invalid": error ? "true" : void 0, ...rest }) }),
4406
- error ? /* @__PURE__ */ jsxs53("span", { className: "fd-field-error", children: [
4407
- /* @__PURE__ */ jsx59("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4408
- error
4409
- ] }) : help ? /* @__PURE__ */ jsx59("span", { className: "fd-field-help", children: help }) : null
4410
- ] });
4411
- }
4412
-
4413
- // src/components/forms/NumberInput.tsx
4414
- import * as React32 from "react";
4415
- import { jsx as jsx60, jsxs as jsxs54 } from "react/jsx-runtime";
4416
- function NumberInput({
4417
- label,
4418
- help,
4419
- error,
4420
- prefix,
4421
- suffix,
4422
- required = false,
4423
- disabled = false,
4424
- min = -Infinity,
4425
- max = Infinity,
4426
- step = 1,
4427
- bigStep,
4428
- value,
4429
- onChange,
4430
- format = true,
4431
- className = "",
4432
- style,
4433
- placeholder,
4434
- id,
4435
- "aria-label": ariaLabel
4436
- }) {
4437
- const fieldId = useFieldId(id);
4438
- const num = (v) => {
4439
- const n = Number(String(v == null ? "" : v).replace(/[^0-9.-]/g, ""));
4440
- return isNaN(n) ? null : n;
4441
- };
4442
- const [text, setText] = React32.useState(value == null || value === "" ? "" : String(value));
4443
- const [editing, setEditing] = React32.useState(false);
4444
- const timer = React32.useRef(null);
4445
- React32.useEffect(() => {
4446
- if (!editing) setText(value == null || value === "" ? "" : String(value));
4447
- }, [value, editing]);
4448
- const clamp = (n) => Math.min(max, Math.max(min, n));
4449
- const fire = (n) => onChange && onChange({ target: { value: n } });
4450
- const bump = (dir, mult = 1) => {
4451
- const cur = num(text) ?? num(value) ?? (min === -Infinity ? 0 : min);
4452
- const next = clamp(cur + dir * (bigStep && mult > 1 ? bigStep : step) * (bigStep ? 1 : mult));
4453
- setText(String(next));
4454
- fire(next);
4455
- };
4456
- const hold = (dir) => {
4457
- bump(dir);
4458
- let n = 0;
4459
- const tick = () => {
4460
- n++;
4461
- bump(dir, n > 6 ? 4 : 1);
4462
- timer.current = setTimeout(tick, n > 12 ? 40 : n > 6 ? 70 : 120);
4463
- };
4464
- timer.current = setTimeout(tick, 420);
4465
- };
4466
- const release = () => {
4467
- if (timer.current) clearTimeout(timer.current);
4468
- };
4469
- React32.useEffect(() => () => {
4470
- if (timer.current) clearTimeout(timer.current);
4471
- }, []);
4472
- const shown = editing ? text : (() => {
4473
- const n = num(text);
4474
- return n == null ? "" : format ? n.toLocaleString() : String(n);
4475
- })();
4476
- const box = ["fd-input", "fd-input-num", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
4477
- const fieldName = label || ariaLabel;
4478
- const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
4479
- return /* @__PURE__ */ jsxs54("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
4480
- label ? /* @__PURE__ */ jsx60(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
4481
- /* @__PURE__ */ jsxs54("div", { className: box, style: { gap: 8 }, children: [
4482
- prefix ? /* @__PURE__ */ jsx60("span", { className: "fd-input-affix", children: prefix }) : null,
4483
- /* @__PURE__ */ jsx60(
4484
- "input",
4485
- {
4486
- id: fieldId,
4487
- "aria-label": ariaLabel,
4488
- inputMode: "numeric",
4489
- disabled,
4490
- placeholder,
4491
- value: shown,
4492
- onFocus: () => setEditing(true),
4493
- onBlur: () => {
4494
- setEditing(false);
4495
- const n = num(text);
4496
- if (n != null) {
4497
- const c = clamp(n);
4498
- setText(String(c));
4499
- fire(c);
4500
- }
4501
- },
4502
- onChange: (e) => {
4503
- setText(e.target.value);
4504
- const n = num(e.target.value);
4505
- if (n != null) fire(n);
5121
+ "aria-hidden": "true",
5122
+ className: "fd-erow-ghost",
5123
+ style: {
5124
+ position: "fixed",
5125
+ left: 0,
5126
+ top: 0,
5127
+ width: drag.width,
5128
+ height: drag.height,
5129
+ transform: `translate(${drag.x - drag.offsetX}px, ${drag.y - drag.offsetY}px) rotate(-3deg)`,
5130
+ pointerEvents: "none",
5131
+ zIndex: OVERLAY_CEILING
4506
5132
  },
4507
- onKeyDown: (e) => {
4508
- if (e.key === "ArrowUp") {
4509
- e.preventDefault();
4510
- bump(1, e.shiftKey ? 2 : 1);
4511
- } else if (e.key === "ArrowDown") {
4512
- e.preventDefault();
4513
- bump(-1, e.shiftKey ? 2 : 1);
4514
- }
4515
- }
5133
+ children: /* @__PURE__ */ jsx58(EntityRow, { ...renderRow(drag.item), draggable: true, className: "fd-erow-dragging" })
4516
5134
  }
4517
5135
  ),
4518
- suffix ? /* @__PURE__ */ jsx60("span", { className: "fd-input-affix", children: suffix }) : null,
4519
- /* @__PURE__ */ jsxs54("span", { className: "fd-row", style: { gap: 4, flex: "none" }, children: [
4520
- /* @__PURE__ */ jsx60(
4521
- "button",
4522
- {
4523
- type: "button",
4524
- className: "fd-stepbtn",
4525
- "aria-label": stepperName("Decrease"),
4526
- disabled: disabled || (num(text) ?? 0) <= min,
4527
- onPointerDown: () => hold(-1),
4528
- onPointerUp: release,
4529
- onPointerLeave: release,
4530
- children: /* @__PURE__ */ jsx60("i", { className: "ph ph-minus" })
4531
- }
4532
- ),
4533
- /* @__PURE__ */ jsx60(
4534
- "button",
4535
- {
4536
- type: "button",
4537
- className: "fd-stepbtn",
4538
- "aria-label": stepperName("Increase"),
4539
- disabled: disabled || (num(text) ?? 0) >= max,
4540
- onPointerDown: () => hold(1),
4541
- onPointerUp: release,
4542
- onPointerLeave: release,
4543
- children: /* @__PURE__ */ jsx60("i", { className: "ph ph-plus" })
4544
- }
4545
- )
4546
- ] })
4547
- ] }),
4548
- error ? /* @__PURE__ */ jsxs54("span", { className: "fd-field-error", children: [
4549
- /* @__PURE__ */ jsx60("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4550
- error
4551
- ] }) : help ? /* @__PURE__ */ jsx60("span", { className: "fd-field-help", children: help }) : null
5136
+ document.body
5137
+ ) : null
4552
5138
  ] });
4553
5139
  }
4554
5140
 
4555
- // src/components/forms/Select.tsx
5141
+ // src/components/forms/Checkbox.tsx
4556
5142
  import * as React33 from "react";
5143
+ import { jsx as jsx59, jsxs as jsxs53 } from "react/jsx-runtime";
5144
+ function Checkbox({ label, description, card = false, indeterminate = false, className = "", ...rest }) {
5145
+ const ref = React33.useRef(null);
5146
+ React33.useEffect(() => {
5147
+ if (ref.current) ref.current.indeterminate = indeterminate;
5148
+ }, [indeterminate]);
5149
+ return /* @__PURE__ */ jsxs53("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
5150
+ /* @__PURE__ */ jsxs53("span", { className: "fd-choice-input", children: [
5151
+ /* @__PURE__ */ jsx59("input", { ref, type: "checkbox", ...rest }),
5152
+ /* @__PURE__ */ jsx59("span", { className: "fd-choice-box", "aria-hidden": "true", children: /* @__PURE__ */ jsx59("i", { className: indeterminate ? "ph ph-minus" : "ph ph-check" }) })
5153
+ ] }),
5154
+ /* @__PURE__ */ jsxs53("span", { className: "fd-choice-text", children: [
5155
+ /* @__PURE__ */ jsx59("span", { className: "fd-choice-title", children: label }),
5156
+ description ? /* @__PURE__ */ jsx59("span", { className: "fd-choice-desc", children: description }) : null
5157
+ ] })
5158
+ ] });
5159
+ }
5160
+
5161
+ // src/components/forms/Radio.tsx
5162
+ import { jsx as jsx60, jsxs as jsxs54 } from "react/jsx-runtime";
5163
+ function Radio({ label, description, card = false, className = "", ...rest }) {
5164
+ return /* @__PURE__ */ jsxs54("label", { className: ["fd-choice", card ? "fd-choice-card" : "", className].filter(Boolean).join(" "), children: [
5165
+ /* @__PURE__ */ jsxs54("span", { className: "fd-choice-input", children: [
5166
+ /* @__PURE__ */ jsx60("input", { type: "radio", ...rest }),
5167
+ /* @__PURE__ */ jsx60("span", { className: "fd-choice-box fd-choice-box-round", "aria-hidden": "true", children: /* @__PURE__ */ jsx60("span", { className: "fd-choice-dot" }) })
5168
+ ] }),
5169
+ /* @__PURE__ */ jsxs54("span", { className: "fd-choice-text", children: [
5170
+ /* @__PURE__ */ jsx60("span", { className: "fd-choice-title", children: label }),
5171
+ description ? /* @__PURE__ */ jsx60("span", { className: "fd-choice-desc", children: description }) : null
5172
+ ] })
5173
+ ] });
5174
+ }
5175
+
5176
+ // src/components/forms/Switch.tsx
4557
5177
  import { jsx as jsx61, jsxs as jsxs55 } from "react/jsx-runtime";
5178
+ function Switch({ label, description, className = "", ...rest }) {
5179
+ return /* @__PURE__ */ jsxs55("label", { className: ["fd-switch", className].filter(Boolean).join(" "), children: [
5180
+ /* @__PURE__ */ jsx61("input", { type: "checkbox", role: "switch", ...rest }),
5181
+ /* @__PURE__ */ jsx61("span", { className: "fd-switch-track", children: /* @__PURE__ */ jsx61("span", { className: "fd-switch-thumb" }) }),
5182
+ label ? /* @__PURE__ */ jsxs55("span", { className: "fd-choice-text", children: [
5183
+ /* @__PURE__ */ jsx61("span", { className: "fd-switch-label", children: label }),
5184
+ description ? /* @__PURE__ */ jsx61("span", { className: "fd-choice-desc", children: description }) : null
5185
+ ] }) : null
5186
+ ] });
5187
+ }
5188
+
5189
+ // src/components/forms/Select.tsx
5190
+ import * as React34 from "react";
5191
+ import { jsx as jsx62, jsxs as jsxs56 } from "react/jsx-runtime";
4558
5192
  var norm = (o) => typeof o === "string" ? { value: o, label: o } : o;
4559
5193
  function Select({
4560
5194
  label,
@@ -4580,13 +5214,13 @@ function Select({
4580
5214
  const isOn = (v) => multiple ? vals.includes(v) : v === value;
4581
5215
  const hasSearch = searchable === void 0 ? opts.length > 8 : searchable;
4582
5216
  const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
4583
- const [open, setOpen] = React33.useState(false);
4584
- const [q, setQ] = React33.useState("");
4585
- const [active, setActive] = React33.useState(-1);
4586
- const rootRef = React33.useRef(null);
4587
- const boxRef = React33.useRef(null);
4588
- const listRef = React33.useRef(null);
4589
- const typeBuf = React33.useRef({ s: "", t: 0 });
5217
+ const [open, setOpen] = React34.useState(false);
5218
+ const [q, setQ] = React34.useState("");
5219
+ const [active, setActive] = React34.useState(-1);
5220
+ const rootRef = React34.useRef(null);
5221
+ const boxRef = React34.useRef(null);
5222
+ const listRef = React34.useRef(null);
5223
+ const typeBuf = React34.useRef({ s: "", t: 0 });
4590
5224
  const selected = multiple ? null : opts.find((o) => o.value === value);
4591
5225
  const chosen = multiple ? opts.filter((o) => vals.includes(o.value)) : [];
4592
5226
  const boxText = multiple ? chosen.length === 0 ? placeholder : chosen.length === 1 ? chosen[0].label : summary ? summary(chosen.map((o) => o.value)) : chosen.length + " selected" : selected ? selected.label : placeholder;
@@ -4611,7 +5245,7 @@ function Select({
4611
5245
  }
4612
5246
  setOpen(!open);
4613
5247
  };
4614
- React33.useEffect(() => {
5248
+ React34.useEffect(() => {
4615
5249
  if (!open || active < 0 || !listRef.current) return;
4616
5250
  const el = listRef.current.querySelector('[data-i="' + active + '"]');
4617
5251
  if (el) {
@@ -4664,10 +5298,10 @@ function Select({
4664
5298
  else last.items.push({ o, i });
4665
5299
  });
4666
5300
  const box = ["fd-input", "fd-select", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
4667
- return /* @__PURE__ */ jsxs55("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
4668
- label ? /* @__PURE__ */ jsx61(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
4669
- /* @__PURE__ */ jsxs55("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
4670
- /* @__PURE__ */ jsxs55(
5301
+ return /* @__PURE__ */ jsxs56("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
5302
+ label ? /* @__PURE__ */ jsx62(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
5303
+ /* @__PURE__ */ jsxs56("div", { className: box, style: { cursor: disabled ? "not-allowed" : "pointer" }, ref: boxRef, children: [
5304
+ /* @__PURE__ */ jsxs56(
4671
5305
  "button",
4672
5306
  {
4673
5307
  type: "button",
@@ -4681,13 +5315,13 @@ function Select({
4681
5315
  "aria-labelledby": ariaLabelledBy,
4682
5316
  style: { all: "unset", flex: 1, minWidth: 0, display: "flex", alignItems: "center", gap: 8, cursor: "inherit", overflow: "hidden" },
4683
5317
  children: [
4684
- selected && selected.icon ? /* @__PURE__ */ jsx61("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
4685
- /* @__PURE__ */ jsx61("span", { title: truncationTitle(boxText), style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
4686
- multiple && chosen.length > 1 ? /* @__PURE__ */ jsx61("span", { className: "fd-mono", style: { flex: "none", fontSize: 11, fontWeight: 700, padding: "1px 6px", borderRadius: 99, background: "var(--brand)", color: "#fff" }, children: chosen.length }) : null
5318
+ selected && selected.icon ? /* @__PURE__ */ jsx62("i", { className: "ph ph-" + selected.icon, style: { flex: "none", color: "var(--text-2)" } }) : null,
5319
+ /* @__PURE__ */ jsx62("span", { title: truncationTitle(boxText), style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: (multiple ? chosen.length : selected) ? "var(--text)" : "var(--text-muted)" }, children: boxText }),
5320
+ multiple && chosen.length > 1 ? /* @__PURE__ */ jsx62("span", { className: "fd-mono", style: { flex: "none", fontSize: 11, fontWeight: 700, padding: "1px 6px", borderRadius: 99, background: "var(--brand)", color: "#fff" }, children: chosen.length }) : null
4687
5321
  ]
4688
5322
  }
4689
5323
  ),
4690
- clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx61(
5324
+ clearable && (multiple ? chosen.length > 0 : selected) && !loading ? /* @__PURE__ */ jsx62(
4691
5325
  "button",
4692
5326
  {
4693
5327
  type: "button",
@@ -4697,12 +5331,12 @@ function Select({
4697
5331
  fire(multiple ? [] : "");
4698
5332
  },
4699
5333
  style: { all: "unset", cursor: "pointer", color: "var(--text-muted)", display: "grid", placeItems: "center", padding: 2 },
4700
- children: /* @__PURE__ */ jsx61("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
5334
+ children: /* @__PURE__ */ jsx62("i", { className: "ph ph-x-circle", style: { fontSize: 15 } })
4701
5335
  }
4702
5336
  ) : null,
4703
- loading ? /* @__PURE__ */ jsx61("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx61("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx61("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
5337
+ loading ? /* @__PURE__ */ jsx62("span", { className: "fd-spinner", style: { color: "var(--text-muted)" }, "aria-label": "Loading options" }) : /* @__PURE__ */ jsx62("span", { className: "fd-select-caret", onClick: toggle, children: /* @__PURE__ */ jsx62("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
4704
5338
  ] }),
4705
- /* @__PURE__ */ jsx61(
5339
+ /* @__PURE__ */ jsx62(
4706
5340
  Popover,
4707
5341
  {
4708
5342
  open,
@@ -4715,9 +5349,9 @@ function Select({
4715
5349
  minWidth: 260,
4716
5350
  role: "presentation",
4717
5351
  style: { maxWidth: 380 },
4718
- header: hasSearch ? /* @__PURE__ */ jsxs55("div", { className: "fd-pop-search", children: [
4719
- /* @__PURE__ */ jsx61("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
4720
- /* @__PURE__ */ jsx61(
5352
+ header: hasSearch ? /* @__PURE__ */ jsxs56("div", { className: "fd-pop-search", children: [
5353
+ /* @__PURE__ */ jsx62("i", { className: "ph ph-magnifying-glass", style: { color: "var(--text-muted)", fontSize: 14 } }),
5354
+ /* @__PURE__ */ jsx62(
4721
5355
  "input",
4722
5356
  {
4723
5357
  autoFocus: true,
@@ -4730,10 +5364,10 @@ function Select({
4730
5364
  }
4731
5365
  }
4732
5366
  ),
4733
- q ? /* @__PURE__ */ jsx61("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
5367
+ q ? /* @__PURE__ */ jsx62("span", { className: "fd-body-sm fd-muted", children: visible.length }) : null
4734
5368
  ] }) : void 0,
4735
- footer: multiple ? /* @__PURE__ */ jsxs55(React33.Fragment, { children: [
4736
- /* @__PURE__ */ jsx61(
5369
+ footer: multiple ? /* @__PURE__ */ jsxs56(React34.Fragment, { children: [
5370
+ /* @__PURE__ */ jsx62(
4737
5371
  "button",
4738
5372
  {
4739
5373
  type: "button",
@@ -4742,13 +5376,13 @@ function Select({
4742
5376
  children: "Select all"
4743
5377
  }
4744
5378
  ),
4745
- /* @__PURE__ */ jsx61("span", { style: { flex: 1 } }),
4746
- /* @__PURE__ */ jsxs55("span", { className: "fd-body-sm fd-muted", children: [
5379
+ /* @__PURE__ */ jsx62("span", { style: { flex: 1 } }),
5380
+ /* @__PURE__ */ jsxs56("span", { className: "fd-body-sm fd-muted", children: [
4747
5381
  vals.length,
4748
5382
  " of ",
4749
5383
  opts.length
4750
5384
  ] }),
4751
- /* @__PURE__ */ jsx61(
5385
+ /* @__PURE__ */ jsx62(
4752
5386
  "button",
4753
5387
  {
4754
5388
  type: "button",
@@ -4759,13 +5393,13 @@ function Select({
4759
5393
  }
4760
5394
  )
4761
5395
  ] }) : void 0,
4762
- children: /* @__PURE__ */ jsx61("div", { className: "fd-pop-list", role: "listbox", "aria-multiselectable": multiple || void 0, ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsxs55("div", { className: "fd-pop-empty", children: [
5396
+ children: /* @__PURE__ */ jsx62("div", { className: "fd-pop-list", role: "listbox", "aria-multiselectable": multiple || void 0, ref: listRef, children: visible.length === 0 ? /* @__PURE__ */ jsxs56("div", { className: "fd-pop-empty", children: [
4763
5397
  'Nothing matches "',
4764
5398
  q,
4765
5399
  '".'
4766
- ] }) : groups.map((grp) => /* @__PURE__ */ jsxs55(React33.Fragment, { children: [
4767
- grp.g ? /* @__PURE__ */ jsx61("div", { className: "fd-pop-group", children: grp.g }) : null,
4768
- grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs55(
5400
+ ] }) : groups.map((grp) => /* @__PURE__ */ jsxs56(React34.Fragment, { children: [
5401
+ grp.g ? /* @__PURE__ */ jsx62("div", { className: "fd-pop-group", children: grp.g }) : null,
5402
+ grp.items.map(({ o, i }) => /* @__PURE__ */ jsxs56(
4769
5403
  "button",
4770
5404
  {
4771
5405
  type: "button",
@@ -4777,14 +5411,14 @@ function Select({
4777
5411
  onMouseEnter: () => setActive(i),
4778
5412
  onClick: () => pick(o),
4779
5413
  children: [
4780
- multiple ? /* @__PURE__ */ jsx61("span", { "aria-hidden": "true", style: { flex: "none", display: "grid", placeItems: "center", width: 16, height: 16, borderRadius: 4, border: "1.5px solid " + (isOn(o.value) ? "var(--brand)" : "var(--border-strong, var(--border))"), background: isOn(o.value) ? "var(--brand)" : "var(--surface)", color: "#fff" }, children: isOn(o.value) ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
4781
- o.icon ? /* @__PURE__ */ jsx61("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx61("i", { className: "ph ph-" + o.icon }) }) : null,
4782
- /* @__PURE__ */ jsxs55("span", { style: { flex: 1, minWidth: 0 }, children: [
4783
- /* @__PURE__ */ jsx61("span", { className: "fd-opt-label", children: o.label }),
4784
- o.description ? /* @__PURE__ */ jsx61("span", { className: "fd-opt-desc", children: o.description }) : null
5414
+ multiple ? /* @__PURE__ */ jsx62("span", { "aria-hidden": "true", style: { flex: "none", display: "grid", placeItems: "center", width: 16, height: 16, borderRadius: 4, border: "1.5px solid " + (isOn(o.value) ? "var(--brand)" : "var(--border-strong, var(--border))"), background: isOn(o.value) ? "var(--brand)" : "var(--surface)", color: "#fff" }, children: isOn(o.value) ? /* @__PURE__ */ jsx62("i", { className: "ph ph-check", style: { fontSize: 11 } }) : null }) : null,
5415
+ o.icon ? /* @__PURE__ */ jsx62("span", { className: "fd-opt-icon", children: /* @__PURE__ */ jsx62("i", { className: "ph ph-" + o.icon }) }) : null,
5416
+ /* @__PURE__ */ jsxs56("span", { style: { flex: 1, minWidth: 0 }, children: [
5417
+ /* @__PURE__ */ jsx62("span", { className: "fd-opt-label", children: o.label }),
5418
+ o.description ? /* @__PURE__ */ jsx62("span", { className: "fd-opt-desc", children: o.description }) : null
4785
5419
  ] }),
4786
- o.meta ? /* @__PURE__ */ jsx61("span", { className: "fd-opt-meta", children: o.meta }) : null,
4787
- multiple ? null : /* @__PURE__ */ jsx61("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx61("i", { className: "ph ph-check" }) : null })
5420
+ o.meta ? /* @__PURE__ */ jsx62("span", { className: "fd-opt-meta", children: o.meta }) : null,
5421
+ multiple ? null : /* @__PURE__ */ jsx62("span", { className: "fd-opt-check", children: o.value === value ? /* @__PURE__ */ jsx62("i", { className: "ph ph-check" }) : null })
4788
5422
  ]
4789
5423
  },
4790
5424
  String(o.value)
@@ -4792,208 +5426,6 @@ function Select({
4792
5426
  ] }, grp.g || "_")) })
4793
5427
  }
4794
5428
  ),
4795
- error ? /* @__PURE__ */ jsxs55("span", { className: "fd-field-error", children: [
4796
- /* @__PURE__ */ jsx61("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4797
- error
4798
- ] }) : help ? /* @__PURE__ */ jsx61("span", { className: "fd-field-help", children: help }) : null
4799
- ] });
4800
- }
4801
-
4802
- // src/components/forms/DatePicker.tsx
4803
- import * as React34 from "react";
4804
- import { jsx as jsx62, jsxs as jsxs56 } from "react/jsx-runtime";
4805
- var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
4806
- var DOW = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
4807
- var iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
4808
- var parse = (s) => {
4809
- if (!s) return null;
4810
- const [y, m, d] = s.split("-").map(Number);
4811
- return new Date(y, m - 1, d);
4812
- };
4813
- var fmt = (s) => {
4814
- const d = parse(s);
4815
- return d ? MONTHS[d.getMonth()].slice(0, 3) + " " + d.getDate() + ", " + d.getFullYear() : "";
4816
- };
4817
- function Calendar({ value, range = false, onPick, initialMonth, months = 1 }) {
4818
- const today = /* @__PURE__ */ new Date();
4819
- const sel = range ? value || {} : { start: value, end: value };
4820
- const anchor = parse(sel.start) || parse(initialMonth) || today;
4821
- const [vy, setVy] = React34.useState(anchor.getFullYear());
4822
- const [vm, setVm] = React34.useState(anchor.getMonth());
4823
- const [mode2, setMode] = React34.useState("days");
4824
- const [hover, setHover] = React34.useState(null);
4825
- const s = parse(sel.start), e = parse(sel.end);
4826
- const hoverEnd = range && s && !e && hover ? parse(hover) : null;
4827
- const inRange = (d) => {
4828
- const lo = s, hi = e || hoverEnd;
4829
- return lo && hi && d > (lo < hi ? lo : hi) && d < (lo < hi ? hi : lo);
4830
- };
4831
- const isEdge = (d) => s && iso(d) === iso(s) || e && iso(d) === iso(e);
4832
- const clickDay = (d) => {
4833
- const v = iso(d);
4834
- if (!range) {
4835
- onPick(v);
4836
- return;
4837
- }
4838
- if (!sel.start || sel.start && sel.end) onPick({ start: v, end: "" });
4839
- else {
4840
- const a = parse(sel.start);
4841
- onPick(d < a ? { start: v, end: sel.start } : { start: sel.start, end: v });
4842
- }
4843
- };
4844
- const nav = (d) => {
4845
- let m = vm + d, y = vy;
4846
- if (m < 0) {
4847
- m = 11;
4848
- y--;
4849
- }
4850
- if (m > 11) {
4851
- m = 0;
4852
- y++;
4853
- }
4854
- setVm(m);
4855
- setVy(y);
4856
- };
4857
- const monthGrid = (y, m) => {
4858
- const startPad = new Date(y, m, 1).getDay();
4859
- const cells = [];
4860
- for (let i = 0; i < 42; i++) cells.push(new Date(y, m, i - startPad + 1));
4861
- return /* @__PURE__ */ jsxs56("div", { className: "fd-cal-grid", style: { width: months > 1 ? 252 : "auto", flex: "none" }, onMouseLeave: () => setHover(null), children: [
4862
- DOW.map((d) => /* @__PURE__ */ jsx62("span", { className: "fd-cal-dow", children: d }, d)),
4863
- cells.map((d, i) => /* @__PURE__ */ jsx62(
4864
- "button",
4865
- {
4866
- type: "button",
4867
- className: ["fd-cal-day", d.getMonth() !== m ? "is-out" : "", iso(d) === iso(today) ? "is-today" : "", inRange(d) ? "in-range" : "", isEdge(d) ? "is-edge" : ""].filter(Boolean).join(" "),
4868
- onClick: () => clickDay(d),
4869
- onMouseEnter: () => range && setHover(iso(d)),
4870
- children: d.getDate()
4871
- },
4872
- i
4873
- ))
4874
- ] });
4875
- };
4876
- const nextY = vm === 11 ? vy + 1 : vy, nextM = (vm + 1) % 12;
4877
- return /* @__PURE__ */ jsxs56("div", { className: "fd-cal", style: { width: months > 1 && mode2 === "days" ? "auto" : void 0 }, children: [
4878
- /* @__PURE__ */ jsxs56("div", { className: "fd-cal-head", children: [
4879
- /* @__PURE__ */ jsx62("button", { type: "button", className: "fd-btn-icon", "aria-label": "Previous", onClick: () => mode2 === "years" ? setVy(vy - 12) : mode2 === "months" ? setVy(vy - 1) : nav(-1), children: /* @__PURE__ */ jsx62("i", { className: "ph ph-caret-left" }) }),
4880
- /* @__PURE__ */ jsxs56("button", { type: "button", className: "fd-cal-title", onClick: () => setMode(mode2 === "days" ? "months" : mode2 === "months" ? "years" : "days"), children: [
4881
- mode2 === "days" ? MONTHS[vm] + " " + vy : mode2 === "months" ? vy : vy - 5 + " \u2013 " + (vy + 6),
4882
- /* @__PURE__ */ jsx62("i", { className: "ph ph-caret-down", style: { fontSize: 10, marginLeft: 6, color: "var(--text-muted)" } })
4883
- ] }),
4884
- months > 1 && mode2 === "days" ? /* @__PURE__ */ jsx62("span", { className: "fd-cal-title", style: { cursor: "default", background: "none" }, children: MONTHS[nextM] + " " + nextY }) : null,
4885
- /* @__PURE__ */ jsx62("button", { type: "button", className: "fd-btn-icon", "aria-label": "Next", onClick: () => mode2 === "years" ? setVy(vy + 12) : mode2 === "months" ? setVy(vy + 1) : nav(1), children: /* @__PURE__ */ jsx62("i", { className: "ph ph-caret-right" }) })
4886
- ] }),
4887
- mode2 === "days" ? /* @__PURE__ */ jsxs56("div", { style: { display: "flex", gap: 18 }, children: [
4888
- monthGrid(vy, vm),
4889
- months > 1 ? monthGrid(nextY, nextM) : null
4890
- ] }) : mode2 === "months" ? /* @__PURE__ */ jsx62("div", { className: "fd-cal-grid-months", children: MONTHS.map((m, i) => /* @__PURE__ */ jsx62(
4891
- "button",
4892
- {
4893
- type: "button",
4894
- className: "fd-cal-cell" + (i === vm && s && s.getFullYear() === vy ? " is-sel" : ""),
4895
- onClick: () => {
4896
- setVm(i);
4897
- setMode("days");
4898
- },
4899
- children: m.slice(0, 3)
4900
- },
4901
- m
4902
- )) }) : /* @__PURE__ */ jsx62("div", { className: "fd-cal-grid-months", children: Array.from({ length: 12 }, (_, i) => vy - 5 + i).map((y) => /* @__PURE__ */ jsx62(
4903
- "button",
4904
- {
4905
- type: "button",
4906
- className: "fd-cal-cell" + (y === vy ? " is-sel" : ""),
4907
- onClick: () => {
4908
- setVy(y);
4909
- setMode("months");
4910
- },
4911
- children: y
4912
- },
4913
- y
4914
- )) }),
4915
- /* @__PURE__ */ jsxs56("div", { className: "fd-cal-foot", children: [
4916
- /* @__PURE__ */ jsx62(
4917
- "button",
4918
- {
4919
- type: "button",
4920
- className: "fd-btn fd-btn-link",
4921
- style: { fontSize: 12.5 },
4922
- onClick: () => {
4923
- setVy(today.getFullYear());
4924
- setVm(today.getMonth());
4925
- setMode("days");
4926
- },
4927
- children: "Today"
4928
- }
4929
- ),
4930
- /* @__PURE__ */ jsx62("span", { style: { flex: 1 } }),
4931
- range && sel.start ? /* @__PURE__ */ jsxs56("span", { className: "fd-body-sm fd-muted", children: [
4932
- fmt(sel.start),
4933
- sel.end ? " \u2192 " + fmt(sel.end) : " \u2192 pick an end"
4934
- ] }) : null
4935
- ] })
4936
- ] });
4937
- }
4938
- function DatePicker({ label, help, error, required = false, disabled = false, range = false, value, onChange, placeholder, id, className = "", style, ...rest }) {
4939
- const { fieldId, labelId, ariaLabelledBy } = useTriggerLabelling(label, id);
4940
- const [open, setOpen] = React34.useState(false);
4941
- const rootRef = React34.useRef(null);
4942
- const boxRef = React34.useRef(null);
4943
- const display = range ? value && value.start ? fmt(value.start) + (value.end ? " \u2192 " + fmt(value.end) : " \u2192 \u2026") : "" : fmt(value);
4944
- const toggle = () => {
4945
- if (!disabled) setOpen(!open);
4946
- };
4947
- return /* @__PURE__ */ jsxs56("div", { className: ["fd-field", "fd-popfield", open ? "is-open" : "", className].filter(Boolean).join(" "), style, ref: rootRef, children: [
4948
- label ? /* @__PURE__ */ jsx62(FieldLabel, { id: labelId, required, onClick: toggle, children: label }) : null,
4949
- /* @__PURE__ */ jsxs56("div", { className: ["fd-input", error ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" "), style: { cursor: disabled ? "not-allowed" : "pointer" }, onClick: toggle, ref: boxRef, children: [
4950
- /* @__PURE__ */ jsx62("span", { className: "fd-input-icon", children: /* @__PURE__ */ jsx62("i", { className: "ph ph-calendar-blank", "aria-hidden": "true" }) }),
4951
- /* @__PURE__ */ jsx62(
4952
- "button",
4953
- {
4954
- type: "button",
4955
- id: fieldId,
4956
- "aria-labelledby": ariaLabelledBy,
4957
- title: truncationTitle(display),
4958
- disabled,
4959
- onKeyDown: (e) => {
4960
- if (e.key === "Enter" || e.key === " ") {
4961
- e.preventDefault();
4962
- toggle();
4963
- }
4964
- },
4965
- style: { all: "unset", flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", cursor: "inherit", color: display ? "var(--text)" : "var(--text-muted)" },
4966
- ...rest,
4967
- children: display || placeholder || (range ? "Pick a date range" : "Pick a date")
4968
- }
4969
- ),
4970
- /* @__PURE__ */ jsx62("span", { className: "fd-select-caret", children: /* @__PURE__ */ jsx62("i", { className: "ph ph-caret-down", "aria-hidden": "true" }) })
4971
- ] }),
4972
- /* @__PURE__ */ jsx62(
4973
- Popover,
4974
- {
4975
- open,
4976
- anchorRef: boxRef,
4977
- triggerRef: rootRef,
4978
- onClose: () => setOpen(false),
4979
- placement: "bottom-start",
4980
- offset: 6,
4981
- role: "presentation",
4982
- style: { width: "max-content" },
4983
- children: /* @__PURE__ */ jsx62(
4984
- Calendar,
4985
- {
4986
- range,
4987
- months: range ? 2 : 1,
4988
- value,
4989
- onPick: (v) => {
4990
- onChange && onChange({ target: { value: v } });
4991
- if (!range || v.start && v.end) setOpen(false);
4992
- }
4993
- }
4994
- )
4995
- }
4996
- ),
4997
5429
  error ? /* @__PURE__ */ jsxs56("span", { className: "fd-field-error", children: [
4998
5430
  /* @__PURE__ */ jsx62("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
4999
5431
  error