@flytedan/flytebot-design-system 0.32.0 → 0.33.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 +6 -4
- package/dist/index.cjs +75 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +75 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -1190,12 +1190,17 @@ interface FilterBarProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "on
|
|
|
1190
1190
|
fields: FilterField[];
|
|
1191
1191
|
/** Straight off useServerTable — a value of undefined/""/false reads as "not set",
|
|
1192
1192
|
* same convention that hook already uses for activeFilterCount. multiSelect/range/
|
|
1193
|
-
* date values are objects instead (see isFieldSet).
|
|
1193
|
+
* date values are objects instead (see isFieldSet). Pass a new object whenever the
|
|
1194
|
+
* filters change (as a state update does): FilterBar re-reads this record only when
|
|
1195
|
+
* its identity changes, so a parent that re-renders before applying an emission
|
|
1196
|
+
* doesn't make FilterBar forget it. */
|
|
1194
1197
|
filters: Record<string, unknown>;
|
|
1195
1198
|
/** Fires on every value edit. Maps 1:1 onto useServerTable's setFilter(id, value).
|
|
1196
1199
|
* FilterBar only ever calls this with a COMPLETE, valid value for the field — an
|
|
1197
|
-
* emptied selection, a one-sided date range, an invalid numeric range
|
|
1198
|
-
* bound go through onFilterRemove (or nothing
|
|
1200
|
+
* emptied selection, a one-sided date range, an invalid numeric range, number text
|
|
1201
|
+
* that isn't a valid value, or a cleared bound go through onFilterRemove (or nothing,
|
|
1202
|
+
* when the filter isn't set) instead. Number fields emit on every keystroke that
|
|
1203
|
+
* leaves them valid, so debounce the request this triggers. */
|
|
1199
1204
|
onFilterChange: (key: string, value: unknown) => void;
|
|
1200
1205
|
/** Fires when a chip's × is clicked, or when an edit leaves a field with no valid
|
|
1201
1206
|
* value. Maps 1:1 onto useServerTable's clearFilter(id). */
|
package/dist/index.d.ts
CHANGED
|
@@ -1190,12 +1190,17 @@ interface FilterBarProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "on
|
|
|
1190
1190
|
fields: FilterField[];
|
|
1191
1191
|
/** Straight off useServerTable — a value of undefined/""/false reads as "not set",
|
|
1192
1192
|
* same convention that hook already uses for activeFilterCount. multiSelect/range/
|
|
1193
|
-
* date values are objects instead (see isFieldSet).
|
|
1193
|
+
* date values are objects instead (see isFieldSet). Pass a new object whenever the
|
|
1194
|
+
* filters change (as a state update does): FilterBar re-reads this record only when
|
|
1195
|
+
* its identity changes, so a parent that re-renders before applying an emission
|
|
1196
|
+
* doesn't make FilterBar forget it. */
|
|
1194
1197
|
filters: Record<string, unknown>;
|
|
1195
1198
|
/** Fires on every value edit. Maps 1:1 onto useServerTable's setFilter(id, value).
|
|
1196
1199
|
* FilterBar only ever calls this with a COMPLETE, valid value for the field — an
|
|
1197
|
-
* emptied selection, a one-sided date range, an invalid numeric range
|
|
1198
|
-
* bound go through onFilterRemove (or nothing
|
|
1200
|
+
* emptied selection, a one-sided date range, an invalid numeric range, number text
|
|
1201
|
+
* that isn't a valid value, or a cleared bound go through onFilterRemove (or nothing,
|
|
1202
|
+
* when the filter isn't set) instead. Number fields emit on every keystroke that
|
|
1203
|
+
* leaves them valid, so debounce the request this triggers. */
|
|
1199
1204
|
onFilterChange: (key: string, value: unknown) => void;
|
|
1200
1205
|
/** Fires when a chip's × is clicked, or when an edit leaves a field with no valid
|
|
1201
1206
|
* value. Maps 1:1 onto useServerTable's clearFilter(id). */
|
package/dist/index.js
CHANGED
|
@@ -2977,7 +2977,8 @@ function NumberInput({
|
|
|
2977
2977
|
)
|
|
2978
2978
|
] })
|
|
2979
2979
|
] }),
|
|
2980
|
-
|
|
2980
|
+
/* @__PURE__ */ jsx42("span", { id: errorId, className: "fd-sr", role: "status", children: shownError ?? "" }),
|
|
2981
|
+
shownError ? /* @__PURE__ */ jsxs36("span", { className: "fd-field-error", "aria-hidden": "true", children: [
|
|
2981
2982
|
/* @__PURE__ */ jsx42("i", { className: "ph ph-warning-circle", "aria-hidden": "true" }),
|
|
2982
2983
|
shownError
|
|
2983
2984
|
] }) : help ? /* @__PURE__ */ jsx42("span", { className: "fd-field-help", children: help }) : null
|
|
@@ -3418,9 +3419,7 @@ function MultiSelectPanel({
|
|
|
3418
3419
|
mountedRef.current = false;
|
|
3419
3420
|
};
|
|
3420
3421
|
}, []);
|
|
3421
|
-
const commit = (nextValues, nextOperator = operator) => {
|
|
3422
|
-
onCommit({ operator: nextOperator, values: nextValues });
|
|
3423
|
-
};
|
|
3422
|
+
const commit = (nextValues, nextOperator = operator) => onCommit({ operator: nextOperator, values: nextValues });
|
|
3424
3423
|
const setOperator = (op) => {
|
|
3425
3424
|
setDraftOperator(op);
|
|
3426
3425
|
if (selectedRef.current.length > 0) commit(selectedRef.current, op);
|
|
@@ -3501,7 +3500,11 @@ function MultiSelectPanel({
|
|
|
3501
3500
|
setPasteError("This filter allows at most " + field.maxValues + " values; adding this list would make " + merged.size + ".");
|
|
3502
3501
|
return;
|
|
3503
3502
|
}
|
|
3504
|
-
commit(Array.from(merged.values()), operatorRef.current);
|
|
3503
|
+
const applied = commit(Array.from(merged.values()), operatorRef.current);
|
|
3504
|
+
if (!applied.ok) {
|
|
3505
|
+
setPasteError(applied.reason);
|
|
3506
|
+
return;
|
|
3507
|
+
}
|
|
3505
3508
|
setPasteText("");
|
|
3506
3509
|
}, (err) => {
|
|
3507
3510
|
if (!mountedRef.current) return;
|
|
@@ -3638,6 +3641,34 @@ function MultiSelectPanel({
|
|
|
3638
3641
|
}
|
|
3639
3642
|
);
|
|
3640
3643
|
}
|
|
3644
|
+
function useTextValidity(onFlip) {
|
|
3645
|
+
const invalidRef = React24.useRef(/* @__PURE__ */ new Set());
|
|
3646
|
+
const [, rerender] = React24.useReducer((n) => n + 1, 0);
|
|
3647
|
+
const onFlipRef = React24.useRef(onFlip);
|
|
3648
|
+
onFlipRef.current = onFlip;
|
|
3649
|
+
const record = (name, valid) => {
|
|
3650
|
+
const invalid = invalidRef.current;
|
|
3651
|
+
if (valid !== invalid.has(name)) return false;
|
|
3652
|
+
if (valid) invalid.delete(name);
|
|
3653
|
+
else invalid.add(name);
|
|
3654
|
+
rerender();
|
|
3655
|
+
return true;
|
|
3656
|
+
};
|
|
3657
|
+
return {
|
|
3658
|
+
allValid: () => invalidRef.current.size === 0,
|
|
3659
|
+
report: (name) => (valid) => {
|
|
3660
|
+
if (record(name, valid)) onFlipRef.current();
|
|
3661
|
+
},
|
|
3662
|
+
/** For an input that is about to unmount: it has nothing left to show. */
|
|
3663
|
+
forget: (name) => {
|
|
3664
|
+
record(name, true);
|
|
3665
|
+
}
|
|
3666
|
+
};
|
|
3667
|
+
}
|
|
3668
|
+
function applicable(field, candidate, textValid) {
|
|
3669
|
+
if (!textValid || candidate === void 0) return void 0;
|
|
3670
|
+
return validateFilterValue(field, candidate).ok ? candidate : void 0;
|
|
3671
|
+
}
|
|
3641
3672
|
function RangePanel({
|
|
3642
3673
|
field,
|
|
3643
3674
|
value,
|
|
@@ -3647,19 +3678,22 @@ function RangePanel({
|
|
|
3647
3678
|
}) {
|
|
3648
3679
|
const [draft, setDraft] = React24.useState({ min: value?.min, max: value?.max });
|
|
3649
3680
|
const draftRef = React24.useRef(draft);
|
|
3650
|
-
const
|
|
3651
|
-
|
|
3681
|
+
const publish = () => {
|
|
3682
|
+
const { min, max } = draftRef.current;
|
|
3683
|
+
onCommit(applicable(field, min == null && max == null ? void 0 : { min, max }, validity.allValid()));
|
|
3684
|
+
};
|
|
3685
|
+
const validity = useTextValidity(publish);
|
|
3652
3686
|
const draftMin = draft.min;
|
|
3653
3687
|
const draftMax = draft.max;
|
|
3654
3688
|
const isEmpty = draftMin == null && draftMax == null;
|
|
3655
3689
|
const validation = isEmpty ? { ok: true } : validateFilterValue(field, { min: draftMin, max: draftMax });
|
|
3656
3690
|
const comboError = !isEmpty && !validation.ok ? validation.reason : void 0;
|
|
3657
|
-
const doneDisabled = !
|
|
3691
|
+
const doneDisabled = !validity.allValid() || !!comboError;
|
|
3658
3692
|
const apply = (patch) => {
|
|
3659
3693
|
const next = { ...draftRef.current, ...patch };
|
|
3660
3694
|
draftRef.current = next;
|
|
3661
3695
|
setDraft(next);
|
|
3662
|
-
|
|
3696
|
+
publish();
|
|
3663
3697
|
};
|
|
3664
3698
|
return /* @__PURE__ */ jsx45(
|
|
3665
3699
|
Popover,
|
|
@@ -3684,7 +3718,7 @@ function RangePanel({
|
|
|
3684
3718
|
integer: field.integer,
|
|
3685
3719
|
placeholder: field.minPlaceholder,
|
|
3686
3720
|
onChange: (e) => apply({ min: e.target.value }),
|
|
3687
|
-
onValidityChange:
|
|
3721
|
+
onValidityChange: validity.report("min")
|
|
3688
3722
|
}
|
|
3689
3723
|
),
|
|
3690
3724
|
/* @__PURE__ */ jsx45(
|
|
@@ -3699,7 +3733,7 @@ function RangePanel({
|
|
|
3699
3733
|
error: comboError,
|
|
3700
3734
|
placeholder: field.maxPlaceholder,
|
|
3701
3735
|
onChange: (e) => apply({ max: e.target.value }),
|
|
3702
|
-
onValidityChange:
|
|
3736
|
+
onValidityChange: validity.report("max")
|
|
3703
3737
|
}
|
|
3704
3738
|
)
|
|
3705
3739
|
] })
|
|
@@ -3715,34 +3749,47 @@ function DatePanel({
|
|
|
3715
3749
|
}) {
|
|
3716
3750
|
const defaultDays = field.defaultDays ?? 30;
|
|
3717
3751
|
const maxDays = effectiveMaxDays(field);
|
|
3718
|
-
const [daysTextValid, setDaysTextValid] = React24.useState(true);
|
|
3719
3752
|
const [kind, setKind] = React24.useState(value?.kind ?? "withinDays");
|
|
3720
3753
|
const [daysDraft, setDaysDraft] = React24.useState(
|
|
3721
3754
|
value?.kind === "withinDays" ? value.days : defaultDays
|
|
3722
3755
|
);
|
|
3756
|
+
const daysRef = React24.useRef(daysDraft);
|
|
3723
3757
|
const [between, setBetween] = React24.useState(
|
|
3724
3758
|
value?.kind === "between" ? { from: value.from, to: value.to } : { from: "", to: "" }
|
|
3725
3759
|
);
|
|
3760
|
+
const shownWithinDays = () => {
|
|
3761
|
+
const days = daysRef.current;
|
|
3762
|
+
return applicable(field, days == null ? void 0 : { kind: "withinDays", days }, validity.allValid());
|
|
3763
|
+
};
|
|
3764
|
+
const validity = useTextValidity(() => onCommit(shownWithinDays()));
|
|
3726
3765
|
const applyWithinDays = (days) => {
|
|
3766
|
+
daysRef.current = days;
|
|
3727
3767
|
setDaysDraft(days);
|
|
3728
|
-
onCommit(
|
|
3768
|
+
onCommit(shownWithinDays());
|
|
3729
3769
|
};
|
|
3730
3770
|
const applyBetween = (from, to) => {
|
|
3731
3771
|
setBetween({ from, to });
|
|
3732
|
-
onCommit(from && to ? { kind: "between", from, to } : void 0);
|
|
3772
|
+
onCommit(applicable(field, from && to ? { kind: "between", from, to } : void 0, true));
|
|
3733
3773
|
};
|
|
3734
3774
|
const switchKind = (next) => {
|
|
3735
3775
|
if (next === kind) return;
|
|
3736
3776
|
setKind(next);
|
|
3737
|
-
if (next === "between")
|
|
3738
|
-
|
|
3739
|
-
|
|
3777
|
+
if (next === "between") {
|
|
3778
|
+
setBetween({ from: "", to: "" });
|
|
3779
|
+
validity.forget("days");
|
|
3780
|
+
} else {
|
|
3781
|
+
daysRef.current = defaultDays;
|
|
3782
|
+
setDaysDraft(defaultDays);
|
|
3783
|
+
}
|
|
3740
3784
|
onCommit(void 0);
|
|
3741
3785
|
};
|
|
3742
|
-
const doneDisabled = kind === "withinDays" && !
|
|
3786
|
+
const doneDisabled = kind === "withinDays" && !validity.allValid();
|
|
3743
3787
|
const confirm = () => {
|
|
3744
3788
|
if (doneDisabled) return;
|
|
3745
|
-
if (kind === "withinDays"
|
|
3789
|
+
if (kind === "withinDays") {
|
|
3790
|
+
const shown = shownWithinDays();
|
|
3791
|
+
if (shown) onCommit(shown);
|
|
3792
|
+
}
|
|
3746
3793
|
onClose();
|
|
3747
3794
|
};
|
|
3748
3795
|
return /* @__PURE__ */ jsx45(
|
|
@@ -3779,7 +3826,7 @@ function DatePanel({
|
|
|
3779
3826
|
integer: true,
|
|
3780
3827
|
value: daysDraft ?? "",
|
|
3781
3828
|
onChange: (e) => applyWithinDays(e.target.value),
|
|
3782
|
-
onValidityChange:
|
|
3829
|
+
onValidityChange: validity.report("days")
|
|
3783
3830
|
}
|
|
3784
3831
|
) : /* @__PURE__ */ jsx45(
|
|
3785
3832
|
DatePicker,
|
|
@@ -3804,7 +3851,14 @@ function FilterBar({ fields = [], filters, onFilterChange, onFilterRemove, align
|
|
|
3804
3851
|
for (const f of fields) assertValidFieldDefinition(f);
|
|
3805
3852
|
}
|
|
3806
3853
|
const latest = React24.useRef({ fields, filters, onFilterChange, onFilterRemove });
|
|
3807
|
-
|
|
3854
|
+
const filtersProp = React24.useRef(filters);
|
|
3855
|
+
if (filters !== filtersProp.current) {
|
|
3856
|
+
filtersProp.current = filters;
|
|
3857
|
+
latest.current.filters = filters;
|
|
3858
|
+
}
|
|
3859
|
+
latest.current.fields = fields;
|
|
3860
|
+
latest.current.onFilterChange = onFilterChange;
|
|
3861
|
+
latest.current.onFilterRemove = onFilterRemove;
|
|
3808
3862
|
const commit = (field, candidate) => {
|
|
3809
3863
|
const current2 = latest.current.fields.find((f) => f.key === field.key);
|
|
3810
3864
|
if (!current2) return { ok: false, reason: "This filter is no longer available" };
|