@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.cjs
CHANGED
|
@@ -233,6 +233,7 @@ __export(index_exports, {
|
|
|
233
233
|
useServerTable: () => useServerTable,
|
|
234
234
|
useSessionContext: () => useSessionContext,
|
|
235
235
|
useStagedFiles: () => useStagedFiles,
|
|
236
|
+
validateFilterValue: () => validateFilterValue,
|
|
236
237
|
visibleMessages: () => visibleMessages
|
|
237
238
|
});
|
|
238
239
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -2996,6 +2997,48 @@ function useTriggerLabelling(label, id) {
|
|
|
2996
2997
|
|
|
2997
2998
|
// src/components/forms/NumberInput.tsx
|
|
2998
2999
|
var import_jsx_runtime42 = require("react/jsx-runtime");
|
|
3000
|
+
var HOLD_DELAY_MS = 400;
|
|
3001
|
+
var HOLD_BIG_AFTER = 6;
|
|
3002
|
+
var HOLD_FAST_AFTER = 12;
|
|
3003
|
+
var holdInterval = (repeats) => repeats > HOLD_FAST_AFTER ? 40 : repeats > HOLD_BIG_AFTER ? 70 : 120;
|
|
3004
|
+
function decimalPlaces(n) {
|
|
3005
|
+
if (!Number.isFinite(n)) return 0;
|
|
3006
|
+
const [mantissa, exp] = String(n).toLowerCase().split("e");
|
|
3007
|
+
const frac = (mantissa.split(".")[1] || "").length;
|
|
3008
|
+
return Math.max(0, frac - (exp ? Number(exp) : 0));
|
|
3009
|
+
}
|
|
3010
|
+
function parseNumberText(text) {
|
|
3011
|
+
const s = text.replace(/,/g, "").trim();
|
|
3012
|
+
if (s === "") return null;
|
|
3013
|
+
if (!/^-?(\d+\.?\d*|\.\d+)$/.test(s)) return NaN;
|
|
3014
|
+
return Number(s);
|
|
3015
|
+
}
|
|
3016
|
+
function allowedRange(min, max, integer) {
|
|
3017
|
+
return integer ? { lo: Math.ceil(min), hi: Math.floor(max) } : { lo: min, hi: max };
|
|
3018
|
+
}
|
|
3019
|
+
function stepNumber({ from, direction, amount, step, min, max, integer }) {
|
|
3020
|
+
const { lo, hi } = allowedRange(min, max, integer);
|
|
3021
|
+
if (lo > hi) return null;
|
|
3022
|
+
const base = from ?? 0;
|
|
3023
|
+
const anchor = Number.isFinite(lo) ? lo : 0;
|
|
3024
|
+
const unit = step > 0 ? step : 1;
|
|
3025
|
+
const travel = amount > 0 ? amount : unit;
|
|
3026
|
+
const magnitude = Math.max(Math.abs(base), Math.abs(anchor), travel, unit, 1);
|
|
3027
|
+
const maxPlaces = Math.max(0, Math.floor(Math.log10(Number.MAX_SAFE_INTEGER / (4 * magnitude))));
|
|
3028
|
+
const places = Math.min(maxPlaces, Math.max(decimalPlaces(base), decimalPlaces(anchor), decimalPlaces(travel), decimalPlaces(unit)));
|
|
3029
|
+
const scale = 10 ** places;
|
|
3030
|
+
const b = Math.round(base * scale);
|
|
3031
|
+
const a = Math.round(anchor * scale);
|
|
3032
|
+
const s = Math.round(unit * scale);
|
|
3033
|
+
const t = Math.round(travel * scale);
|
|
3034
|
+
const target = b + direction * t;
|
|
3035
|
+
let k = direction > 0 ? Math.floor((target - a) / s) : Math.ceil((target - a) / s);
|
|
3036
|
+
if (direction > 0 && a + k * s <= b) k = Math.floor((b - a) / s) + 1;
|
|
3037
|
+
if (direction < 0 && a + k * s >= b) k = Math.ceil((b - a) / s) - 1;
|
|
3038
|
+
let next = (a + k * s) / scale;
|
|
3039
|
+
if (integer && !Number.isInteger(next)) next = direction > 0 ? Math.ceil(next) : Math.floor(next);
|
|
3040
|
+
return Math.min(hi, Math.max(lo, next));
|
|
3041
|
+
}
|
|
2999
3042
|
function NumberInput({
|
|
3000
3043
|
label,
|
|
3001
3044
|
help,
|
|
@@ -3008,8 +3051,10 @@ function NumberInput({
|
|
|
3008
3051
|
max = Infinity,
|
|
3009
3052
|
step = 1,
|
|
3010
3053
|
bigStep,
|
|
3054
|
+
integer = false,
|
|
3011
3055
|
value,
|
|
3012
3056
|
onChange,
|
|
3057
|
+
onValidityChange,
|
|
3013
3058
|
format = true,
|
|
3014
3059
|
className = "",
|
|
3015
3060
|
style,
|
|
@@ -3019,65 +3064,78 @@ function NumberInput({
|
|
|
3019
3064
|
}) {
|
|
3020
3065
|
const fieldId = useFieldId(id);
|
|
3021
3066
|
const errorId = fieldId + "-error";
|
|
3022
|
-
const
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
const validationMessage = (n) => {
|
|
3030
|
-
if (requiresInteger && !Number.isInteger(n)) return "Enter a whole number";
|
|
3031
|
-
if (n < min) return "Must be \u2265 " + min;
|
|
3032
|
-
if (n > max) return "Must be \u2264 " + max;
|
|
3033
|
-
return null;
|
|
3067
|
+
const { lo, hi } = allowedRange(min, max, integer);
|
|
3068
|
+
const big = bigStep ?? Number((step * 10).toFixed(decimalPlaces(step)));
|
|
3069
|
+
const toText = (v) => v == null || v === "" ? "" : String(v);
|
|
3070
|
+
const toNumber = (v) => {
|
|
3071
|
+
if (v == null || v === "") return null;
|
|
3072
|
+
const n = typeof v === "number" ? v : parseNumberText(v);
|
|
3073
|
+
return n == null || Number.isNaN(n) ? null : n;
|
|
3034
3074
|
};
|
|
3035
|
-
const [text, setText] = React21.useState(
|
|
3075
|
+
const [text, setText] = React21.useState(() => toText(value));
|
|
3036
3076
|
const [editing, setEditing] = React21.useState(false);
|
|
3037
|
-
const
|
|
3038
|
-
const
|
|
3077
|
+
const parsed = parseNumberText(text);
|
|
3078
|
+
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;
|
|
3079
|
+
const valid = invalidMessage == null;
|
|
3080
|
+
const committedRef = React21.useRef(toNumber(value));
|
|
3081
|
+
const onChangeRef = React21.useRef(onChange);
|
|
3082
|
+
onChangeRef.current = onChange;
|
|
3083
|
+
const onValidityChangeRef = React21.useRef(onValidityChange);
|
|
3084
|
+
onValidityChangeRef.current = onValidityChange;
|
|
3085
|
+
const focusedRef = React21.useRef(false);
|
|
3039
3086
|
React21.useEffect(() => {
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
const fire = (n) =>
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3087
|
+
committedRef.current = toNumber(value);
|
|
3088
|
+
if (!focusedRef.current) setText(toText(value));
|
|
3089
|
+
}, [value]);
|
|
3090
|
+
React21.useLayoutEffect(() => {
|
|
3091
|
+
onValidityChangeRef.current?.(valid);
|
|
3092
|
+
}, [valid]);
|
|
3093
|
+
const fire = (n) => {
|
|
3094
|
+
committedRef.current = n ?? null;
|
|
3095
|
+
onChangeRef.current?.({ target: { value: n } });
|
|
3096
|
+
};
|
|
3097
|
+
const bump = (direction, amount) => {
|
|
3098
|
+
const next = stepNumber({ from: committedRef.current, direction, amount, step, min, max, integer });
|
|
3099
|
+
if (next == null) return false;
|
|
3051
3100
|
setText(String(next));
|
|
3101
|
+
if (next === committedRef.current) return false;
|
|
3052
3102
|
fire(next);
|
|
3103
|
+
return true;
|
|
3053
3104
|
};
|
|
3054
|
-
const
|
|
3055
|
-
|
|
3056
|
-
|
|
3105
|
+
const bumpRef = React21.useRef(bump);
|
|
3106
|
+
bumpRef.current = bump;
|
|
3107
|
+
const holdTimer = React21.useRef(null);
|
|
3108
|
+
const release = () => {
|
|
3109
|
+
if (holdTimer.current) clearTimeout(holdTimer.current);
|
|
3110
|
+
holdTimer.current = null;
|
|
3111
|
+
};
|
|
3112
|
+
const hold = (direction) => {
|
|
3113
|
+
release();
|
|
3114
|
+
bump(direction, step);
|
|
3115
|
+
let repeats = 0;
|
|
3057
3116
|
const tick = () => {
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3117
|
+
repeats++;
|
|
3118
|
+
if (!bumpRef.current(direction, repeats > HOLD_BIG_AFTER ? big : step)) {
|
|
3119
|
+
release();
|
|
3120
|
+
return;
|
|
3121
|
+
}
|
|
3122
|
+
holdTimer.current = setTimeout(tick, holdInterval(repeats));
|
|
3061
3123
|
};
|
|
3062
|
-
|
|
3063
|
-
};
|
|
3064
|
-
const release = () => {
|
|
3065
|
-
if (timer.current) clearTimeout(timer.current);
|
|
3124
|
+
holdTimer.current = setTimeout(tick, HOLD_DELAY_MS);
|
|
3066
3125
|
};
|
|
3067
3126
|
React21.useEffect(() => () => {
|
|
3068
|
-
if (
|
|
3127
|
+
if (holdTimer.current) clearTimeout(holdTimer.current);
|
|
3069
3128
|
}, []);
|
|
3070
|
-
const
|
|
3071
|
-
|
|
3072
|
-
return n == null ? "" : format ? n.toLocaleString() : String(n);
|
|
3073
|
-
})();
|
|
3129
|
+
const current2 = committedRef.current;
|
|
3130
|
+
const shown = editing || !valid ? text : parsed == null ? "" : format ? parsed.toLocaleString() : String(parsed);
|
|
3074
3131
|
const shownError = error || invalidMessage || void 0;
|
|
3075
3132
|
const box = ["fd-input", "fd-input-num", shownError ? "fd-input-error" : "", disabled ? "fd-input-disabled" : ""].filter(Boolean).join(" ");
|
|
3076
3133
|
const fieldName = label || ariaLabel;
|
|
3077
3134
|
const stepperName = (verb) => fieldName ? verb + " " + fieldName : verb;
|
|
3135
|
+
const noRange = lo > hi;
|
|
3078
3136
|
return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: ["fd-field", className].filter(Boolean).join(" "), style, children: [
|
|
3079
3137
|
label ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(FieldLabel, { htmlFor: fieldId, required, children: label }) : null,
|
|
3080
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: box,
|
|
3138
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: box, children: [
|
|
3081
3139
|
prefix ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-input-affix", children: prefix }) : null,
|
|
3082
3140
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
3083
3141
|
"input",
|
|
@@ -3090,52 +3148,54 @@ function NumberInput({
|
|
|
3090
3148
|
value: shown,
|
|
3091
3149
|
"aria-invalid": shownError ? "true" : void 0,
|
|
3092
3150
|
"aria-describedby": shownError ? errorId : void 0,
|
|
3093
|
-
onFocus: () =>
|
|
3151
|
+
onFocus: () => {
|
|
3152
|
+
focusedRef.current = true;
|
|
3153
|
+
setEditing(true);
|
|
3154
|
+
},
|
|
3094
3155
|
onBlur: () => {
|
|
3156
|
+
focusedRef.current = false;
|
|
3095
3157
|
setEditing(false);
|
|
3096
|
-
if (text.trim() === "") fire(void 0);
|
|
3158
|
+
if (text.trim() === "" && committedRef.current != null) fire(void 0);
|
|
3097
3159
|
},
|
|
3098
3160
|
onChange: (e) => {
|
|
3099
3161
|
const raw = e.target.value;
|
|
3100
3162
|
setText(raw);
|
|
3101
|
-
|
|
3102
|
-
setInvalidMessage(null);
|
|
3103
|
-
fire(void 0);
|
|
3104
|
-
return;
|
|
3105
|
-
}
|
|
3106
|
-
const n = num(raw);
|
|
3163
|
+
const n = parseNumberText(raw);
|
|
3107
3164
|
if (n == null) {
|
|
3108
|
-
|
|
3165
|
+
if (committedRef.current != null) fire(void 0);
|
|
3109
3166
|
return;
|
|
3110
3167
|
}
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
if (!message) fire(n);
|
|
3168
|
+
if (Number.isNaN(n) || integer && !Number.isInteger(n) || n < lo || n > hi) return;
|
|
3169
|
+
fire(n);
|
|
3114
3170
|
},
|
|
3115
3171
|
onKeyDown: (e) => {
|
|
3116
3172
|
if (e.key === "ArrowUp") {
|
|
3117
3173
|
e.preventDefault();
|
|
3118
|
-
bump(1, e.shiftKey ?
|
|
3174
|
+
bump(1, e.shiftKey ? big : step);
|
|
3119
3175
|
} else if (e.key === "ArrowDown") {
|
|
3120
3176
|
e.preventDefault();
|
|
3121
|
-
bump(-1, e.shiftKey ?
|
|
3177
|
+
bump(-1, e.shiftKey ? big : step);
|
|
3122
3178
|
}
|
|
3123
3179
|
}
|
|
3124
3180
|
}
|
|
3125
3181
|
),
|
|
3126
3182
|
suffix ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("span", { className: "fd-input-affix", children: suffix }) : null,
|
|
3127
|
-
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "fd-
|
|
3183
|
+
/* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("span", { className: "fd-input-steppers", children: [
|
|
3128
3184
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
3129
3185
|
"button",
|
|
3130
3186
|
{
|
|
3131
3187
|
type: "button",
|
|
3132
3188
|
className: "fd-stepbtn",
|
|
3133
3189
|
"aria-label": stepperName("Decrease"),
|
|
3134
|
-
disabled: disabled ||
|
|
3190
|
+
disabled: disabled || noRange || current2 != null && current2 <= lo,
|
|
3135
3191
|
onPointerDown: () => hold(-1),
|
|
3136
3192
|
onPointerUp: release,
|
|
3137
3193
|
onPointerLeave: release,
|
|
3138
|
-
|
|
3194
|
+
onPointerCancel: release,
|
|
3195
|
+
onClick: (e) => {
|
|
3196
|
+
if (e.detail === 0) bump(-1, step);
|
|
3197
|
+
},
|
|
3198
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-minus", "aria-hidden": "true" })
|
|
3139
3199
|
}
|
|
3140
3200
|
),
|
|
3141
3201
|
/* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
@@ -3144,11 +3204,15 @@ function NumberInput({
|
|
|
3144
3204
|
type: "button",
|
|
3145
3205
|
className: "fd-stepbtn",
|
|
3146
3206
|
"aria-label": stepperName("Increase"),
|
|
3147
|
-
disabled: disabled ||
|
|
3207
|
+
disabled: disabled || noRange || current2 != null && current2 >= hi,
|
|
3148
3208
|
onPointerDown: () => hold(1),
|
|
3149
3209
|
onPointerUp: release,
|
|
3150
3210
|
onPointerLeave: release,
|
|
3151
|
-
|
|
3211
|
+
onPointerCancel: release,
|
|
3212
|
+
onClick: (e) => {
|
|
3213
|
+
if (e.detail === 0) bump(1, step);
|
|
3214
|
+
},
|
|
3215
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("i", { className: "ph ph-plus", "aria-hidden": "true" })
|
|
3152
3216
|
}
|
|
3153
3217
|
)
|
|
3154
3218
|
] })
|
|
@@ -3433,6 +3497,97 @@ function isFieldSet(field, value) {
|
|
|
3433
3497
|
}
|
|
3434
3498
|
}
|
|
3435
3499
|
}
|
|
3500
|
+
var MAX_WITHIN_DAYS = 3650;
|
|
3501
|
+
function effectiveMaxDays(field) {
|
|
3502
|
+
return Math.min(field.maxDays ?? MAX_WITHIN_DAYS, MAX_WITHIN_DAYS);
|
|
3503
|
+
}
|
|
3504
|
+
function isIsoDate(v) {
|
|
3505
|
+
if (typeof v !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(v)) return false;
|
|
3506
|
+
const d = /* @__PURE__ */ new Date(v + "T00:00:00Z");
|
|
3507
|
+
return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === v;
|
|
3508
|
+
}
|
|
3509
|
+
var isOption = (o) => !!o && typeof o.value === "string" && typeof o.label === "string";
|
|
3510
|
+
function validateFilterValue(field, value) {
|
|
3511
|
+
switch (field.type) {
|
|
3512
|
+
case "text":
|
|
3513
|
+
return typeof value === "string" ? { ok: true } : { ok: false, reason: "Enter text" };
|
|
3514
|
+
case "select":
|
|
3515
|
+
return field.options.some((o) => o.value === value) ? { ok: true } : { ok: false, reason: "Pick one of the options" };
|
|
3516
|
+
case "multiSelect": {
|
|
3517
|
+
const v = value;
|
|
3518
|
+
if (!v || !Array.isArray(v.values) || v.values.length === 0) {
|
|
3519
|
+
return { ok: false, reason: "Select at least one value" };
|
|
3520
|
+
}
|
|
3521
|
+
if (!v.values.every(isOption)) return { ok: false, reason: "Each value needs a value and a label" };
|
|
3522
|
+
if (field.maxValues != null && v.values.length > field.maxValues) {
|
|
3523
|
+
return { ok: false, reason: "Select at most " + field.maxValues + " values" };
|
|
3524
|
+
}
|
|
3525
|
+
if (!operatorsFor(field).includes(v.operator)) {
|
|
3526
|
+
return { ok: false, reason: "That operator isn't allowed for " + field.label };
|
|
3527
|
+
}
|
|
3528
|
+
return { ok: true };
|
|
3529
|
+
}
|
|
3530
|
+
case "range": {
|
|
3531
|
+
const v = value;
|
|
3532
|
+
if (!v || v.min == null && v.max == null) {
|
|
3533
|
+
return { ok: false, reason: "Enter at least one bound" };
|
|
3534
|
+
}
|
|
3535
|
+
const lo = field.min ?? -Infinity;
|
|
3536
|
+
const hi = field.max ?? Infinity;
|
|
3537
|
+
for (const n of [v.min, v.max]) {
|
|
3538
|
+
if (n == null) continue;
|
|
3539
|
+
if (typeof n !== "number" || !Number.isFinite(n)) return { ok: false, reason: "Enter a number" };
|
|
3540
|
+
if (field.integer && !Number.isInteger(n)) return { ok: false, reason: "Enter a whole number" };
|
|
3541
|
+
if (n < lo) return { ok: false, reason: "Must be \u2265 " + lo };
|
|
3542
|
+
if (n > hi) return { ok: false, reason: "Must be \u2264 " + hi };
|
|
3543
|
+
}
|
|
3544
|
+
if (v.min != null && v.max != null && v.min > v.max) {
|
|
3545
|
+
return { ok: false, reason: "Must be \u2265 " + v.min };
|
|
3546
|
+
}
|
|
3547
|
+
return { ok: true };
|
|
3548
|
+
}
|
|
3549
|
+
case "date": {
|
|
3550
|
+
const v = value;
|
|
3551
|
+
if (!v) return { ok: false, reason: "Pick a date value" };
|
|
3552
|
+
if (v.kind === "withinDays") {
|
|
3553
|
+
const maxDays = effectiveMaxDays(field);
|
|
3554
|
+
if (v.days == null) return { ok: false, reason: "Enter a number of days" };
|
|
3555
|
+
if (!Number.isInteger(v.days)) return { ok: false, reason: "Enter a whole number" };
|
|
3556
|
+
if (v.days < 1) return { ok: false, reason: "Must be \u2265 1" };
|
|
3557
|
+
if (v.days > maxDays) return { ok: false, reason: "Must be \u2264 " + maxDays };
|
|
3558
|
+
return { ok: true };
|
|
3559
|
+
}
|
|
3560
|
+
if (v.kind !== "between") return { ok: false, reason: "Pick a date value" };
|
|
3561
|
+
if (!v.from || !v.to) return { ok: false, reason: "Pick both dates" };
|
|
3562
|
+
if (!isIsoDate(v.from) || !isIsoDate(v.to)) return { ok: false, reason: "Dates must be YYYY-MM-DD" };
|
|
3563
|
+
if (v.from > v.to) return { ok: false, reason: "The start date must be on or before the end date" };
|
|
3564
|
+
return { ok: true };
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
}
|
|
3568
|
+
function isEmptyCandidate(field, candidate) {
|
|
3569
|
+
return field.type !== "text" && field.type !== "select" && !isFieldSet(field, candidate);
|
|
3570
|
+
}
|
|
3571
|
+
function assertValidFieldDefinition(field) {
|
|
3572
|
+
if (field.type === "multiSelect" && field.maxValues != null && (!Number.isInteger(field.maxValues) || field.maxValues < 1)) {
|
|
3573
|
+
throw new Error(
|
|
3574
|
+
'FilterBar: multiSelect field "' + field.key + '" has an invalid maxValues (' + field.maxValues + ") \u2014 must be a whole number of at least 1."
|
|
3575
|
+
);
|
|
3576
|
+
}
|
|
3577
|
+
if (field.type !== "date") return;
|
|
3578
|
+
const defaultDays = field.defaultDays ?? 30;
|
|
3579
|
+
const maxDays = field.maxDays ?? MAX_WITHIN_DAYS;
|
|
3580
|
+
if (!Number.isInteger(maxDays) || maxDays < 1 || maxDays > MAX_WITHIN_DAYS) {
|
|
3581
|
+
throw new Error(
|
|
3582
|
+
'FilterBar: date field "' + field.key + '" has an invalid maxDays (' + field.maxDays + ") \u2014 must be a whole number from 1 to " + MAX_WITHIN_DAYS + "."
|
|
3583
|
+
);
|
|
3584
|
+
}
|
|
3585
|
+
if (!Number.isInteger(defaultDays) || defaultDays < 1 || defaultDays > maxDays) {
|
|
3586
|
+
throw new Error(
|
|
3587
|
+
'FilterBar: date field "' + field.key + '" has an invalid defaultDays (' + field.defaultDays + ") \u2014 must be a whole number from 1 to maxDays (" + maxDays + ")."
|
|
3588
|
+
);
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3436
3591
|
function chipLabel(field, value) {
|
|
3437
3592
|
switch (field.type) {
|
|
3438
3593
|
case "text":
|
|
@@ -3485,8 +3640,7 @@ function MultiSelectPanel({
|
|
|
3485
3640
|
field,
|
|
3486
3641
|
value,
|
|
3487
3642
|
anchorRef,
|
|
3488
|
-
|
|
3489
|
-
onRemove,
|
|
3643
|
+
onCommit,
|
|
3490
3644
|
onClose
|
|
3491
3645
|
}) {
|
|
3492
3646
|
const allowedOps = operatorsFor(field);
|
|
@@ -3495,13 +3649,21 @@ function MultiSelectPanel({
|
|
|
3495
3649
|
const selected = value?.values ?? [];
|
|
3496
3650
|
const selectedRef = React24.useRef(selected);
|
|
3497
3651
|
selectedRef.current = selected;
|
|
3652
|
+
const operatorRef = React24.useRef(operator);
|
|
3653
|
+
operatorRef.current = operator;
|
|
3654
|
+
const mountedRef = React24.useRef(true);
|
|
3655
|
+
React24.useEffect(() => {
|
|
3656
|
+
mountedRef.current = true;
|
|
3657
|
+
return () => {
|
|
3658
|
+
mountedRef.current = false;
|
|
3659
|
+
};
|
|
3660
|
+
}, []);
|
|
3498
3661
|
const commit = (nextValues, nextOperator = operator) => {
|
|
3499
|
-
|
|
3500
|
-
else onChange({ operator: nextOperator, values: nextValues });
|
|
3662
|
+
onCommit({ operator: nextOperator, values: nextValues });
|
|
3501
3663
|
};
|
|
3502
3664
|
const setOperator = (op) => {
|
|
3503
3665
|
setDraftOperator(op);
|
|
3504
|
-
if (
|
|
3666
|
+
if (selectedRef.current.length > 0) commit(selectedRef.current, op);
|
|
3505
3667
|
};
|
|
3506
3668
|
const [mode2, setMode] = React24.useState("search");
|
|
3507
3669
|
const [query, setQuery] = React24.useState("");
|
|
@@ -3541,9 +3703,12 @@ function MultiSelectPanel({
|
|
|
3541
3703
|
const showError = !!field.loadOptions && asyncState.error;
|
|
3542
3704
|
const hasListbox = !showLoading && !showError && options.length > 0;
|
|
3543
3705
|
const isSelected = (o) => selected.some((s) => s.value === o.value);
|
|
3706
|
+
const atLimit = field.maxValues != null && selected.length >= field.maxValues;
|
|
3544
3707
|
const toggle = (o) => {
|
|
3545
|
-
const
|
|
3546
|
-
|
|
3708
|
+
const current2 = selectedRef.current;
|
|
3709
|
+
const on = current2.some((s) => s.value === o.value);
|
|
3710
|
+
if (!on && field.maxValues != null && current2.length >= field.maxValues) return;
|
|
3711
|
+
commit(on ? current2.filter((s) => s.value !== o.value) : [...current2, o]);
|
|
3547
3712
|
};
|
|
3548
3713
|
const nav = useListboxNav({ count: options.length, onSelect: (i) => toggle(options[i]) });
|
|
3549
3714
|
useListboxScrollIntoView(nav.active, listRef, hasListbox);
|
|
@@ -3551,8 +3716,7 @@ function MultiSelectPanel({
|
|
|
3551
3716
|
nav.setActive(0);
|
|
3552
3717
|
}, [query, options.length]);
|
|
3553
3718
|
const activeId = hasListbox && options[nav.active] ? listId + "-opt-" + nav.active : void 0;
|
|
3554
|
-
const
|
|
3555
|
-
const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : "";
|
|
3719
|
+
const liveMessage = showLoading ? "Loading\u2026" : showError ? "Couldn't load options." : options.length === 0 ? "No matches" : atLimit ? "Limit reached: at most " + field.maxValues + " values" : "";
|
|
3556
3720
|
const [pasteText, setPasteText] = React24.useState("");
|
|
3557
3721
|
const [pasteLoading, setPasteLoading] = React24.useState(false);
|
|
3558
3722
|
const [unmatchedTokens, setUnmatchedTokens] = React24.useState([]);
|
|
@@ -3568,13 +3732,19 @@ function MultiSelectPanel({
|
|
|
3568
3732
|
setPasteLoading(true);
|
|
3569
3733
|
setPasteError(null);
|
|
3570
3734
|
field.resolve(tokens).then((result) => {
|
|
3735
|
+
if (!mountedRef.current) return;
|
|
3571
3736
|
setPasteLoading(false);
|
|
3572
3737
|
setUnmatchedTokens(result.unmatched);
|
|
3573
3738
|
const merged = new Map(selectedRef.current.map((s) => [s.value, s]));
|
|
3574
3739
|
for (const m of result.matched) merged.set(m.value, { value: m.value, label: m.label });
|
|
3575
|
-
|
|
3740
|
+
if (field.maxValues != null && merged.size > field.maxValues) {
|
|
3741
|
+
setPasteError("This filter allows at most " + field.maxValues + " values; adding this list would make " + merged.size + ".");
|
|
3742
|
+
return;
|
|
3743
|
+
}
|
|
3744
|
+
commit(Array.from(merged.values()), operatorRef.current);
|
|
3576
3745
|
setPasteText("");
|
|
3577
|
-
}
|
|
3746
|
+
}, (err) => {
|
|
3747
|
+
if (!mountedRef.current) return;
|
|
3578
3748
|
setPasteLoading(false);
|
|
3579
3749
|
setPasteError(err instanceof Error ? err.message : "Could not resolve the pasted list.");
|
|
3580
3750
|
});
|
|
@@ -3652,14 +3822,14 @@ function MultiSelectPanel({
|
|
|
3652
3822
|
selected.length,
|
|
3653
3823
|
" matched"
|
|
3654
3824
|
] }),
|
|
3655
|
-
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-row fd-wrap fd-gap-xs", children: selected.map((v) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { onRemove: () => commit(
|
|
3825
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-row fd-wrap fd-gap-xs", children: selected.map((v) => /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Tag, { onRemove: () => commit(selectedRef.current.filter((s) => s.value !== v.value)), children: v.label }, v.value)) })
|
|
3656
3826
|
] }) : null
|
|
3657
3827
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3658
3828
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3659
3829
|
"span",
|
|
3660
3830
|
{
|
|
3661
3831
|
className: "fd-row fd-gap-xs" + (liveMessage && !showError ? " fd-muted" : ""),
|
|
3662
|
-
role:
|
|
3832
|
+
role: "status",
|
|
3663
3833
|
children: [
|
|
3664
3834
|
showLoading ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-spinner", "aria-hidden": "true" }) : null,
|
|
3665
3835
|
liveMessage ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-body-sm", children: liveMessage }) : null
|
|
@@ -3669,6 +3839,7 @@ function MultiSelectPanel({
|
|
|
3669
3839
|
showError ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: () => setRetryTick((n) => n + 1), children: "Retry" }) : null,
|
|
3670
3840
|
hasListbox ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { id: listId, role: "listbox", "aria-label": field.label, "aria-multiselectable": "true", ref: listRef, className: "fd-pop-list", children: options.map((o, i) => {
|
|
3671
3841
|
const on = isSelected(o);
|
|
3842
|
+
const blocked = !on && atLimit;
|
|
3672
3843
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
3673
3844
|
"div",
|
|
3674
3845
|
{
|
|
@@ -3677,6 +3848,7 @@ function MultiSelectPanel({
|
|
|
3677
3848
|
role: "option",
|
|
3678
3849
|
tabIndex: -1,
|
|
3679
3850
|
"aria-selected": on,
|
|
3851
|
+
"aria-disabled": blocked ? "true" : void 0,
|
|
3680
3852
|
className: ["fd-opt", i === nav.active ? "is-active" : "", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3681
3853
|
onMouseEnter: () => nav.setActive(i),
|
|
3682
3854
|
onClick: () => toggle(o),
|
|
@@ -3710,22 +3882,24 @@ function RangePanel({
|
|
|
3710
3882
|
field,
|
|
3711
3883
|
value,
|
|
3712
3884
|
anchorRef,
|
|
3713
|
-
|
|
3714
|
-
onRemove,
|
|
3885
|
+
onCommit,
|
|
3715
3886
|
onClose
|
|
3716
3887
|
}) {
|
|
3717
|
-
const [
|
|
3718
|
-
const
|
|
3719
|
-
const
|
|
3720
|
-
const
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3888
|
+
const [draft, setDraft] = React24.useState({ min: value?.min, max: value?.max });
|
|
3889
|
+
const draftRef = React24.useRef(draft);
|
|
3890
|
+
const [minTextValid, setMinTextValid] = React24.useState(true);
|
|
3891
|
+
const [maxTextValid, setMaxTextValid] = React24.useState(true);
|
|
3892
|
+
const draftMin = draft.min;
|
|
3893
|
+
const draftMax = draft.max;
|
|
3894
|
+
const isEmpty = draftMin == null && draftMax == null;
|
|
3895
|
+
const validation = isEmpty ? { ok: true } : validateFilterValue(field, { min: draftMin, max: draftMax });
|
|
3896
|
+
const comboError = !isEmpty && !validation.ok ? validation.reason : void 0;
|
|
3897
|
+
const doneDisabled = !minTextValid || !maxTextValid || !!comboError;
|
|
3898
|
+
const apply = (patch) => {
|
|
3899
|
+
const next = { ...draftRef.current, ...patch };
|
|
3900
|
+
draftRef.current = next;
|
|
3901
|
+
setDraft(next);
|
|
3902
|
+
onCommit(next.min == null && next.max == null ? void 0 : next);
|
|
3729
3903
|
};
|
|
3730
3904
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3731
3905
|
Popover,
|
|
@@ -3737,7 +3911,7 @@ function RangePanel({
|
|
|
3737
3911
|
offset: 6,
|
|
3738
3912
|
width: PANEL_WIDTH.range,
|
|
3739
3913
|
label: field.label,
|
|
3740
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: onClose, disabled:
|
|
3914
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: onClose, disabled: doneDisabled, children: "Done" }),
|
|
3741
3915
|
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3742
3916
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3743
3917
|
NumberInput,
|
|
@@ -3747,8 +3921,10 @@ function RangePanel({
|
|
|
3747
3921
|
min: field.min,
|
|
3748
3922
|
max: field.max,
|
|
3749
3923
|
step: field.step,
|
|
3924
|
+
integer: field.integer,
|
|
3750
3925
|
placeholder: field.minPlaceholder,
|
|
3751
|
-
onChange: (e) => apply(e.target.value
|
|
3926
|
+
onChange: (e) => apply({ min: e.target.value }),
|
|
3927
|
+
onValidityChange: setMinTextValid
|
|
3752
3928
|
}
|
|
3753
3929
|
),
|
|
3754
3930
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
@@ -3759,9 +3935,11 @@ function RangePanel({
|
|
|
3759
3935
|
min: field.min,
|
|
3760
3936
|
max: field.max,
|
|
3761
3937
|
step: field.step,
|
|
3762
|
-
|
|
3938
|
+
integer: field.integer,
|
|
3939
|
+
error: comboError,
|
|
3763
3940
|
placeholder: field.maxPlaceholder,
|
|
3764
|
-
onChange: (e) => apply(
|
|
3941
|
+
onChange: (e) => apply({ max: e.target.value }),
|
|
3942
|
+
onValidityChange: setMaxTextValid
|
|
3765
3943
|
}
|
|
3766
3944
|
)
|
|
3767
3945
|
] })
|
|
@@ -3772,12 +3950,12 @@ function DatePanel({
|
|
|
3772
3950
|
field,
|
|
3773
3951
|
value,
|
|
3774
3952
|
anchorRef,
|
|
3775
|
-
|
|
3776
|
-
onRemove,
|
|
3953
|
+
onCommit,
|
|
3777
3954
|
onClose
|
|
3778
3955
|
}) {
|
|
3779
3956
|
const defaultDays = field.defaultDays ?? 30;
|
|
3780
|
-
const maxDays = field
|
|
3957
|
+
const maxDays = effectiveMaxDays(field);
|
|
3958
|
+
const [daysTextValid, setDaysTextValid] = React24.useState(true);
|
|
3781
3959
|
const [kind, setKind] = React24.useState(value?.kind ?? "withinDays");
|
|
3782
3960
|
const [daysDraft, setDaysDraft] = React24.useState(
|
|
3783
3961
|
value?.kind === "withinDays" ? value.days : defaultDays
|
|
@@ -3785,42 +3963,26 @@ function DatePanel({
|
|
|
3785
3963
|
const [between, setBetween] = React24.useState(
|
|
3786
3964
|
value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
|
|
3787
3965
|
);
|
|
3788
|
-
const committedRef = React24.useRef(!!value);
|
|
3789
3966
|
const applyWithinDays = (days) => {
|
|
3790
3967
|
setDaysDraft(days);
|
|
3791
|
-
|
|
3792
|
-
committedRef.current = true;
|
|
3793
|
-
onChange({ kind: "withinDays", days });
|
|
3794
|
-
} else if (committedRef.current) {
|
|
3795
|
-
committedRef.current = false;
|
|
3796
|
-
onRemove();
|
|
3797
|
-
}
|
|
3968
|
+
onCommit(days == null ? void 0 : { kind: "withinDays", days });
|
|
3798
3969
|
};
|
|
3799
3970
|
const applyBetween = (from, to) => {
|
|
3800
3971
|
setBetween({ from, to });
|
|
3801
|
-
|
|
3802
|
-
committedRef.current = true;
|
|
3803
|
-
onChange({ kind: "between", from, to });
|
|
3804
|
-
} else if (committedRef.current) {
|
|
3805
|
-
committedRef.current = false;
|
|
3806
|
-
onRemove();
|
|
3807
|
-
}
|
|
3972
|
+
onCommit(from && to ? { kind: "between", from, to } : void 0);
|
|
3808
3973
|
};
|
|
3809
3974
|
const switchKind = (next) => {
|
|
3975
|
+
if (next === kind) return;
|
|
3810
3976
|
setKind(next);
|
|
3811
|
-
if (next === "between") {
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
onRemove();
|
|
3816
|
-
}
|
|
3817
|
-
}
|
|
3977
|
+
if (next === "between") setBetween({ from: "", to: "" });
|
|
3978
|
+
else setDaysDraft(defaultDays);
|
|
3979
|
+
setDaysTextValid(true);
|
|
3980
|
+
onCommit(void 0);
|
|
3818
3981
|
};
|
|
3982
|
+
const doneDisabled = kind === "withinDays" && !daysTextValid;
|
|
3819
3983
|
const confirm = () => {
|
|
3820
|
-
if (
|
|
3821
|
-
|
|
3822
|
-
onChange({ kind: "withinDays", days: daysDraft });
|
|
3823
|
-
}
|
|
3984
|
+
if (doneDisabled) return;
|
|
3985
|
+
if (kind === "withinDays" && daysDraft != null) onCommit({ kind: "withinDays", days: daysDraft });
|
|
3824
3986
|
onClose();
|
|
3825
3987
|
};
|
|
3826
3988
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
@@ -3833,7 +3995,7 @@ function DatePanel({
|
|
|
3833
3995
|
offset: 6,
|
|
3834
3996
|
width: PANEL_WIDTH.date,
|
|
3835
3997
|
label: field.label,
|
|
3836
|
-
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: confirm, children: "Done" }),
|
|
3998
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { size: "sm", variant: "secondary", onClick: confirm, disabled: doneDisabled, children: "Done" }),
|
|
3837
3999
|
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("span", { className: "fd-stack fd-gap-sm", children: [
|
|
3838
4000
|
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3839
4001
|
SegmentedControl,
|
|
@@ -3847,7 +4009,19 @@ function DatePanel({
|
|
|
3847
4009
|
onChange: (k) => switchKind(k)
|
|
3848
4010
|
}
|
|
3849
4011
|
),
|
|
3850
|
-
kind === "withinDays" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
4012
|
+
kind === "withinDays" ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
4013
|
+
NumberInput,
|
|
4014
|
+
{
|
|
4015
|
+
label: "Days",
|
|
4016
|
+
min: 1,
|
|
4017
|
+
max: maxDays,
|
|
4018
|
+
step: 1,
|
|
4019
|
+
integer: true,
|
|
4020
|
+
value: daysDraft ?? "",
|
|
4021
|
+
onChange: (e) => applyWithinDays(e.target.value),
|
|
4022
|
+
onValidityChange: setDaysTextValid
|
|
4023
|
+
}
|
|
4024
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
3851
4025
|
DatePicker,
|
|
3852
4026
|
{
|
|
3853
4027
|
range: true,
|
|
@@ -3866,6 +4040,33 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3866
4040
|
const addAnchorRef = React24.useRef(null);
|
|
3867
4041
|
const textInputRef = React24.useRef(null);
|
|
3868
4042
|
const optionsRef = React24.useRef(null);
|
|
4043
|
+
if (process.env.NODE_ENV !== "production") {
|
|
4044
|
+
for (const f of fields) assertValidFieldDefinition(f);
|
|
4045
|
+
}
|
|
4046
|
+
const latest = React24.useRef({ fields, filters, onFilterChange, onFilterRemove });
|
|
4047
|
+
latest.current = { fields, filters, onFilterChange, onFilterRemove };
|
|
4048
|
+
const commit = (field, candidate) => {
|
|
4049
|
+
const current2 = latest.current.fields.find((f) => f.key === field.key);
|
|
4050
|
+
if (!current2) return { ok: false, reason: "This filter is no longer available" };
|
|
4051
|
+
if (isEmptyCandidate(current2, candidate)) {
|
|
4052
|
+
removeField(current2);
|
|
4053
|
+
return { ok: true };
|
|
4054
|
+
}
|
|
4055
|
+
const result = validateFilterValue(current2, candidate);
|
|
4056
|
+
if (result.ok) {
|
|
4057
|
+
latest.current.filters = { ...latest.current.filters, [current2.key]: candidate };
|
|
4058
|
+
latest.current.onFilterChange(current2.key, candidate);
|
|
4059
|
+
}
|
|
4060
|
+
return result;
|
|
4061
|
+
};
|
|
4062
|
+
const removeField = (field) => {
|
|
4063
|
+
const { filters: now, onFilterRemove: remove } = latest.current;
|
|
4064
|
+
if (!isFieldSet(field, now[field.key])) return;
|
|
4065
|
+
const next = { ...now };
|
|
4066
|
+
delete next[field.key];
|
|
4067
|
+
latest.current.filters = next;
|
|
4068
|
+
remove(field.key);
|
|
4069
|
+
};
|
|
3869
4070
|
const editingField = panel && panel.kind === "edit" ? fields.find((f) => f.key === panel.key) : void 0;
|
|
3870
4071
|
const startEditing = (key) => setPanel({ kind: "edit", key });
|
|
3871
4072
|
const closeEditing = () => setPanel(null);
|
|
@@ -3897,7 +4098,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3897
4098
|
value: value ?? "",
|
|
3898
4099
|
placeholder: field.placeholder || field.label,
|
|
3899
4100
|
"aria-label": field.label,
|
|
3900
|
-
onChange: (e) =>
|
|
4101
|
+
onChange: (e) => commit(field, e.target.value),
|
|
3901
4102
|
onKeyDown: (e) => {
|
|
3902
4103
|
if (e.key === "Enter") setPanel(null);
|
|
3903
4104
|
else if (e.key === "Escape") {
|
|
@@ -3916,7 +4117,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3916
4117
|
"aria-label": "Remove " + field.label,
|
|
3917
4118
|
onClick: (e) => {
|
|
3918
4119
|
e.stopPropagation();
|
|
3919
|
-
|
|
4120
|
+
removeField(field);
|
|
3920
4121
|
setPanel(null);
|
|
3921
4122
|
},
|
|
3922
4123
|
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("i", { className: "ph ph-x", "aria-hidden": "true" })
|
|
@@ -3929,7 +4130,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3929
4130
|
const chipRef = editing ? editAnchorRef : void 0;
|
|
3930
4131
|
const toggleOrClose = () => editing ? closeEditing() : startEditing(field.key);
|
|
3931
4132
|
const remove = () => {
|
|
3932
|
-
|
|
4133
|
+
removeField(field);
|
|
3933
4134
|
closeEditing();
|
|
3934
4135
|
};
|
|
3935
4136
|
const chipText = field.label + (set ? ": " + chipLabel(field, value) : "");
|
|
@@ -3959,7 +4160,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3959
4160
|
"aria-selected": on,
|
|
3960
4161
|
className: ["fd-opt", on ? "is-selected" : ""].filter(Boolean).join(" "),
|
|
3961
4162
|
onClick: () => {
|
|
3962
|
-
|
|
4163
|
+
commit(field, o.value);
|
|
3963
4164
|
setPanel(null);
|
|
3964
4165
|
},
|
|
3965
4166
|
children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { className: "fd-opt-label", children: o.label })
|
|
@@ -3980,8 +4181,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3980
4181
|
field,
|
|
3981
4182
|
value,
|
|
3982
4183
|
anchorRef: editAnchorRef,
|
|
3983
|
-
|
|
3984
|
-
onRemove: () => onFilterRemove(field.key),
|
|
4184
|
+
onCommit: (v) => commit(field, v),
|
|
3985
4185
|
onClose: closeEditing
|
|
3986
4186
|
}
|
|
3987
4187
|
) : null
|
|
@@ -3996,8 +4196,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3996
4196
|
field,
|
|
3997
4197
|
value,
|
|
3998
4198
|
anchorRef: editAnchorRef,
|
|
3999
|
-
|
|
4000
|
-
onRemove: () => onFilterRemove(field.key),
|
|
4199
|
+
onCommit: (v) => commit(field, v),
|
|
4001
4200
|
onClose: closeEditing
|
|
4002
4201
|
}
|
|
4003
4202
|
) : null
|
|
@@ -4012,8 +4211,7 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
4012
4211
|
field,
|
|
4013
4212
|
value,
|
|
4014
4213
|
anchorRef: editAnchorRef,
|
|
4015
|
-
|
|
4016
|
-
onRemove: () => onFilterRemove(field.key),
|
|
4214
|
+
onCommit: (v) => commit(field, v),
|
|
4017
4215
|
onClose: closeEditing
|
|
4018
4216
|
}
|
|
4019
4217
|
) : null
|
|
@@ -13862,6 +14060,7 @@ function useDocumentTitle(routeTitle, appName) {
|
|
|
13862
14060
|
useServerTable,
|
|
13863
14061
|
useSessionContext,
|
|
13864
14062
|
useStagedFiles,
|
|
14063
|
+
validateFilterValue,
|
|
13865
14064
|
visibleMessages
|
|
13866
14065
|
});
|
|
13867
14066
|
//# sourceMappingURL=index.cjs.map
|