@rufous/ui 0.3.40 → 0.3.42
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/main.cjs +124 -35
- package/dist/main.d.cts +22 -7
- package/dist/main.d.ts +22 -7
- package/dist/main.js +124 -35
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -1422,14 +1422,14 @@ var SubmitButton = ({
|
|
|
1422
1422
|
setLoading(false);
|
|
1423
1423
|
}
|
|
1424
1424
|
};
|
|
1425
|
-
const handleClick = (e) => runProtected(e, onClick);
|
|
1426
|
-
const handleDoubleClick = (e) => runProtected(e, onDoubleClick);
|
|
1425
|
+
const handleClick = onClick ? (e) => runProtected(e, onClick) : void 0;
|
|
1426
|
+
const handleDoubleClick = onDoubleClick ? (e) => runProtected(e, onDoubleClick) : void 0;
|
|
1427
1427
|
const showLoader = loading || isLoading;
|
|
1428
1428
|
return /* @__PURE__ */ React60.createElement(
|
|
1429
1429
|
"button",
|
|
1430
1430
|
{
|
|
1431
1431
|
...props,
|
|
1432
|
-
type
|
|
1432
|
+
type,
|
|
1433
1433
|
className: ["btn submit-btn", bgGradiant ? "submit-btn-gradiant" : "", sxClass, className].filter(Boolean).join(" "),
|
|
1434
1434
|
disabled: props.disabled || showLoader,
|
|
1435
1435
|
onClick: handleClick,
|
|
@@ -5556,8 +5556,8 @@ function DataGrid({
|
|
|
5556
5556
|
const totalRows = isServer ? rowCount ?? data.length : flatEntries ? flatEntries.length : filteredData.length;
|
|
5557
5557
|
const totalPages = Math.max(1, Math.ceil(totalRows / activePageSize));
|
|
5558
5558
|
const displayRows = (0, import_react25.useMemo)(() => {
|
|
5559
|
-
if (isServer) return data.map((row) => ({ kind: "data", row, depth: 0 }));
|
|
5560
5559
|
const source = flatEntries ?? sortedData.map((row) => ({ kind: "data", row, depth: 0 }));
|
|
5560
|
+
if (isServer) return source;
|
|
5561
5561
|
const start = (activePage - 1) * activePageSize;
|
|
5562
5562
|
return source.slice(start, start + activePageSize);
|
|
5563
5563
|
}, [isServer, data, flatEntries, sortedData, activePage, activePageSize]);
|
|
@@ -5702,7 +5702,7 @@ function DataGrid({
|
|
|
5702
5702
|
const showExportBtn = !tOpts.hideExport && !hideTopExport;
|
|
5703
5703
|
const showTitle = !tOpts.hideTitle;
|
|
5704
5704
|
const showRecordCount = !tOpts.hideRecordCount;
|
|
5705
|
-
return /* @__PURE__ */ import_react25.default.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, !tOpts.hideHeader && /* @__PURE__ */ import_react25.default.createElement("div", { className: `dg-header${customToolbar ? " dg-header--custom" : ""}` }, !customToolbar && (showTitle || showRecordCount) && /* @__PURE__ */ import_react25.default.createElement("div", { className: "dg-header-info" }, showTitle && /* @__PURE__ */ import_react25.default.createElement("h2", null, title), showRecordCount && /* @__PURE__ */ import_react25.default.createElement("p", null, filteredData.length, " total records")), /* @__PURE__ */ import_react25.default.createElement("div", { className: "dg-header-actions" }, customToolbar ?? /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, showSearch && /* @__PURE__ */ import_react25.default.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ import_react25.default.createElement(Search, { size: 15 }), /* @__PURE__ */ import_react25.default.createElement(
|
|
5705
|
+
return /* @__PURE__ */ import_react25.default.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, !tOpts.hideHeader && /* @__PURE__ */ import_react25.default.createElement("div", { className: `dg-header${customToolbar ? " dg-header--custom" : ""}` }, !customToolbar && (showTitle || showRecordCount) && /* @__PURE__ */ import_react25.default.createElement("div", { className: "dg-header-info" }, showTitle && /* @__PURE__ */ import_react25.default.createElement("h2", null, title), showRecordCount && /* @__PURE__ */ import_react25.default.createElement("p", null, isServer ? totalRows : filteredData.length, " total records")), /* @__PURE__ */ import_react25.default.createElement("div", { className: "dg-header-actions" }, customToolbar ?? /* @__PURE__ */ import_react25.default.createElement(import_react25.default.Fragment, null, showSearch && /* @__PURE__ */ import_react25.default.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ import_react25.default.createElement(Search, { size: 15 }), /* @__PURE__ */ import_react25.default.createElement(
|
|
5706
5706
|
"input",
|
|
5707
5707
|
{
|
|
5708
5708
|
className: "dg-search",
|
|
@@ -10665,6 +10665,14 @@ function buildLookup(options, getChildren, getValue, map = /* @__PURE__ */ new M
|
|
|
10665
10665
|
}
|
|
10666
10666
|
return map;
|
|
10667
10667
|
}
|
|
10668
|
+
function safeLabel(getOptionLabel, option) {
|
|
10669
|
+
try {
|
|
10670
|
+
const l = getOptionLabel(option);
|
|
10671
|
+
return typeof l === "string" ? l : "";
|
|
10672
|
+
} catch {
|
|
10673
|
+
return "";
|
|
10674
|
+
}
|
|
10675
|
+
}
|
|
10668
10676
|
function SmartSelect({
|
|
10669
10677
|
options,
|
|
10670
10678
|
value,
|
|
@@ -10681,6 +10689,7 @@ function SmartSelect({
|
|
|
10681
10689
|
getOptionChildren,
|
|
10682
10690
|
multiple = false,
|
|
10683
10691
|
allowChildNodesSelection = true,
|
|
10692
|
+
strictSelection = false,
|
|
10684
10693
|
loading = false,
|
|
10685
10694
|
loadingText,
|
|
10686
10695
|
filterOptions: filterOptionsProp,
|
|
@@ -10704,15 +10713,6 @@ function SmartSelect({
|
|
|
10704
10713
|
(0, import_react54.useEffect)(() => () => {
|
|
10705
10714
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
10706
10715
|
}, []);
|
|
10707
|
-
const [internalInput, setInternalInput] = (0, import_react54.useState)(
|
|
10708
|
-
() => !multiple && value != null ? getOptionLabel(value) : ""
|
|
10709
|
-
);
|
|
10710
|
-
(0, import_react54.useEffect)(() => {
|
|
10711
|
-
if (!isControlled && !multiple) {
|
|
10712
|
-
setInternalInput(value != null ? getOptionLabel(value) : "");
|
|
10713
|
-
}
|
|
10714
|
-
}, [value, multiple, getOptionLabel, isControlled]);
|
|
10715
|
-
const activeInput = isControlled ? inputValueProp : internalInput;
|
|
10716
10716
|
const getValue = (0, import_react54.useCallback)(
|
|
10717
10717
|
(o) => getOptionValue ? getOptionValue(o) : String(getOptionLabel(o)),
|
|
10718
10718
|
[getOptionValue, getOptionLabel]
|
|
@@ -10722,6 +10722,55 @@ function SmartSelect({
|
|
|
10722
10722
|
return flattenTree(options, getOptionChildren);
|
|
10723
10723
|
}, [options, getOptionChildren]);
|
|
10724
10724
|
const flatOptionsList = (0, import_react54.useMemo)(() => flatItems.map((f) => f.option), [flatItems]);
|
|
10725
|
+
const strictValidation = (0, import_react54.useMemo)(() => {
|
|
10726
|
+
if (!strictSelection || multiple) return { valid: true, canonicalValue: value };
|
|
10727
|
+
if (value == null || value === "") {
|
|
10728
|
+
return { valid: false, displayText: "" };
|
|
10729
|
+
}
|
|
10730
|
+
const invalidDisplayText = (v) => {
|
|
10731
|
+
const fromLabel = safeLabel(getOptionLabel, v).trim();
|
|
10732
|
+
if (fromLabel) return fromLabel;
|
|
10733
|
+
if (typeof v === "string" || typeof v === "number") return String(v);
|
|
10734
|
+
return "";
|
|
10735
|
+
};
|
|
10736
|
+
try {
|
|
10737
|
+
const key = getValue(value);
|
|
10738
|
+
const canonicalOpt = flatOptionsList.find((o) => getValue(o) === key) ?? searchResults.find((o) => getValue(o) === key);
|
|
10739
|
+
if (!canonicalOpt) {
|
|
10740
|
+
return { valid: false, displayText: invalidDisplayText(value) };
|
|
10741
|
+
}
|
|
10742
|
+
if (typeof canonicalOpt === "object" && canonicalOpt !== null && typeof value === "object" && value !== null) {
|
|
10743
|
+
const src = canonicalOpt;
|
|
10744
|
+
const inc = value;
|
|
10745
|
+
const fullMatch = Object.keys(src).every((k) => k in inc && inc[k] === src[k]);
|
|
10746
|
+
if (!fullMatch) {
|
|
10747
|
+
return { valid: false, displayText: invalidDisplayText(value) };
|
|
10748
|
+
}
|
|
10749
|
+
}
|
|
10750
|
+
return { valid: true, canonicalValue: canonicalOpt };
|
|
10751
|
+
} catch {
|
|
10752
|
+
return { valid: false, displayText: invalidDisplayText(value) };
|
|
10753
|
+
}
|
|
10754
|
+
}, [strictSelection, multiple, value, getValue, flatOptionsList, searchResults, getOptionLabel]);
|
|
10755
|
+
const [internalInput, setInternalInput] = (0, import_react54.useState)(
|
|
10756
|
+
() => !multiple && value != null ? getOptionLabel(value) : ""
|
|
10757
|
+
);
|
|
10758
|
+
const strictValidationRef = (0, import_react54.useRef)(strictValidation);
|
|
10759
|
+
strictValidationRef.current = strictValidation;
|
|
10760
|
+
const lastSeededValue = (0, import_react54.useRef)(/* @__PURE__ */ Symbol("init"));
|
|
10761
|
+
(0, import_react54.useEffect)(() => {
|
|
10762
|
+
if (isControlled || multiple) return;
|
|
10763
|
+
if (strictSelection && !strictValidationRef.current.valid) {
|
|
10764
|
+
if (Object.is(value, lastSeededValue.current)) return;
|
|
10765
|
+
lastSeededValue.current = value;
|
|
10766
|
+
const sv = strictValidationRef.current;
|
|
10767
|
+
setInternalInput(sv.displayText);
|
|
10768
|
+
return;
|
|
10769
|
+
}
|
|
10770
|
+
lastSeededValue.current = value;
|
|
10771
|
+
setInternalInput(value != null ? getOptionLabel(value) : "");
|
|
10772
|
+
}, [value, multiple, getOptionLabel, isControlled, strictSelection]);
|
|
10773
|
+
const activeInput = isControlled ? inputValueProp : internalInput;
|
|
10725
10774
|
const displayOptions = (0, import_react54.useMemo)(() => {
|
|
10726
10775
|
let base = flatOptionsList;
|
|
10727
10776
|
if (searchResults.length) {
|
|
@@ -10729,17 +10778,26 @@ function SmartSelect({
|
|
|
10729
10778
|
const serverOnly = searchResults.filter((o) => !localKeys.has(getValue(o)));
|
|
10730
10779
|
base = [...flatOptionsList, ...serverOnly];
|
|
10731
10780
|
}
|
|
10732
|
-
if (!multiple
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10781
|
+
if (!multiple) {
|
|
10782
|
+
if (strictSelection) {
|
|
10783
|
+
const injectValue = strictValidation.valid ? strictValidation.canonicalValue : null;
|
|
10784
|
+
if (injectValue != null) {
|
|
10785
|
+
const key = getValue(injectValue);
|
|
10786
|
+
if (!base.some((o) => getValue(o) === key)) base = [injectValue, ...base];
|
|
10787
|
+
}
|
|
10788
|
+
} else {
|
|
10789
|
+
if (value != null) {
|
|
10790
|
+
const key = getValue(value);
|
|
10791
|
+
if (!base.some((o) => getValue(o) === key)) base = [value, ...base];
|
|
10792
|
+
}
|
|
10793
|
+
}
|
|
10794
|
+
} else if (Array.isArray(value) && value.length > 0) {
|
|
10737
10795
|
const baseKeys = new Set(base.map((o) => getValue(o)));
|
|
10738
10796
|
const missing = value.filter((v) => !baseKeys.has(getValue(v)));
|
|
10739
10797
|
if (missing.length > 0) base = [...base, ...missing];
|
|
10740
10798
|
}
|
|
10741
10799
|
return base;
|
|
10742
|
-
}, [flatOptionsList, searchResults, getValue, value, multiple]);
|
|
10800
|
+
}, [flatOptionsList, searchResults, getValue, value, multiple, strictSelection, strictValidation]);
|
|
10743
10801
|
const depthMap = (0, import_react54.useMemo)(() => {
|
|
10744
10802
|
const map = /* @__PURE__ */ new Map();
|
|
10745
10803
|
flatItems.forEach(({ option, depth }) => map.set(getValue(option), depth));
|
|
@@ -10753,13 +10811,31 @@ function SmartSelect({
|
|
|
10753
10811
|
if (multiple) {
|
|
10754
10812
|
return new Set((Array.isArray(value) ? value : []).map((v) => getValue(v)));
|
|
10755
10813
|
}
|
|
10814
|
+
if (strictSelection) {
|
|
10815
|
+
const sv = strictValidation;
|
|
10816
|
+
if (!strictValidation.valid || sv.canonicalValue == null) return /* @__PURE__ */ new Set();
|
|
10817
|
+
return /* @__PURE__ */ new Set([getValue(sv.canonicalValue)]);
|
|
10818
|
+
}
|
|
10756
10819
|
return value != null ? /* @__PURE__ */ new Set([getValue(value)]) : /* @__PURE__ */ new Set();
|
|
10757
|
-
}, [multiple, value, getValue]);
|
|
10820
|
+
}, [multiple, value, getValue, strictSelection, strictValidation]);
|
|
10821
|
+
let autocompleteValue;
|
|
10822
|
+
let autocompleteInputValue;
|
|
10823
|
+
if (strictSelection && !multiple) {
|
|
10824
|
+
const sv = strictValidation;
|
|
10825
|
+
if (!strictValidation.valid) {
|
|
10826
|
+
autocompleteValue = null;
|
|
10827
|
+
autocompleteInputValue = isControlled ? inputValueProp : internalInput;
|
|
10828
|
+
} else {
|
|
10829
|
+
autocompleteValue = sv.canonicalValue ?? null;
|
|
10830
|
+
autocompleteInputValue = isControlled ? inputValueProp : activeInput;
|
|
10831
|
+
}
|
|
10832
|
+
} else {
|
|
10833
|
+
autocompleteValue = value ?? (multiple ? [] : null);
|
|
10834
|
+
autocompleteInputValue = multiple ? isControlled ? inputValueProp : void 0 : activeInput;
|
|
10835
|
+
}
|
|
10758
10836
|
const handleInputChange = (0, import_react54.useCallback)((_, val, reason) => {
|
|
10759
10837
|
const resolvedReason = reason ?? "input";
|
|
10760
|
-
if (!isControlled)
|
|
10761
|
-
setInternalInput(val);
|
|
10762
|
-
}
|
|
10838
|
+
if (!isControlled) setInternalInput(val);
|
|
10763
10839
|
onInputChange?.(val, resolvedReason);
|
|
10764
10840
|
if (!onSearchChange) return;
|
|
10765
10841
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
@@ -10781,9 +10857,7 @@ function SmartSelect({
|
|
|
10781
10857
|
if (debounceMs <= 0) {
|
|
10782
10858
|
onSearchChange(val, needed);
|
|
10783
10859
|
} else {
|
|
10784
|
-
debounceTimer.current = setTimeout(() =>
|
|
10785
|
-
onSearchChange(val, needed);
|
|
10786
|
-
}, debounceMs);
|
|
10860
|
+
debounceTimer.current = setTimeout(() => onSearchChange(val, needed), debounceMs);
|
|
10787
10861
|
}
|
|
10788
10862
|
}, [isControlled, onInputChange, onSearchChange, debounceMs, searchThreshold, flatOptionsList, getOptionLabel, getOptionSubLabel]);
|
|
10789
10863
|
const handleChange = (0, import_react54.useCallback)((_, newValue) => {
|
|
@@ -10863,6 +10937,14 @@ function SmartSelect({
|
|
|
10863
10937
|
}, [depthMap, getValue, getOptionLabel, getOptionSubLabel, selectedKeys]);
|
|
10864
10938
|
const computedFilterOptions = (0, import_react54.useCallback)((opts, inputVal) => {
|
|
10865
10939
|
if (filterOptionsProp) return filterOptionsProp(opts, inputVal);
|
|
10940
|
+
if (strictSelection && !strictValidation.valid) {
|
|
10941
|
+
const sv = strictValidation;
|
|
10942
|
+
if (!inputVal || inputVal === sv.displayText) return opts;
|
|
10943
|
+
const q2 = inputVal.toLowerCase();
|
|
10944
|
+
return opts.filter(
|
|
10945
|
+
(opt) => getOptionLabel(opt).toLowerCase().includes(q2) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q2)
|
|
10946
|
+
).slice(0, searchThreshold);
|
|
10947
|
+
}
|
|
10866
10948
|
if (multiple) {
|
|
10867
10949
|
const selected = opts.filter((o) => selectedKeys.has(getValue(o)));
|
|
10868
10950
|
const unselected = opts.filter((o) => !selectedKeys.has(getValue(o)));
|
|
@@ -10873,11 +10955,12 @@ function SmartSelect({
|
|
|
10873
10955
|
).slice(0, searchThreshold);
|
|
10874
10956
|
return [...selected, ...filteredUnselected];
|
|
10875
10957
|
}
|
|
10876
|
-
|
|
10877
|
-
|
|
10878
|
-
const
|
|
10958
|
+
const effectiveVal = strictSelection ? strictValidation.canonicalValue : value;
|
|
10959
|
+
if (effectiveVal != null) {
|
|
10960
|
+
const selectedKey = getValue(effectiveVal);
|
|
10961
|
+
const selectedLabel = getOptionLabel(effectiveVal);
|
|
10879
10962
|
const inOpts = opts.some((o) => getValue(o) === selectedKey);
|
|
10880
|
-
const selectedFallback = inOpts ? [] : [
|
|
10963
|
+
const selectedFallback = inOpts ? [] : [effectiveVal];
|
|
10881
10964
|
if (!inputVal || inputVal === selectedLabel) {
|
|
10882
10965
|
return [
|
|
10883
10966
|
...selectedFallback,
|
|
@@ -10891,21 +10974,27 @@ function SmartSelect({
|
|
|
10891
10974
|
return opts.filter(
|
|
10892
10975
|
(opt) => getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)
|
|
10893
10976
|
).slice(0, searchThreshold);
|
|
10894
|
-
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value, searchThreshold]);
|
|
10977
|
+
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value, searchThreshold, strictSelection, strictValidation]);
|
|
10895
10978
|
return /* @__PURE__ */ import_react54.default.createElement(
|
|
10896
10979
|
Autocomplete,
|
|
10897
10980
|
{
|
|
10898
10981
|
options: displayOptions,
|
|
10899
|
-
value:
|
|
10982
|
+
value: autocompleteValue,
|
|
10900
10983
|
onChange: handleChange,
|
|
10901
|
-
inputValue:
|
|
10984
|
+
inputValue: autocompleteInputValue,
|
|
10902
10985
|
onInputChange: handleInputChange,
|
|
10903
10986
|
multiple,
|
|
10904
10987
|
limitTags,
|
|
10905
10988
|
loading,
|
|
10906
10989
|
loadingText: loadingText ?? /* @__PURE__ */ import_react54.default.createElement("span", { style: { fontSize: "0.875rem", color: "var(--text-secondary)" } }, "Loading\u2026"),
|
|
10907
10990
|
getOptionLabel,
|
|
10908
|
-
isOptionEqualToValue: (opt, val) =>
|
|
10991
|
+
isOptionEqualToValue: (opt, val) => {
|
|
10992
|
+
try {
|
|
10993
|
+
return getValue(opt) === getValue(val);
|
|
10994
|
+
} catch {
|
|
10995
|
+
return false;
|
|
10996
|
+
}
|
|
10997
|
+
},
|
|
10909
10998
|
filterOptions: computedFilterOptions,
|
|
10910
10999
|
renderOption: renderOptionProp ?? defaultRenderOption,
|
|
10911
11000
|
label,
|
package/dist/main.d.cts
CHANGED
|
@@ -2264,8 +2264,7 @@ interface SmartSelectProps<T = any> {
|
|
|
2264
2264
|
onInputChange?: (value: string, reason: 'input' | 'reset' | 'clear') => void;
|
|
2265
2265
|
/**
|
|
2266
2266
|
* Called when local matches fall below `searchThreshold`.
|
|
2267
|
-
* Receives the current query and how many more records are needed
|
|
2268
|
-
* Use this to trigger an API / server search and update `searchResults`.
|
|
2267
|
+
* Receives the current query and how many more records are needed.
|
|
2269
2268
|
*/
|
|
2270
2269
|
onSearchChange?: (query: string, needed: number) => void;
|
|
2271
2270
|
/**
|
|
@@ -2275,14 +2274,14 @@ interface SmartSelectProps<T = any> {
|
|
|
2275
2274
|
*/
|
|
2276
2275
|
searchResults?: T[];
|
|
2277
2276
|
/**
|
|
2278
|
-
* Debounce delay in ms before `onSearchChange` fires.
|
|
2279
|
-
*
|
|
2277
|
+
* Debounce delay in ms before `onSearchChange` fires. Default: 300.
|
|
2278
|
+
* Pass 0 to disable.
|
|
2280
2279
|
*/
|
|
2281
2280
|
debounceMs?: number;
|
|
2282
2281
|
/**
|
|
2283
2282
|
* Max results to show when a query is active.
|
|
2284
|
-
*
|
|
2285
|
-
*
|
|
2283
|
+
* `onSearchChange` fires only when local matches < this threshold.
|
|
2284
|
+
* Default: 10. Pass 0 to always call the API.
|
|
2286
2285
|
*/
|
|
2287
2286
|
searchThreshold?: number;
|
|
2288
2287
|
/** Primary display label for an option (required) */
|
|
@@ -2304,6 +2303,22 @@ interface SmartSelectProps<T = any> {
|
|
|
2304
2303
|
* Only relevant when getOptionChildren is provided and multiple is true.
|
|
2305
2304
|
*/
|
|
2306
2305
|
allowChildNodesSelection?: boolean;
|
|
2306
|
+
/**
|
|
2307
|
+
* When **true**, the incoming `value` is validated against the source options
|
|
2308
|
+
* before being used. Three cases are handled strictly:
|
|
2309
|
+
*
|
|
2310
|
+
* - **Case 1 — Empty**: `value` is `null`, `undefined`, or `""` → treated as no selection.
|
|
2311
|
+
* - **Case 2 — Missing**: value's key is not present in `options` or `searchResults`
|
|
2312
|
+
* → ignored; not injected into the dropdown list.
|
|
2313
|
+
* - **Case 3 — Incomplete**: value's key exists in the source but the canonical source
|
|
2314
|
+
* option returns an empty label from `getOptionLabel` → not treated as selected.
|
|
2315
|
+
*
|
|
2316
|
+
* When invalid, `null` is passed to Autocomplete (nothing selected) and the raw text
|
|
2317
|
+
* is shown in the input field. No `onChange` fires.
|
|
2318
|
+
*
|
|
2319
|
+
* Only applies to single-select mode. Default: **false**.
|
|
2320
|
+
*/
|
|
2321
|
+
strictSelection?: boolean;
|
|
2307
2322
|
/** Show a loading spinner in the dropdown */
|
|
2308
2323
|
loading?: boolean;
|
|
2309
2324
|
/** Content shown while loading */
|
|
@@ -2338,7 +2353,7 @@ interface SmartSelectProps<T = any> {
|
|
|
2338
2353
|
style?: CSSProperties;
|
|
2339
2354
|
sx?: SxProp;
|
|
2340
2355
|
}
|
|
2341
|
-
declare function SmartSelect<T = any>({ options, value, onChange, inputValue: inputValueProp, onInputChange, onSearchChange, searchResults, debounceMs, searchThreshold, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
2356
|
+
declare function SmartSelect<T = any>({ options, value, onChange, inputValue: inputValueProp, onInputChange, onSearchChange, searchResults, debounceMs, searchThreshold, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, strictSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
2342
2357
|
|
|
2343
2358
|
type ToolbarButton = 'undo' | 'redo' | 'ai' | 'paragraph' | 'fontsize' | 'font' | 'color' | 'bold' | 'italic' | 'strike' | 'link' | 'lineheight' | 'ul' | 'ol' | 'align' | 'indent' | 'outdent' | 'table' | 'image' | 'video' | 'cut' | 'copy' | 'paste' | 'specialchars' | 'code' | 'fullscreen' | 'tts' | 'stt' | 'translate' | 'todo' | '|';
|
|
2344
2359
|
type EditorVariant = 'default' | 'basic';
|
package/dist/main.d.ts
CHANGED
|
@@ -2264,8 +2264,7 @@ interface SmartSelectProps<T = any> {
|
|
|
2264
2264
|
onInputChange?: (value: string, reason: 'input' | 'reset' | 'clear') => void;
|
|
2265
2265
|
/**
|
|
2266
2266
|
* Called when local matches fall below `searchThreshold`.
|
|
2267
|
-
* Receives the current query and how many more records are needed
|
|
2268
|
-
* Use this to trigger an API / server search and update `searchResults`.
|
|
2267
|
+
* Receives the current query and how many more records are needed.
|
|
2269
2268
|
*/
|
|
2270
2269
|
onSearchChange?: (query: string, needed: number) => void;
|
|
2271
2270
|
/**
|
|
@@ -2275,14 +2274,14 @@ interface SmartSelectProps<T = any> {
|
|
|
2275
2274
|
*/
|
|
2276
2275
|
searchResults?: T[];
|
|
2277
2276
|
/**
|
|
2278
|
-
* Debounce delay in ms before `onSearchChange` fires.
|
|
2279
|
-
*
|
|
2277
|
+
* Debounce delay in ms before `onSearchChange` fires. Default: 300.
|
|
2278
|
+
* Pass 0 to disable.
|
|
2280
2279
|
*/
|
|
2281
2280
|
debounceMs?: number;
|
|
2282
2281
|
/**
|
|
2283
2282
|
* Max results to show when a query is active.
|
|
2284
|
-
*
|
|
2285
|
-
*
|
|
2283
|
+
* `onSearchChange` fires only when local matches < this threshold.
|
|
2284
|
+
* Default: 10. Pass 0 to always call the API.
|
|
2286
2285
|
*/
|
|
2287
2286
|
searchThreshold?: number;
|
|
2288
2287
|
/** Primary display label for an option (required) */
|
|
@@ -2304,6 +2303,22 @@ interface SmartSelectProps<T = any> {
|
|
|
2304
2303
|
* Only relevant when getOptionChildren is provided and multiple is true.
|
|
2305
2304
|
*/
|
|
2306
2305
|
allowChildNodesSelection?: boolean;
|
|
2306
|
+
/**
|
|
2307
|
+
* When **true**, the incoming `value` is validated against the source options
|
|
2308
|
+
* before being used. Three cases are handled strictly:
|
|
2309
|
+
*
|
|
2310
|
+
* - **Case 1 — Empty**: `value` is `null`, `undefined`, or `""` → treated as no selection.
|
|
2311
|
+
* - **Case 2 — Missing**: value's key is not present in `options` or `searchResults`
|
|
2312
|
+
* → ignored; not injected into the dropdown list.
|
|
2313
|
+
* - **Case 3 — Incomplete**: value's key exists in the source but the canonical source
|
|
2314
|
+
* option returns an empty label from `getOptionLabel` → not treated as selected.
|
|
2315
|
+
*
|
|
2316
|
+
* When invalid, `null` is passed to Autocomplete (nothing selected) and the raw text
|
|
2317
|
+
* is shown in the input field. No `onChange` fires.
|
|
2318
|
+
*
|
|
2319
|
+
* Only applies to single-select mode. Default: **false**.
|
|
2320
|
+
*/
|
|
2321
|
+
strictSelection?: boolean;
|
|
2307
2322
|
/** Show a loading spinner in the dropdown */
|
|
2308
2323
|
loading?: boolean;
|
|
2309
2324
|
/** Content shown while loading */
|
|
@@ -2338,7 +2353,7 @@ interface SmartSelectProps<T = any> {
|
|
|
2338
2353
|
style?: CSSProperties;
|
|
2339
2354
|
sx?: SxProp;
|
|
2340
2355
|
}
|
|
2341
|
-
declare function SmartSelect<T = any>({ options, value, onChange, inputValue: inputValueProp, onInputChange, onSearchChange, searchResults, debounceMs, searchThreshold, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
2356
|
+
declare function SmartSelect<T = any>({ options, value, onChange, inputValue: inputValueProp, onInputChange, onSearchChange, searchResults, debounceMs, searchThreshold, getOptionLabel, getOptionValue, getOptionSubLabel, getOptionChildren, multiple, allowChildNodesSelection, strictSelection, loading, loadingText, filterOptions: filterOptionsProp, renderOption: renderOptionProp, limitTags, label, placeholder, variant, size, disabled, error, helperText, fullWidth, required, className, style, sx, }: SmartSelectProps<T>): React__default.JSX.Element;
|
|
2342
2357
|
|
|
2343
2358
|
type ToolbarButton = 'undo' | 'redo' | 'ai' | 'paragraph' | 'fontsize' | 'font' | 'color' | 'bold' | 'italic' | 'strike' | 'link' | 'lineheight' | 'ul' | 'ol' | 'align' | 'indent' | 'outdent' | 'table' | 'image' | 'video' | 'cut' | 'copy' | 'paste' | 'specialchars' | 'code' | 'fullscreen' | 'tts' | 'stt' | 'translate' | 'todo' | '|';
|
|
2344
2359
|
type EditorVariant = 'default' | 'basic';
|
package/dist/main.js
CHANGED
|
@@ -1209,14 +1209,14 @@ var SubmitButton = ({
|
|
|
1209
1209
|
setLoading(false);
|
|
1210
1210
|
}
|
|
1211
1211
|
};
|
|
1212
|
-
const handleClick = (e) => runProtected(e, onClick);
|
|
1213
|
-
const handleDoubleClick = (e) => runProtected(e, onDoubleClick);
|
|
1212
|
+
const handleClick = onClick ? (e) => runProtected(e, onClick) : void 0;
|
|
1213
|
+
const handleDoubleClick = onDoubleClick ? (e) => runProtected(e, onDoubleClick) : void 0;
|
|
1214
1214
|
const showLoader = loading || isLoading;
|
|
1215
1215
|
return /* @__PURE__ */ React60.createElement(
|
|
1216
1216
|
"button",
|
|
1217
1217
|
{
|
|
1218
1218
|
...props,
|
|
1219
|
-
type
|
|
1219
|
+
type,
|
|
1220
1220
|
className: ["btn submit-btn", bgGradiant ? "submit-btn-gradiant" : "", sxClass, className].filter(Boolean).join(" "),
|
|
1221
1221
|
disabled: props.disabled || showLoader,
|
|
1222
1222
|
onClick: handleClick,
|
|
@@ -5370,8 +5370,8 @@ function DataGrid({
|
|
|
5370
5370
|
const totalRows = isServer ? rowCount ?? data.length : flatEntries ? flatEntries.length : filteredData.length;
|
|
5371
5371
|
const totalPages = Math.max(1, Math.ceil(totalRows / activePageSize));
|
|
5372
5372
|
const displayRows = useMemo2(() => {
|
|
5373
|
-
if (isServer) return data.map((row) => ({ kind: "data", row, depth: 0 }));
|
|
5374
5373
|
const source = flatEntries ?? sortedData.map((row) => ({ kind: "data", row, depth: 0 }));
|
|
5374
|
+
if (isServer) return source;
|
|
5375
5375
|
const start = (activePage - 1) * activePageSize;
|
|
5376
5376
|
return source.slice(start, start + activePageSize);
|
|
5377
5377
|
}, [isServer, data, flatEntries, sortedData, activePage, activePageSize]);
|
|
@@ -5516,7 +5516,7 @@ function DataGrid({
|
|
|
5516
5516
|
const showExportBtn = !tOpts.hideExport && !hideTopExport;
|
|
5517
5517
|
const showTitle = !tOpts.hideTitle;
|
|
5518
5518
|
const showRecordCount = !tOpts.hideRecordCount;
|
|
5519
|
-
return /* @__PURE__ */ React75.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, !tOpts.hideHeader && /* @__PURE__ */ React75.createElement("div", { className: `dg-header${customToolbar ? " dg-header--custom" : ""}` }, !customToolbar && (showTitle || showRecordCount) && /* @__PURE__ */ React75.createElement("div", { className: "dg-header-info" }, showTitle && /* @__PURE__ */ React75.createElement("h2", null, title), showRecordCount && /* @__PURE__ */ React75.createElement("p", null, filteredData.length, " total records")), /* @__PURE__ */ React75.createElement("div", { className: "dg-header-actions" }, customToolbar ?? /* @__PURE__ */ React75.createElement(React75.Fragment, null, showSearch && /* @__PURE__ */ React75.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ React75.createElement(Search, { size: 15 }), /* @__PURE__ */ React75.createElement(
|
|
5519
|
+
return /* @__PURE__ */ React75.createElement("div", { className: ["dg-root", sxClass, className].filter(Boolean).join(" ") }, !tOpts.hideHeader && /* @__PURE__ */ React75.createElement("div", { className: `dg-header${customToolbar ? " dg-header--custom" : ""}` }, !customToolbar && (showTitle || showRecordCount) && /* @__PURE__ */ React75.createElement("div", { className: "dg-header-info" }, showTitle && /* @__PURE__ */ React75.createElement("h2", null, title), showRecordCount && /* @__PURE__ */ React75.createElement("p", null, isServer ? totalRows : filteredData.length, " total records")), /* @__PURE__ */ React75.createElement("div", { className: "dg-header-actions" }, customToolbar ?? /* @__PURE__ */ React75.createElement(React75.Fragment, null, showSearch && /* @__PURE__ */ React75.createElement("div", { className: "dg-search-wrap" }, /* @__PURE__ */ React75.createElement(Search, { size: 15 }), /* @__PURE__ */ React75.createElement(
|
|
5520
5520
|
"input",
|
|
5521
5521
|
{
|
|
5522
5522
|
className: "dg-search",
|
|
@@ -10548,6 +10548,14 @@ function buildLookup(options, getChildren, getValue, map = /* @__PURE__ */ new M
|
|
|
10548
10548
|
}
|
|
10549
10549
|
return map;
|
|
10550
10550
|
}
|
|
10551
|
+
function safeLabel(getOptionLabel, option) {
|
|
10552
|
+
try {
|
|
10553
|
+
const l = getOptionLabel(option);
|
|
10554
|
+
return typeof l === "string" ? l : "";
|
|
10555
|
+
} catch {
|
|
10556
|
+
return "";
|
|
10557
|
+
}
|
|
10558
|
+
}
|
|
10551
10559
|
function SmartSelect({
|
|
10552
10560
|
options,
|
|
10553
10561
|
value,
|
|
@@ -10564,6 +10572,7 @@ function SmartSelect({
|
|
|
10564
10572
|
getOptionChildren,
|
|
10565
10573
|
multiple = false,
|
|
10566
10574
|
allowChildNodesSelection = true,
|
|
10575
|
+
strictSelection = false,
|
|
10567
10576
|
loading = false,
|
|
10568
10577
|
loadingText,
|
|
10569
10578
|
filterOptions: filterOptionsProp,
|
|
@@ -10587,15 +10596,6 @@ function SmartSelect({
|
|
|
10587
10596
|
useEffect21(() => () => {
|
|
10588
10597
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
10589
10598
|
}, []);
|
|
10590
|
-
const [internalInput, setInternalInput] = useState27(
|
|
10591
|
-
() => !multiple && value != null ? getOptionLabel(value) : ""
|
|
10592
|
-
);
|
|
10593
|
-
useEffect21(() => {
|
|
10594
|
-
if (!isControlled && !multiple) {
|
|
10595
|
-
setInternalInput(value != null ? getOptionLabel(value) : "");
|
|
10596
|
-
}
|
|
10597
|
-
}, [value, multiple, getOptionLabel, isControlled]);
|
|
10598
|
-
const activeInput = isControlled ? inputValueProp : internalInput;
|
|
10599
10599
|
const getValue = useCallback12(
|
|
10600
10600
|
(o) => getOptionValue ? getOptionValue(o) : String(getOptionLabel(o)),
|
|
10601
10601
|
[getOptionValue, getOptionLabel]
|
|
@@ -10605,6 +10605,55 @@ function SmartSelect({
|
|
|
10605
10605
|
return flattenTree(options, getOptionChildren);
|
|
10606
10606
|
}, [options, getOptionChildren]);
|
|
10607
10607
|
const flatOptionsList = useMemo3(() => flatItems.map((f) => f.option), [flatItems]);
|
|
10608
|
+
const strictValidation = useMemo3(() => {
|
|
10609
|
+
if (!strictSelection || multiple) return { valid: true, canonicalValue: value };
|
|
10610
|
+
if (value == null || value === "") {
|
|
10611
|
+
return { valid: false, displayText: "" };
|
|
10612
|
+
}
|
|
10613
|
+
const invalidDisplayText = (v) => {
|
|
10614
|
+
const fromLabel = safeLabel(getOptionLabel, v).trim();
|
|
10615
|
+
if (fromLabel) return fromLabel;
|
|
10616
|
+
if (typeof v === "string" || typeof v === "number") return String(v);
|
|
10617
|
+
return "";
|
|
10618
|
+
};
|
|
10619
|
+
try {
|
|
10620
|
+
const key = getValue(value);
|
|
10621
|
+
const canonicalOpt = flatOptionsList.find((o) => getValue(o) === key) ?? searchResults.find((o) => getValue(o) === key);
|
|
10622
|
+
if (!canonicalOpt) {
|
|
10623
|
+
return { valid: false, displayText: invalidDisplayText(value) };
|
|
10624
|
+
}
|
|
10625
|
+
if (typeof canonicalOpt === "object" && canonicalOpt !== null && typeof value === "object" && value !== null) {
|
|
10626
|
+
const src = canonicalOpt;
|
|
10627
|
+
const inc = value;
|
|
10628
|
+
const fullMatch = Object.keys(src).every((k) => k in inc && inc[k] === src[k]);
|
|
10629
|
+
if (!fullMatch) {
|
|
10630
|
+
return { valid: false, displayText: invalidDisplayText(value) };
|
|
10631
|
+
}
|
|
10632
|
+
}
|
|
10633
|
+
return { valid: true, canonicalValue: canonicalOpt };
|
|
10634
|
+
} catch {
|
|
10635
|
+
return { valid: false, displayText: invalidDisplayText(value) };
|
|
10636
|
+
}
|
|
10637
|
+
}, [strictSelection, multiple, value, getValue, flatOptionsList, searchResults, getOptionLabel]);
|
|
10638
|
+
const [internalInput, setInternalInput] = useState27(
|
|
10639
|
+
() => !multiple && value != null ? getOptionLabel(value) : ""
|
|
10640
|
+
);
|
|
10641
|
+
const strictValidationRef = useRef25(strictValidation);
|
|
10642
|
+
strictValidationRef.current = strictValidation;
|
|
10643
|
+
const lastSeededValue = useRef25(/* @__PURE__ */ Symbol("init"));
|
|
10644
|
+
useEffect21(() => {
|
|
10645
|
+
if (isControlled || multiple) return;
|
|
10646
|
+
if (strictSelection && !strictValidationRef.current.valid) {
|
|
10647
|
+
if (Object.is(value, lastSeededValue.current)) return;
|
|
10648
|
+
lastSeededValue.current = value;
|
|
10649
|
+
const sv = strictValidationRef.current;
|
|
10650
|
+
setInternalInput(sv.displayText);
|
|
10651
|
+
return;
|
|
10652
|
+
}
|
|
10653
|
+
lastSeededValue.current = value;
|
|
10654
|
+
setInternalInput(value != null ? getOptionLabel(value) : "");
|
|
10655
|
+
}, [value, multiple, getOptionLabel, isControlled, strictSelection]);
|
|
10656
|
+
const activeInput = isControlled ? inputValueProp : internalInput;
|
|
10608
10657
|
const displayOptions = useMemo3(() => {
|
|
10609
10658
|
let base = flatOptionsList;
|
|
10610
10659
|
if (searchResults.length) {
|
|
@@ -10612,17 +10661,26 @@ function SmartSelect({
|
|
|
10612
10661
|
const serverOnly = searchResults.filter((o) => !localKeys.has(getValue(o)));
|
|
10613
10662
|
base = [...flatOptionsList, ...serverOnly];
|
|
10614
10663
|
}
|
|
10615
|
-
if (!multiple
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
10664
|
+
if (!multiple) {
|
|
10665
|
+
if (strictSelection) {
|
|
10666
|
+
const injectValue = strictValidation.valid ? strictValidation.canonicalValue : null;
|
|
10667
|
+
if (injectValue != null) {
|
|
10668
|
+
const key = getValue(injectValue);
|
|
10669
|
+
if (!base.some((o) => getValue(o) === key)) base = [injectValue, ...base];
|
|
10670
|
+
}
|
|
10671
|
+
} else {
|
|
10672
|
+
if (value != null) {
|
|
10673
|
+
const key = getValue(value);
|
|
10674
|
+
if (!base.some((o) => getValue(o) === key)) base = [value, ...base];
|
|
10675
|
+
}
|
|
10676
|
+
}
|
|
10677
|
+
} else if (Array.isArray(value) && value.length > 0) {
|
|
10620
10678
|
const baseKeys = new Set(base.map((o) => getValue(o)));
|
|
10621
10679
|
const missing = value.filter((v) => !baseKeys.has(getValue(v)));
|
|
10622
10680
|
if (missing.length > 0) base = [...base, ...missing];
|
|
10623
10681
|
}
|
|
10624
10682
|
return base;
|
|
10625
|
-
}, [flatOptionsList, searchResults, getValue, value, multiple]);
|
|
10683
|
+
}, [flatOptionsList, searchResults, getValue, value, multiple, strictSelection, strictValidation]);
|
|
10626
10684
|
const depthMap = useMemo3(() => {
|
|
10627
10685
|
const map = /* @__PURE__ */ new Map();
|
|
10628
10686
|
flatItems.forEach(({ option, depth }) => map.set(getValue(option), depth));
|
|
@@ -10636,13 +10694,31 @@ function SmartSelect({
|
|
|
10636
10694
|
if (multiple) {
|
|
10637
10695
|
return new Set((Array.isArray(value) ? value : []).map((v) => getValue(v)));
|
|
10638
10696
|
}
|
|
10697
|
+
if (strictSelection) {
|
|
10698
|
+
const sv = strictValidation;
|
|
10699
|
+
if (!strictValidation.valid || sv.canonicalValue == null) return /* @__PURE__ */ new Set();
|
|
10700
|
+
return /* @__PURE__ */ new Set([getValue(sv.canonicalValue)]);
|
|
10701
|
+
}
|
|
10639
10702
|
return value != null ? /* @__PURE__ */ new Set([getValue(value)]) : /* @__PURE__ */ new Set();
|
|
10640
|
-
}, [multiple, value, getValue]);
|
|
10703
|
+
}, [multiple, value, getValue, strictSelection, strictValidation]);
|
|
10704
|
+
let autocompleteValue;
|
|
10705
|
+
let autocompleteInputValue;
|
|
10706
|
+
if (strictSelection && !multiple) {
|
|
10707
|
+
const sv = strictValidation;
|
|
10708
|
+
if (!strictValidation.valid) {
|
|
10709
|
+
autocompleteValue = null;
|
|
10710
|
+
autocompleteInputValue = isControlled ? inputValueProp : internalInput;
|
|
10711
|
+
} else {
|
|
10712
|
+
autocompleteValue = sv.canonicalValue ?? null;
|
|
10713
|
+
autocompleteInputValue = isControlled ? inputValueProp : activeInput;
|
|
10714
|
+
}
|
|
10715
|
+
} else {
|
|
10716
|
+
autocompleteValue = value ?? (multiple ? [] : null);
|
|
10717
|
+
autocompleteInputValue = multiple ? isControlled ? inputValueProp : void 0 : activeInput;
|
|
10718
|
+
}
|
|
10641
10719
|
const handleInputChange = useCallback12((_, val, reason) => {
|
|
10642
10720
|
const resolvedReason = reason ?? "input";
|
|
10643
|
-
if (!isControlled)
|
|
10644
|
-
setInternalInput(val);
|
|
10645
|
-
}
|
|
10721
|
+
if (!isControlled) setInternalInput(val);
|
|
10646
10722
|
onInputChange?.(val, resolvedReason);
|
|
10647
10723
|
if (!onSearchChange) return;
|
|
10648
10724
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
@@ -10664,9 +10740,7 @@ function SmartSelect({
|
|
|
10664
10740
|
if (debounceMs <= 0) {
|
|
10665
10741
|
onSearchChange(val, needed);
|
|
10666
10742
|
} else {
|
|
10667
|
-
debounceTimer.current = setTimeout(() =>
|
|
10668
|
-
onSearchChange(val, needed);
|
|
10669
|
-
}, debounceMs);
|
|
10743
|
+
debounceTimer.current = setTimeout(() => onSearchChange(val, needed), debounceMs);
|
|
10670
10744
|
}
|
|
10671
10745
|
}, [isControlled, onInputChange, onSearchChange, debounceMs, searchThreshold, flatOptionsList, getOptionLabel, getOptionSubLabel]);
|
|
10672
10746
|
const handleChange = useCallback12((_, newValue) => {
|
|
@@ -10746,6 +10820,14 @@ function SmartSelect({
|
|
|
10746
10820
|
}, [depthMap, getValue, getOptionLabel, getOptionSubLabel, selectedKeys]);
|
|
10747
10821
|
const computedFilterOptions = useCallback12((opts, inputVal) => {
|
|
10748
10822
|
if (filterOptionsProp) return filterOptionsProp(opts, inputVal);
|
|
10823
|
+
if (strictSelection && !strictValidation.valid) {
|
|
10824
|
+
const sv = strictValidation;
|
|
10825
|
+
if (!inputVal || inputVal === sv.displayText) return opts;
|
|
10826
|
+
const q2 = inputVal.toLowerCase();
|
|
10827
|
+
return opts.filter(
|
|
10828
|
+
(opt) => getOptionLabel(opt).toLowerCase().includes(q2) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q2)
|
|
10829
|
+
).slice(0, searchThreshold);
|
|
10830
|
+
}
|
|
10749
10831
|
if (multiple) {
|
|
10750
10832
|
const selected = opts.filter((o) => selectedKeys.has(getValue(o)));
|
|
10751
10833
|
const unselected = opts.filter((o) => !selectedKeys.has(getValue(o)));
|
|
@@ -10756,11 +10838,12 @@ function SmartSelect({
|
|
|
10756
10838
|
).slice(0, searchThreshold);
|
|
10757
10839
|
return [...selected, ...filteredUnselected];
|
|
10758
10840
|
}
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
const
|
|
10841
|
+
const effectiveVal = strictSelection ? strictValidation.canonicalValue : value;
|
|
10842
|
+
if (effectiveVal != null) {
|
|
10843
|
+
const selectedKey = getValue(effectiveVal);
|
|
10844
|
+
const selectedLabel = getOptionLabel(effectiveVal);
|
|
10762
10845
|
const inOpts = opts.some((o) => getValue(o) === selectedKey);
|
|
10763
|
-
const selectedFallback = inOpts ? [] : [
|
|
10846
|
+
const selectedFallback = inOpts ? [] : [effectiveVal];
|
|
10764
10847
|
if (!inputVal || inputVal === selectedLabel) {
|
|
10765
10848
|
return [
|
|
10766
10849
|
...selectedFallback,
|
|
@@ -10774,21 +10857,27 @@ function SmartSelect({
|
|
|
10774
10857
|
return opts.filter(
|
|
10775
10858
|
(opt) => getOptionLabel(opt).toLowerCase().includes(q) || (getOptionSubLabel?.(opt) ?? "").toLowerCase().includes(q)
|
|
10776
10859
|
).slice(0, searchThreshold);
|
|
10777
|
-
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value, searchThreshold]);
|
|
10860
|
+
}, [filterOptionsProp, multiple, selectedKeys, getValue, getOptionLabel, getOptionSubLabel, value, searchThreshold, strictSelection, strictValidation]);
|
|
10778
10861
|
return /* @__PURE__ */ React109.createElement(
|
|
10779
10862
|
Autocomplete,
|
|
10780
10863
|
{
|
|
10781
10864
|
options: displayOptions,
|
|
10782
|
-
value:
|
|
10865
|
+
value: autocompleteValue,
|
|
10783
10866
|
onChange: handleChange,
|
|
10784
|
-
inputValue:
|
|
10867
|
+
inputValue: autocompleteInputValue,
|
|
10785
10868
|
onInputChange: handleInputChange,
|
|
10786
10869
|
multiple,
|
|
10787
10870
|
limitTags,
|
|
10788
10871
|
loading,
|
|
10789
10872
|
loadingText: loadingText ?? /* @__PURE__ */ React109.createElement("span", { style: { fontSize: "0.875rem", color: "var(--text-secondary)" } }, "Loading\u2026"),
|
|
10790
10873
|
getOptionLabel,
|
|
10791
|
-
isOptionEqualToValue: (opt, val) =>
|
|
10874
|
+
isOptionEqualToValue: (opt, val) => {
|
|
10875
|
+
try {
|
|
10876
|
+
return getValue(opt) === getValue(val);
|
|
10877
|
+
} catch {
|
|
10878
|
+
return false;
|
|
10879
|
+
}
|
|
10880
|
+
},
|
|
10792
10881
|
filterOptions: computedFilterOptions,
|
|
10793
10882
|
renderOption: renderOptionProp ?? defaultRenderOption,
|
|
10794
10883
|
label,
|