@flytedan/flytebot-design-system 0.30.0 → 0.32.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/README.md +4 -4
- package/dist/index.cjs +332 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -8
- package/dist/index.d.ts +68 -8
- package/dist/index.js +331 -133
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/styles/components.css +8 -0
package/dist/index.js
CHANGED
|
@@ -2757,6 +2757,48 @@ function useTriggerLabelling(label, id) {
|
|
|
2757
2757
|
|
|
2758
2758
|
// src/components/forms/NumberInput.tsx
|
|
2759
2759
|
import { jsx as jsx42, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
2760
|
+
var HOLD_DELAY_MS = 400;
|
|
2761
|
+
var HOLD_BIG_AFTER = 6;
|
|
2762
|
+
var HOLD_FAST_AFTER = 12;
|
|
2763
|
+
var holdInterval = (repeats) => repeats > HOLD_FAST_AFTER ? 40 : repeats > HOLD_BIG_AFTER ? 70 : 120;
|
|
2764
|
+
function decimalPlaces(n) {
|
|
2765
|
+
if (!Number.isFinite(n)) return 0;
|
|
2766
|
+
const [mantissa, exp] = String(n).toLowerCase().split("e");
|
|
2767
|
+
const frac = (mantissa.split(".")[1] || "").length;
|
|
2768
|
+
return Math.max(0, frac - (exp ? Number(exp) : 0));
|
|
2769
|
+
}
|
|
2770
|
+
function parseNumberText(text) {
|
|
2771
|
+
const s = text.replace(/,/g, "").trim();
|
|
2772
|
+
if (s === "") return null;
|
|
2773
|
+
if (!/^-?(\d+\.?\d*|\.\d+)$/.test(s)) return NaN;
|
|
2774
|
+
return Number(s);
|
|
2775
|
+
}
|
|
2776
|
+
function allowedRange(min, max, integer) {
|
|
2777
|
+
return integer ? { lo: Math.ceil(min), hi: Math.floor(max) } : { lo: min, hi: max };
|
|
2778
|
+
}
|
|
2779
|
+
function stepNumber({ from, direction, amount, step, min, max, integer }) {
|
|
2780
|
+
const { lo, hi } = allowedRange(min, max, integer);
|
|
2781
|
+
if (lo > hi) return null;
|
|
2782
|
+
const base = from ?? 0;
|
|
2783
|
+
const anchor = Number.isFinite(lo) ? lo : 0;
|
|
2784
|
+
const unit = step > 0 ? step : 1;
|
|
2785
|
+
const travel = amount > 0 ? amount : unit;
|
|
2786
|
+
const magnitude = Math.max(Math.abs(base), Math.abs(anchor), travel, unit, 1);
|
|
2787
|
+
const maxPlaces = Math.max(0, Math.floor(Math.log10(Number.MAX_SAFE_INTEGER / (4 * magnitude))));
|
|
2788
|
+
const places = Math.min(maxPlaces, Math.max(decimalPlaces(base), decimalPlaces(anchor), decimalPlaces(travel), decimalPlaces(unit)));
|
|
2789
|
+
const scale = 10 ** places;
|
|
2790
|
+
const b = Math.round(base * scale);
|
|
2791
|
+
const a = Math.round(anchor * scale);
|
|
2792
|
+
const s = Math.round(unit * scale);
|
|
2793
|
+
const t = Math.round(travel * scale);
|
|
2794
|
+
const target = b + direction * t;
|
|
2795
|
+
let k = direction > 0 ? Math.floor((target - a) / s) : Math.ceil((target - a) / s);
|
|
2796
|
+
if (direction > 0 && a + k * s <= b) k = Math.floor((b - a) / s) + 1;
|
|
2797
|
+
if (direction < 0 && a + k * s >= b) k = Math.ceil((b - a) / s) - 1;
|
|
2798
|
+
let next = (a + k * s) / scale;
|
|
2799
|
+
if (integer && !Number.isInteger(next)) next = direction > 0 ? Math.ceil(next) : Math.floor(next);
|
|
2800
|
+
return Math.min(hi, Math.max(lo, next));
|
|
2801
|
+
}
|
|
2760
2802
|
function NumberInput({
|
|
2761
2803
|
label,
|
|
2762
2804
|
help,
|
|
@@ -2769,8 +2811,10 @@ function NumberInput({
|
|
|
2769
2811
|
max = Infinity,
|
|
2770
2812
|
step = 1,
|
|
2771
2813
|
bigStep,
|
|
2814
|
+
integer = false,
|
|
2772
2815
|
value,
|
|
2773
2816
|
onChange,
|
|
2817
|
+
onValidityChange,
|
|
2774
2818
|
format = true,
|
|
2775
2819
|
className = "",
|
|
2776
2820
|
style,
|
|
@@ -2780,65 +2824,78 @@ function NumberInput({
|
|
|
2780
2824
|
}) {
|
|
2781
2825
|
const fieldId = useFieldId(id);
|
|
2782
2826
|
const errorId = fieldId + "-error";
|
|
2783
|
-
const
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
const validationMessage = (n) => {
|
|
2791
|
-
if (requiresInteger && !Number.isInteger(n)) return "Enter a whole number";
|
|
2792
|
-
if (n < min) return "Must be \u2265 " + min;
|
|
2793
|
-
if (n > max) return "Must be \u2264 " + max;
|
|
2794
|
-
return null;
|
|
2827
|
+
const { lo, hi } = allowedRange(min, max, integer);
|
|
2828
|
+
const big = bigStep ?? Number((step * 10).toFixed(decimalPlaces(step)));
|
|
2829
|
+
const toText = (v) => v == null || v === "" ? "" : String(v);
|
|
2830
|
+
const toNumber = (v) => {
|
|
2831
|
+
if (v == null || v === "") return null;
|
|
2832
|
+
const n = typeof v === "number" ? v : parseNumberText(v);
|
|
2833
|
+
return n == null || Number.isNaN(n) ? null : n;
|
|
2795
2834
|
};
|
|
2796
|
-
const [text, setText] = React21.useState(
|
|
2835
|
+
const [text, setText] = React21.useState(() => toText(value));
|
|
2797
2836
|
const [editing, setEditing] = React21.useState(false);
|
|
2798
|
-
const
|
|
2799
|
-
const
|
|
2837
|
+
const parsed = parseNumberText(text);
|
|
2838
|
+
const invalidMessage = parsed == null ? null : Number.isNaN(parsed) ? "Enter a number" : integer && !Number.isInteger(parsed) ? "Enter a whole number" : parsed < lo ? "Must be \u2265 " + lo : parsed > hi ? "Must be \u2264 " + hi : null;
|
|
2839
|
+
const valid = invalidMessage == null;
|
|
2840
|
+
const committedRef = React21.useRef(toNumber(value));
|
|
2841
|
+
const onChangeRef = React21.useRef(onChange);
|
|
2842
|
+
onChangeRef.current = onChange;
|
|
2843
|
+
const onValidityChangeRef = React21.useRef(onValidityChange);
|
|
2844
|
+
onValidityChangeRef.current = onValidityChange;
|
|
2845
|
+
const focusedRef = React21.useRef(false);
|
|
2800
2846
|
React21.useEffect(() => {
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
const fire = (n) =>
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2847
|
+
committedRef.current = toNumber(value);
|
|
2848
|
+
if (!focusedRef.current) setText(toText(value));
|
|
2849
|
+
}, [value]);
|
|
2850
|
+
React21.useLayoutEffect(() => {
|
|
2851
|
+
onValidityChangeRef.current?.(valid);
|
|
2852
|
+
}, [valid]);
|
|
2853
|
+
const fire = (n) => {
|
|
2854
|
+
committedRef.current = n ?? null;
|
|
2855
|
+
onChangeRef.current?.({ target: { value: n } });
|
|
2856
|
+
};
|
|
2857
|
+
const bump = (direction, amount) => {
|
|
2858
|
+
const next = stepNumber({ from: committedRef.current, direction, amount, step, min, max, integer });
|
|
2859
|
+
if (next == null) return false;
|
|
2812
2860
|
setText(String(next));
|
|
2861
|
+
if (next === committedRef.current) return false;
|
|
2813
2862
|
fire(next);
|
|
2863
|
+
return true;
|
|
2814
2864
|
};
|
|
2815
|
-
const
|
|
2816
|
-
|
|
2817
|
-
|
|
2865
|
+
const bumpRef = React21.useRef(bump);
|
|
2866
|
+
bumpRef.current = bump;
|
|
2867
|
+
const holdTimer = React21.useRef(null);
|
|
2868
|
+
const release = () => {
|
|
2869
|
+
if (holdTimer.current) clearTimeout(holdTimer.current);
|
|
2870
|
+
holdTimer.current = null;
|
|
2871
|
+
};
|
|
2872
|
+
const hold = (direction) => {
|
|
2873
|
+
release();
|
|
2874
|
+
bump(direction, step);
|
|
2875
|
+
let repeats = 0;
|
|
2818
2876
|
const tick = () => {
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2877
|
+
repeats++;
|
|
2878
|
+
if (!bumpRef.current(direction, repeats > HOLD_BIG_AFTER ? big : step)) {
|
|
2879
|
+
release();
|
|
2880
|
+
return;
|
|
2881
|
+
}
|
|
2882
|
+
holdTimer.current = setTimeout(tick, holdInterval(repeats));
|
|
2822
2883
|
};
|
|
2823
|
-
|
|
2824
|
-
};
|
|
2825
|
-
const release = () => {
|
|
2826
|
-
if (timer.current) clearTimeout(timer.current);
|
|
2884
|
+
holdTimer.current = setTimeout(tick, HOLD_DELAY_MS);
|
|
2827
2885
|
};
|
|
2828
2886
|
React21.useEffect(() => () => {
|
|
2829
|
-
if (
|
|
2887
|
+
if (holdTimer.current) clearTimeout(holdTimer.current);
|
|
2830
2888
|
}, []);
|
|
2831
|
-
const
|
|
2832
|
-
|
|
2833
|
-
return n == null ? "" : format ? n.toLocaleString() : String(n);
|
|
2834
|
-
})();
|
|
2889
|
+
const current2 = committedRef.current;
|
|
2890
|
+
const shown = editing || !valid ? text : parsed == null ? "" : format ? parsed.toLocaleString() : String(parsed);
|
|
2835
2891
|
const shownError = error || invalidMessage || void 0;
|
|
2836
2892
|
const box = ["fd-input", "fd-input-num", shownError ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
2837
2893
|
const fieldName = label || ariaLabel;
|
|
2838
2894
|
const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
|
|
2895
|
+
const noRange = lo > hi;
|
|
2839
2896
|
return /* @__PURE__ */ jsxs36("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
2840
2897
|
label ? /* @__PURE__ */ jsx42(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
2841
|
-
/* @__PURE__ */ jsxs36("div", { className: box,
|
|
2898
|
+
/* @__PURE__ */ jsxs36("div", { className: box, children: [
|
|
2842
2899
|
prefix ? /* @__PURE__ */ jsx42("span", { className: "fd-input-affix", children: prefix }) : null,
|
|
2843
2900
|
/* @__PURE__ */ jsx42(
|
|
2844
2901
|
"input",
|
|
@@ -2851,52 +2908,54 @@ function NumberInput({
|
|
|
2851
2908
|
value: shown,
|
|
2852
2909
|
"aria-invalid": shownError ? "true" : void 0,
|
|
2853
2910
|
"aria-describedby": shownError ? errorId : void 0,
|
|
2854
|
-
onFocus: () =>
|
|
2911
|
+
onFocus: () => {
|
|
2912
|
+
focusedRef.current = true;
|
|
2913
|
+
setEditing(true);
|
|
2914
|
+
},
|
|
2855
2915
|
onBlur: () => {
|
|
2916
|
+
focusedRef.current = false;
|
|
2856
2917
|
setEditing(false);
|
|
2857
|
-
if (text.trim() === "") fire(void 0);
|
|
2918
|
+
if (text.trim() === "" && committedRef.current != null) fire(void 0);
|
|
2858
2919
|
},
|
|
2859
2920
|
onChange: (e) => {
|
|
2860
2921
|
const raw = e.target.value;
|
|
2861
2922
|
setText(raw);
|
|
2862
|
-
|
|
2863
|
-
setInvalidMessage(null);
|
|
2864
|
-
fire(void 0);
|
|
2865
|
-
return;
|
|
2866
|
-
}
|
|
2867
|
-
const n = num(raw);
|
|
2923
|
+
const n = parseNumberText(raw);
|
|
2868
2924
|
if (n == null) {
|
|
2869
|
-
|
|
2925
|
+
if (committedRef.current != null) fire(void 0);
|
|
2870
2926
|
return;
|
|
2871
2927
|
}
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
if (!message) fire(n);
|
|
2928
|
+
if (Number.isNaN(n) || integer && !Number.isInteger(n) || n < lo || n > hi) return;
|
|
2929
|
+
fire(n);
|
|
2875
2930
|
},
|
|
2876
2931
|
onKeyDown: (e) => {
|
|
2877
2932
|
if (e.key === "ArrowUp") {
|
|
2878
2933
|
e.preventDefault();
|
|
2879
|
-
bump(1, e.shiftKey ?
|
|
2934
|
+
bump(1, e.shiftKey ? big : step);
|
|
2880
2935
|
} else if (e.key === "ArrowDown") {
|
|
2881
2936
|
e.preventDefault();
|
|
2882
|
-
bump(-1, e.shiftKey ?
|
|
2937
|
+
bump(-1, e.shiftKey ? big : step);
|
|
2883
2938
|
}
|
|
2884
2939
|
}
|
|
2885
2940
|
}
|
|
2886
2941
|
),
|
|
2887
2942
|
suffix ? /* @__PURE__ */ jsx42("span", { className: "fd-input-affix", children: suffix }) : null,
|
|
2888
|
-
/* @__PURE__ */ jsxs36("span", { className: "fd-
|
|
2943
|
+
/* @__PURE__ */ jsxs36("span", { className: "fd-input-steppers", children: [
|
|
2889
2944
|
/* @__PURE__ */ jsx42(
|
|
2890
2945
|
"button",
|
|
2891
2946
|
{
|
|
2892
2947
|
type: "button",
|
|
2893
2948
|
className: "fd-stepbtn",
|
|
2894
2949
|
"aria-label": stepperName("Decrease"),
|
|
2895
|
-
disabled: disabled ||
|
|
2950
|
+
disabled: disabled || noRange || current2 != null && current2 <= lo,
|
|
2896
2951
|
onPointerDown: () => hold(-1),
|
|
2897
2952
|
onPointerUp: release,
|
|
2898
2953
|
onPointerLeave: release,
|
|
2899
|
-
|
|
2954
|
+
onPointerCancel: release,
|
|
2955
|
+
onClick: (e) => {
|
|
2956
|
+
if (e.detail === 0) bump(-1, step);
|
|
2957
|
+
},
|
|
2958
|
+
children: /* @__PURE__ */ jsx42("i", { className: "ph ph-minus", "aria-hidden": "true" })
|
|
2900
2959
|
}
|
|
2901
2960
|
),
|
|
2902
2961
|
/* @__PURE__ */ jsx42(
|
|
@@ -2905,11 +2964,15 @@ function NumberInput({
|
|
|
2905
2964
|
type: "button",
|
|
2906
2965
|
className: "fd-stepbtn",
|
|
2907
2966
|
"aria-label": stepperName("Increase"),
|
|
2908
|
-
disabled: disabled ||
|
|
2967
|
+
disabled: disabled || noRange || current2 != null && current2 >= hi,
|
|
2909
2968
|
onPointerDown: () => hold(1),
|
|
2910
2969
|
onPointerUp: release,
|
|
2911
2970
|
onPointerLeave: release,
|
|
2912
|
-
|
|
2971
|
+
onPointerCancel: release,
|
|
2972
|
+
onClick: (e) => {
|
|
2973
|
+
if (e.detail === 0) bump(1, step);
|
|
2974
|
+
},
|
|
2975
|
+
children: /* @__PURE__ */ jsx42("i", { className: "ph ph-plus", "aria-hidden": "true" })
|
|
2913
2976
|
}
|
|
2914
2977
|
)
|
|
2915
2978
|
] })
|
|
@@ -3194,6 +3257,97 @@ function isFieldSet(field, value) {
|
|
|
3194
3257
|
}
|
|
3195
3258
|
}
|
|
3196
3259
|
}
|
|
3260
|
+
var MAX_WITHIN_DAYS = 3650;
|
|
3261
|
+
function effectiveMaxDays(field) {
|
|
3262
|
+
return Math.min(field.maxDays ?? MAX_WITHIN_DAYS, MAX_WITHIN_DAYS);
|
|
3263
|
+
}
|
|
3264
|
+
function isIsoDate(v) {
|
|
3265
|
+
if (typeof v !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(v)) return false;
|
|
3266
|
+
const d = /* @__PURE__ */ new Date(v + "T00:00:00Z");
|
|
3267
|
+
return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === v;
|
|
3268
|
+
}
|
|
3269
|
+
var isOption = (o) => !!o && typeof o.value === "string" && typeof o.label === "string";
|
|
3270
|
+
function validateFilterValue(field, value) {
|
|
3271
|
+
switch (field.type) {
|
|
3272
|
+
case "text":
|
|
3273
|
+
return typeof value === "string" ? { ok: true } : { ok: false, reason: "Enter text" };
|
|
3274
|
+
case "select":
|
|
3275
|
+
return field.options.some((o) => o.value === value) ? { ok: true } : { ok: false, reason: "Pick one of the options" };
|
|
3276
|
+
case "multiSelect": {
|
|
3277
|
+
const v = value;
|
|
3278
|
+
if (!v || !Array.isArray(v.values) || v.values.length === 0) {
|
|
3279
|
+
return { ok: false, reason: "Select at least one value" };
|
|
3280
|
+
}
|
|
3281
|
+
if (!v.values.every(isOption)) return { ok: false, reason: "Each value needs a value and a label" };
|
|
3282
|
+
if (field.maxValues != null && v.values.length > field.maxValues) {
|
|
3283
|
+
return { ok: false, reason: "Select at most " + field.maxValues + " values" };
|
|
3284
|
+
}
|
|
3285
|
+
if (!operatorsFor(field).includes(v.operator)) {
|
|
3286
|
+
return { ok: false, reason: "That operator isn't allowed for " + field.label };
|
|
3287
|
+
}
|
|
3288
|
+
return { ok: true };
|
|
3289
|
+
}
|
|
3290
|
+
case "range": {
|
|
3291
|
+
const v = value;
|
|
3292
|
+
if (!v || v.min == null && v.max == null) {
|
|
3293
|
+
return { ok: false, reason: "Enter at least one bound" };
|
|
3294
|
+
}
|
|
3295
|
+
const lo = field.min ?? -Infinity;
|
|
3296
|
+
const hi = field.max ?? Infinity;
|
|
3297
|
+
for (const n of [v.min, v.max]) {
|
|
3298
|
+
if (n == null) continue;
|
|
3299
|
+
if (typeof n !== "number" || !Number.isFinite(n)) return { ok: false, reason: "Enter a number" };
|
|
3300
|
+
if (field.integer && !Number.isInteger(n)) return { ok: false, reason: "Enter a whole number" };
|
|
3301
|
+
if (n < lo) return { ok: false, reason: "Must be \u2265 " + lo };
|
|
3302
|
+
if (n > hi) return { ok: false, reason: "Must be \u2264 " + hi };
|
|
3303
|
+
}
|
|
3304
|
+
if (v.min != null && v.max != null && v.min > v.max) {
|
|
3305
|
+
return { ok: false, reason: "Must be \u2265 " + v.min };
|
|
3306
|
+
}
|
|
3307
|
+
return { ok: true };
|
|
3308
|
+
}
|
|
3309
|
+
case "date": {
|
|
3310
|
+
const v = value;
|
|
3311
|
+
if (!v) return { ok: false, reason: "Pick a date value" };
|
|
3312
|
+
if (v.kind === "withinDays") {
|
|
3313
|
+
const maxDays = effectiveMaxDays(field);
|
|
3314
|
+
if (v.days == null) return { ok: false, reason: "Enter a number of days" };
|
|
3315
|
+
if (!Number.isInteger(v.days)) return { ok: false, reason: "Enter a whole number" };
|
|
3316
|
+
if (v.days < 1) return { ok: false, reason: "Must be \u2265 1" };
|
|
3317
|
+
if (v.days > maxDays) return { ok: false, reason: "Must be \u2264 " + maxDays };
|
|
3318
|
+
return { ok: true };
|
|
3319
|
+
}
|
|
3320
|
+
if (v.kind !== "between") return { ok: false, reason: "Pick a date value" };
|
|
3321
|
+
if (!v.from || !v.to) return { ok: false, reason: "Pick both dates" };
|
|
3322
|
+
if (!isIsoDate(v.from) || !isIsoDate(v.to)) return { ok: false, reason: "Dates must be YYYY-MM-DD" };
|
|
3323
|
+
if (v.from > v.to) return { ok: false, reason: "The start date must be on or before the end date" };
|
|
3324
|
+
return { ok: true };
|
|
3325
|
+
}
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
function isEmptyCandidate(field, candidate) {
|
|
3329
|
+
return field.type !== "text" && field.type !== "select" && !isFieldSet(field, candidate);
|
|
3330
|
+
}
|
|
3331
|
+
function assertValidFieldDefinition(field) {
|
|
3332
|
+
if (field.type === "multiSelect" && field.maxValues != null && (!Number.isInteger(field.maxValues) || field.maxValues < 1)) {
|
|
3333
|
+
throw new Error(
|
|
3334
|
+
'FilterBar: multiSelect field "' + field.key + '" has an invalid maxValues (' + field.maxValues + ") \u2014 must be a whole number of at least 1."
|
|
3335
|
+
);
|
|
3336
|
+
}
|
|
3337
|
+
if (field.type !== "date") return;
|
|
3338
|
+
const defaultDays = field.defaultDays ?? 30;
|
|
3339
|
+
const maxDays = field.maxDays ?? MAX_WITHIN_DAYS;
|
|
3340
|
+
if (!Number.isInteger(maxDays) || maxDays < 1 || maxDays > MAX_WITHIN_DAYS) {
|
|
3341
|
+
throw new Error(
|
|
3342
|
+
'FilterBar: date field "' + field.key + '" has an invalid maxDays (' + field.maxDays + ") \u2014 must be a whole number from 1 to " + MAX_WITHIN_DAYS + "."
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
if (!Number.isInteger(defaultDays) || defaultDays < 1 || defaultDays > maxDays) {
|
|
3346
|
+
throw new Error(
|
|
3347
|
+
'FilterBar: date field "' + field.key + '" has an invalid defaultDays (' + field.defaultDays + ") \u2014 must be a whole number from 1 to maxDays (" + maxDays + ")."
|
|
3348
|
+
);
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3197
3351
|
function chipLabel(field, value) {
|
|
3198
3352
|
switch (field.type) {
|
|
3199
3353
|
case "text":
|
|
@@ -3246,8 +3400,7 @@ function MultiSelectPanel({
|
|
|
3246
3400
|
field,
|
|
3247
3401
|
value,
|
|
3248
3402
|
anchorRef,
|
|
3249
|
-
|
|
3250
|
-
onRemove,
|
|
3403
|
+
onCommit,
|
|
3251
3404
|
onClose
|
|
3252
3405
|
}) {
|
|
3253
3406
|
const allowedOps = operatorsFor(field);
|
|
@@ -3256,13 +3409,21 @@ function MultiSelectPanel({
|
|
|
3256
3409
|
const selected = value?.values ?? [];
|
|
3257
3410
|
const selectedRef = React24.useRef(selected);
|
|
3258
3411
|
selectedRef.current = selected;
|
|
3412
|
+
const operatorRef = React24.useRef(operator);
|
|
3413
|
+
operatorRef.current = operator;
|
|
3414
|
+
const mountedRef = React24.useRef(true);
|
|
3415
|
+
React24.useEffect(() => {
|
|
3416
|
+
mountedRef.current = true;
|
|
3417
|
+
return () => {
|
|
3418
|
+
mountedRef.current = false;
|
|
3419
|
+
};
|
|
3420
|
+
}, []);
|
|
3259
3421
|
const commit = (nextValues, nextOperator = operator) => {
|
|
3260
|
-
|
|
3261
|
-
else onChange({ operator: nextOperator, values: nextValues });
|
|
3422
|
+
onCommit({ operator: nextOperator, values: nextValues });
|
|
3262
3423
|
};
|
|
3263
3424
|
const setOperator = (op) => {
|
|
3264
3425
|
setDraftOperator(op);
|
|
3265
|
-
if (
|
|
3426
|
+
if (selectedRef.current.length > 0) commit(selectedRef.current, op);
|
|
3266
3427
|
};
|
|
3267
3428
|
const [mode2, setMode] = React24.useState("search");
|
|
3268
3429
|
const [query, setQuery] = React24.useState("");
|
|
@@ -3302,9 +3463,12 @@ function MultiSelectPanel({
|
|
|
3302
3463
|
const showError = !!field.loadOptions && asyncState.error;
|
|
3303
3464
|
const hasListbox = !showLoading && !showError && options.length > 0;
|
|
3304
3465
|
const isSelected = (o) => selected.some((s) => s.value === o.value);
|
|
3466
|
+
const atLimit = field.maxValues != null && selected.length >= field.maxValues;
|
|
3305
3467
|
const toggle = (o) => {
|
|
3306
|
-
const
|
|
3307
|
-
|
|
3468
|
+
const current2 = selectedRef.current;
|
|
3469
|
+
const on = current2.some((s) => s.value === o.value);
|
|
3470
|
+
if (!on && field.maxValues != null && current2.length >= field.maxValues) return;
|
|
3471
|
+
commit(on ? current2.filter((s) => s.value !== o.value) : [...current2, o]);
|
|
3308
3472
|
};
|
|
3309
3473
|
const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
|
|
3310
3474
|
useListboxScrollIntoView(nav.active, listRef, hasListbox);
|
|
@@ -3312,8 +3476,7 @@ function MultiSelectPanel({
|
|
|
3312
3476
|
nav.setActive(0);
|
|
3313
3477
|
}, [query, options.length]);
|
|
3314
3478
|
const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
|
|
3315
|
-
const
|
|
3316
|
-
const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : "";
|
|
3479
|
+
const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
|
|
3317
3480
|
const [pasteText, setPasteText] = React24.useState("");
|
|
3318
3481
|
const [pasteLoading, setPasteLoading] = React24.useState(false);
|
|
3319
3482
|
const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
|
|
@@ -3329,13 +3492,19 @@ function MultiSelectPanel({
|
|
|
3329
3492
|
setPasteLoading(true);
|
|
3330
3493
|
setPasteError(null);
|
|
3331
3494
|
field.resolve(tokens).then((result) => {
|
|
3495
|
+
if (!mountedRef.current) return;
|
|
3332
3496
|
setPasteLoading(false);
|
|
3333
3497
|
setUnmatchedTokens(result.unmatched);
|
|
3334
3498
|
const merged = new Map(selectedRef.current.map((s) => [s.value, s]));
|
|
3335
3499
|
for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
|
|
3336
|
-
|
|
3500
|
+
if (field.maxValues != null && merged.size > field.maxValues) {
|
|
3501
|
+
setPasteError("This filter allows at most " + field.maxValues + " values; adding this list would make " + merged.size + ".");
|
|
3502
|
+
return;
|
|
3503
|
+
}
|
|
3504
|
+
commit(Array.from(merged.values()), operatorRef.current);
|
|
3337
3505
|
setPasteText("");
|
|
3338
|
-
}
|
|
3506
|
+
}, (err) => {
|
|
3507
|
+
if (!mountedRef.current) return;
|
|
3339
3508
|
setPasteLoading(false);
|
|
3340
3509
|
setPasteError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
|
|
3341
3510
|
});
|
|
@@ -3413,14 +3582,14 @@ function MultiSelectPanel({
|
|
|
3413
3582
|
selected.length,
|
|
3414
3583
|
" matched"
|
|
3415
3584
|
] }),
|
|
3416
|
-
/* @__PURE__ */ jsx45("span", { className: "fd-row fd-wrap fd-gap-xs", children: selected.map((v) => /* @__PURE__ */ jsx45(Tag, { onRemove: () => commit(
|
|
3585
|
+
/* @__PURE__ */ jsx45("span", { className: "fd-row fd-wrap fd-gap-xs", children: selected.map((v) => /* @__PURE__ */ jsx45(Tag, { onRemove: () => commit(selectedRef.current.filter((s) => s.value !== v.value)), children: v.label }, v.value)) })
|
|
3417
3586
|
] }) : null
|
|
3418
3587
|
] }) : /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3419
3588
|
/* @__PURE__ */ jsxs39(
|
|
3420
3589
|
"span",
|
|
3421
3590
|
{
|
|
3422
3591
|
className: "fd-row fd-gap-xs" + (liveMessage && !showError ? " fd-muted" : ""),
|
|
3423
|
-
role:
|
|
3592
|
+
role: "status",
|
|
3424
3593
|
children: [
|
|
3425
3594
|
showLoading ? /* @__PURE__ */ jsx45("span", { className: "fd-spinner", "aria-hidden": "true" }) : null,
|
|
3426
3595
|
liveMessage ? /* @__PURE__ */ jsx45("span", { className: "fd-body-sm", children: liveMessage }) : null
|
|
@@ -3430,6 +3599,7 @@ function MultiSelectPanel({
|
|
|
3430
3599
|
showError ? /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: () => setRetryTick((n) => n + 1), children: "Retry" }) : null,
|
|
3431
3600
|
hasListbox ? /* @__PURE__ */ jsx45("span", { id: listId, role: "listbox", "aria-label": field.label, "aria-multiselectable": "true", ref: listRef, className: "fd-pop-list", children: options.map((o, i) => {
|
|
3432
3601
|
const on = isSelected(o);
|
|
3602
|
+
const blocked = !on && atLimit;
|
|
3433
3603
|
return /* @__PURE__ */ jsxs39(
|
|
3434
3604
|
"div",
|
|
3435
3605
|
{
|
|
@@ -3438,6 +3608,7 @@ function MultiSelectPanel({
|
|
|
3438
3608
|
role: "option",
|
|
3439
3609
|
tabIndex: -1,
|
|
3440
3610
|
"aria-selected": on,
|
|
3611
|
+
"aria-disabled": blocked ? "true" : void 0,
|
|
3441
3612
|
className: ["fd-opt", i === nav.active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3442
3613
|
onMouseEnter: () => nav.setActive(i),
|
|
3443
3614
|
onClick: () => toggle(o),
|
|
@@ -3471,22 +3642,24 @@ function RangePanel({
|
|
|
3471
3642
|
field,
|
|
3472
3643
|
value,
|
|
3473
3644
|
anchorRef,
|
|
3474
|
-
|
|
3475
|
-
onRemove,
|
|
3645
|
+
onCommit,
|
|
3476
3646
|
onClose
|
|
3477
3647
|
}) {
|
|
3478
|
-
const [
|
|
3479
|
-
const
|
|
3480
|
-
const
|
|
3481
|
-
const
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3648
|
+
const [draft, setDraft] = React24.useState({ min: value?.min, max: value?.max });
|
|
3649
|
+
const draftRef = React24.useRef(draft);
|
|
3650
|
+
const [minTextValid, setMinTextValid] = React24.useState(true);
|
|
3651
|
+
const [maxTextValid, setMaxTextValid] = React24.useState(true);
|
|
3652
|
+
const draftMin = draft.min;
|
|
3653
|
+
const draftMax = draft.max;
|
|
3654
|
+
const isEmpty = draftMin == null && draftMax == null;
|
|
3655
|
+
const validation = isEmpty ? { ok: true } : validateFilterValue(field, { min: draftMin, max: draftMax });
|
|
3656
|
+
const comboError = !isEmpty && !validation.ok ? validation.reason : void 0;
|
|
3657
|
+
const doneDisabled = !minTextValid || !maxTextValid || !!comboError;
|
|
3658
|
+
const apply = (patch) => {
|
|
3659
|
+
const next = { ...draftRef.current, ...patch };
|
|
3660
|
+
draftRef.current = next;
|
|
3661
|
+
setDraft(next);
|
|
3662
|
+
onCommit(next.min == null && next.max == null ? void 0 : next);
|
|
3490
3663
|
};
|
|
3491
3664
|
return /* @__PURE__ */ jsx45(
|
|
3492
3665
|
Popover,
|
|
@@ -3498,7 +3671,7 @@ function RangePanel({
|
|
|
3498
3671
|
offset: 6,
|
|
3499
3672
|
width: PANEL_WIDTH.range,
|
|
3500
3673
|
label: field.label,
|
|
3501
|
-
footer: /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, disabled:
|
|
3674
|
+
footer: /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: onClose, disabled: doneDisabled, children: "Done" }),
|
|
3502
3675
|
children: /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3503
3676
|
/* @__PURE__ */ jsx45(
|
|
3504
3677
|
NumberInput,
|
|
@@ -3508,8 +3681,10 @@ function RangePanel({
|
|
|
3508
3681
|
min: field.min,
|
|
3509
3682
|
max: field.max,
|
|
3510
3683
|
step: field.step,
|
|
3684
|
+
integer: field.integer,
|
|
3511
3685
|
placeholder: field.minPlaceholder,
|
|
3512
|
-
onChange: (e) => apply(e.target.value
|
|
3686
|
+
onChange: (e) => apply({ min: e.target.value }),
|
|
3687
|
+
onValidityChange: setMinTextValid
|
|
3513
3688
|
}
|
|
3514
3689
|
),
|
|
3515
3690
|
/* @__PURE__ */ jsx45(
|
|
@@ -3520,9 +3695,11 @@ function RangePanel({
|
|
|
3520
3695
|
min: field.min,
|
|
3521
3696
|
max: field.max,
|
|
3522
3697
|
step: field.step,
|
|
3523
|
-
|
|
3698
|
+
integer: field.integer,
|
|
3699
|
+
error: comboError,
|
|
3524
3700
|
placeholder: field.maxPlaceholder,
|
|
3525
|
-
onChange: (e) => apply(
|
|
3701
|
+
onChange: (e) => apply({ max: e.target.value }),
|
|
3702
|
+
onValidityChange: setMaxTextValid
|
|
3526
3703
|
}
|
|
3527
3704
|
)
|
|
3528
3705
|
] })
|
|
@@ -3533,12 +3710,12 @@ function DatePanel({
|
|
|
3533
3710
|
field,
|
|
3534
3711
|
value,
|
|
3535
3712
|
anchorRef,
|
|
3536
|
-
|
|
3537
|
-
onRemove,
|
|
3713
|
+
onCommit,
|
|
3538
3714
|
onClose
|
|
3539
3715
|
}) {
|
|
3540
3716
|
const defaultDays = field.defaultDays ?? 30;
|
|
3541
|
-
const maxDays = field
|
|
3717
|
+
const maxDays = effectiveMaxDays(field);
|
|
3718
|
+
const [daysTextValid, setDaysTextValid] = React24.useState(true);
|
|
3542
3719
|
const [kind, setKind] = React24.useState(value?.kind ?? "withinDays");
|
|
3543
3720
|
const [daysDraft, setDaysDraft] = React24.useState(
|
|
3544
3721
|
value?.kind === "withinDays" ? value.days : defaultDays
|
|
@@ -3546,42 +3723,26 @@ function DatePanel({
|
|
|
3546
3723
|
const [between, setBetween] = React24.useState(
|
|
3547
3724
|
value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
|
|
3548
3725
|
);
|
|
3549
|
-
const committedRef = React24.useRef(!!value);
|
|
3550
3726
|
const applyWithinDays = (days) => {
|
|
3551
3727
|
setDaysDraft(days);
|
|
3552
|
-
|
|
3553
|
-
committedRef.current = true;
|
|
3554
|
-
onChange({ kind: "withinDays", days });
|
|
3555
|
-
} else if (committedRef.current) {
|
|
3556
|
-
committedRef.current = false;
|
|
3557
|
-
onRemove();
|
|
3558
|
-
}
|
|
3728
|
+
onCommit(days == null ? void 0 : { kind: "withinDays", days });
|
|
3559
3729
|
};
|
|
3560
3730
|
const applyBetween = (from, to) => {
|
|
3561
3731
|
setBetween({ from, to });
|
|
3562
|
-
|
|
3563
|
-
committedRef.current = true;
|
|
3564
|
-
onChange({ kind: "between", from, to });
|
|
3565
|
-
} else if (committedRef.current) {
|
|
3566
|
-
committedRef.current = false;
|
|
3567
|
-
onRemove();
|
|
3568
|
-
}
|
|
3732
|
+
onCommit(from && to ? { kind: "between", from, to } : void 0);
|
|
3569
3733
|
};
|
|
3570
3734
|
const switchKind = (next) => {
|
|
3735
|
+
if (next === kind) return;
|
|
3571
3736
|
setKind(next);
|
|
3572
|
-
if (next === "between") {
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
onRemove();
|
|
3577
|
-
}
|
|
3578
|
-
}
|
|
3737
|
+
if (next === "between") setBetween({ from: "", to: "" });
|
|
3738
|
+
else setDaysDraft(defaultDays);
|
|
3739
|
+
setDaysTextValid(true);
|
|
3740
|
+
onCommit(void 0);
|
|
3579
3741
|
};
|
|
3742
|
+
const doneDisabled = kind === "withinDays" && !daysTextValid;
|
|
3580
3743
|
const confirm = () => {
|
|
3581
|
-
if (
|
|
3582
|
-
|
|
3583
|
-
onChange({ kind: "withinDays", days: daysDraft });
|
|
3584
|
-
}
|
|
3744
|
+
if (doneDisabled) return;
|
|
3745
|
+
if (kind === "withinDays" && daysDraft != null) onCommit({ kind: "withinDays", days: daysDraft });
|
|
3585
3746
|
onClose();
|
|
3586
3747
|
};
|
|
3587
3748
|
return /* @__PURE__ */ jsx45(
|
|
@@ -3594,7 +3755,7 @@ function DatePanel({
|
|
|
3594
3755
|
offset: 6,
|
|
3595
3756
|
width: PANEL_WIDTH.date,
|
|
3596
3757
|
label: field.label,
|
|
3597
|
-
footer: /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: confirm, children: "Done" }),
|
|
3758
|
+
footer: /* @__PURE__ */ jsx45(Button, { size: "sm", variant: "secondary", onClick: confirm, disabled: doneDisabled, children: "Done" }),
|
|
3598
3759
|
children: /* @__PURE__ */ jsxs39("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3599
3760
|
/* @__PURE__ */ jsx45(
|
|
3600
3761
|
SegmentedControl,
|
|
@@ -3608,7 +3769,19 @@ function DatePanel({
|
|
|
3608
3769
|
onChange: (k) => switchKind(k)
|
|
3609
3770
|
}
|
|
3610
3771
|
),
|
|
3611
|
-
kind === "withinDays" ? /* @__PURE__ */ jsx45(
|
|
3772
|
+
kind === "withinDays" ? /* @__PURE__ */ jsx45(
|
|
3773
|
+
NumberInput,
|
|
3774
|
+
{
|
|
3775
|
+
label: "Days",
|
|
3776
|
+
min: 1,
|
|
3777
|
+
max: maxDays,
|
|
3778
|
+
step: 1,
|
|
3779
|
+
integer: true,
|
|
3780
|
+
value: daysDraft ?? "",
|
|
3781
|
+
onChange: (e) => applyWithinDays(e.target.value),
|
|
3782
|
+
onValidityChange: setDaysTextValid
|
|
3783
|
+
}
|
|
3784
|
+
) : /* @__PURE__ */ jsx45(
|
|
3612
3785
|
DatePicker,
|
|
3613
3786
|
{
|
|
3614
3787
|
range: true,
|
|
@@ -3627,6 +3800,33 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3627
3800
|
const addAnchorRef = React24.useRef(null);
|
|
3628
3801
|
const textInputRef = React24.useRef(null);
|
|
3629
3802
|
const optionsRef = React24.useRef(null);
|
|
3803
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3804
|
+
for (const f of fields) assertValidFieldDefinition(f);
|
|
3805
|
+
}
|
|
3806
|
+
const latest = React24.useRef({ fields, filters, onFilterChange, onFilterRemove });
|
|
3807
|
+
latest.current = { fields, filters, onFilterChange, onFilterRemove };
|
|
3808
|
+
const commit = (field, candidate) => {
|
|
3809
|
+
const current2 = latest.current.fields.find((f) => f.key === field.key);
|
|
3810
|
+
if (!current2) return { ok: false, reason: "This filter is no longer available" };
|
|
3811
|
+
if (isEmptyCandidate(current2, candidate)) {
|
|
3812
|
+
removeField(current2);
|
|
3813
|
+
return { ok: true };
|
|
3814
|
+
}
|
|
3815
|
+
const result = validateFilterValue(current2, candidate);
|
|
3816
|
+
if (result.ok) {
|
|
3817
|
+
latest.current.filters = { ...latest.current.filters, [current2.key]: candidate };
|
|
3818
|
+
latest.current.onFilterChange(current2.key, candidate);
|
|
3819
|
+
}
|
|
3820
|
+
return result;
|
|
3821
|
+
};
|
|
3822
|
+
const removeField = (field) => {
|
|
3823
|
+
const { filters: now, onFilterRemove: remove } = latest.current;
|
|
3824
|
+
if (!isFieldSet(field, now[field.key])) return;
|
|
3825
|
+
const next = { ...now };
|
|
3826
|
+
delete next[field.key];
|
|
3827
|
+
latest.current.filters = next;
|
|
3828
|
+
remove(field.key);
|
|
3829
|
+
};
|
|
3630
3830
|
const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
|
|
3631
3831
|
const startEditing = (key) => setPanel({ kind: "edit", key });
|
|
3632
3832
|
const closeEditing = () => setPanel(null);
|
|
@@ -3658,7 +3858,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3658
3858
|
value: value ?? "",
|
|
3659
3859
|
placeholder: field.placeholder || field.label,
|
|
3660
3860
|
"aria-label": field.label,
|
|
3661
|
-
onChange: (e) =>
|
|
3861
|
+
onChange: (e) => commit(field, e.target.value),
|
|
3662
3862
|
onKeyDown: (e) => {
|
|
3663
3863
|
if (e.key === "Enter") setPanel(null);
|
|
3664
3864
|
else if (e.key === "Escape") {
|
|
@@ -3677,7 +3877,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3677
3877
|
"aria-label": "Remove " + field.label,
|
|
3678
3878
|
onClick: (e) => {
|
|
3679
3879
|
e.stopPropagation();
|
|
3680
|
-
|
|
3880
|
+
removeField(field);
|
|
3681
3881
|
setPanel(null);
|
|
3682
3882
|
},
|
|
3683
3883
|
children: /* @__PURE__ */ jsx45("i", { className: "ph ph-x", "aria-hidden": "true" })
|
|
@@ -3690,7 +3890,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3690
3890
|
const chipRef = editing ? editAnchorRef : void 0;
|
|
3691
3891
|
const toggleOrClose = () => editing ? closeEditing() : startEditing(field.key);
|
|
3692
3892
|
const remove = () => {
|
|
3693
|
-
|
|
3893
|
+
removeField(field);
|
|
3694
3894
|
closeEditing();
|
|
3695
3895
|
};
|
|
3696
3896
|
const chipText = field.label + (set ? ": " + chipLabel(field, value) : "");
|
|
@@ -3720,7 +3920,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3720
3920
|
"aria-selected": on,
|
|
3721
3921
|
className: ["fd-opt", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3722
3922
|
onClick: () => {
|
|
3723
|
-
|
|
3923
|
+
commit(field, o.value);
|
|
3724
3924
|
setPanel(null);
|
|
3725
3925
|
},
|
|
3726
3926
|
children: /* @__PURE__ */ jsx45("span", { className: "fd-opt-label", children: o.label })
|
|
@@ -3741,8 +3941,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3741
3941
|
field,
|
|
3742
3942
|
value,
|
|
3743
3943
|
anchorRef: editAnchorRef,
|
|
3744
|
-
|
|
3745
|
-
onRemove: () => onFilterRemove(field.key),
|
|
3944
|
+
onCommit: (v) => commit(field, v),
|
|
3746
3945
|
onClose: closeEditing
|
|
3747
3946
|
}
|
|
3748
3947
|
) : null
|
|
@@ -3757,8 +3956,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3757
3956
|
field,
|
|
3758
3957
|
value,
|
|
3759
3958
|
anchorRef: editAnchorRef,
|
|
3760
|
-
|
|
3761
|
-
onRemove: () => onFilterRemove(field.key),
|
|
3959
|
+
onCommit: (v) => commit(field, v),
|
|
3762
3960
|
onClose: closeEditing
|
|
3763
3961
|
}
|
|
3764
3962
|
) : null
|
|
@@ -3773,8 +3971,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3773
3971
|
field,
|
|
3774
3972
|
value,
|
|
3775
3973
|
anchorRef: editAnchorRef,
|
|
3776
|
-
|
|
3777
|
-
onRemove: () => onFilterRemove(field.key),
|
|
3974
|
+
onCommit: (v) => commit(field, v),
|
|
3778
3975
|
onClose: closeEditing
|
|
3779
3976
|
}
|
|
3780
3977
|
) : null
|
|
@@ -13622,6 +13819,7 @@ export {
|
|
|
13622
13819
|
useServerTable,
|
|
13623
13820
|
useSessionContext,
|
|
13624
13821
|
useStagedFiles,
|
|
13822
|
+
validateFilterValue,
|
|
13625
13823
|
visibleMessages
|
|
13626
13824
|
};
|
|
13627
13825
|
//# sourceMappingURL=index.js.map
|