hs-uix 1.4.0 → 1.5.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 +20 -2
- package/common-components.d.ts +55 -0
- package/dist/common-components.js +260 -0
- package/dist/common-components.mjs +221 -0
- package/dist/datatable.js +74 -38
- package/dist/datatable.mjs +74 -38
- package/dist/form.js +204 -76
- package/dist/form.mjs +204 -76
- package/dist/index.js +486 -114
- package/dist/index.mjs +481 -114
- package/dist/utils.js +269 -0
- package/dist/utils.mjs +230 -0
- package/index.d.ts +21 -0
- package/package.json +14 -2
- package/utils.d.ts +59 -0
package/dist/index.mjs
CHANGED
|
@@ -304,7 +304,9 @@ var DataTable = ({
|
|
|
304
304
|
const initialSortState = useMemo(() => {
|
|
305
305
|
return normalizeSortState(columns, defaultSort);
|
|
306
306
|
}, [columns, defaultSort]);
|
|
307
|
-
const [internalSearchTerm, setInternalSearchTerm] = useState(
|
|
307
|
+
const [internalSearchTerm, setInternalSearchTerm] = useState(
|
|
308
|
+
() => serverSide && searchValue != null ? searchValue : ""
|
|
309
|
+
);
|
|
308
310
|
const [internalFilterValues, setInternalFilterValues] = useState(() => {
|
|
309
311
|
const init = {};
|
|
310
312
|
filters.forEach((f) => {
|
|
@@ -315,7 +317,16 @@ var DataTable = ({
|
|
|
315
317
|
const [internalSortState, setInternalSortState] = useState(initialSortState);
|
|
316
318
|
const [currentPage, setCurrentPage] = useState(1);
|
|
317
319
|
const [showMoreFilters, setShowMoreFilters] = useState(false);
|
|
320
|
+
const lastAppliedSearchRef = useRef(
|
|
321
|
+
serverSide && searchValue != null ? searchValue : ""
|
|
322
|
+
);
|
|
318
323
|
const searchTerm = serverSide && searchValue != null ? searchValue : internalSearchTerm;
|
|
324
|
+
useEffect(() => {
|
|
325
|
+
if (!serverSide || searchValue == null) return;
|
|
326
|
+
if (searchValue === lastAppliedSearchRef.current) return;
|
|
327
|
+
lastAppliedSearchRef.current = searchValue;
|
|
328
|
+
setInternalSearchTerm(searchValue);
|
|
329
|
+
}, [serverSide, searchValue]);
|
|
319
330
|
const filterValues = serverSide && externalFilterValues != null ? externalFilterValues : internalFilterValues;
|
|
320
331
|
const externalSortState = useMemo(
|
|
321
332
|
() => normalizeSortState(columns, externalSort),
|
|
@@ -349,15 +360,16 @@ var DataTable = ({
|
|
|
349
360
|
const handleSearchChange = useCallback((term) => {
|
|
350
361
|
setInternalSearchTerm(term);
|
|
351
362
|
resetPage();
|
|
363
|
+
const dispatch = () => {
|
|
364
|
+
lastAppliedSearchRef.current = term;
|
|
365
|
+
fireSearchCallback(term);
|
|
366
|
+
fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
|
|
367
|
+
};
|
|
352
368
|
if (searchDebounce > 0) {
|
|
353
369
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
354
|
-
debounceRef.current = setTimeout(
|
|
355
|
-
fireSearchCallback(term);
|
|
356
|
-
fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
|
|
357
|
-
}, searchDebounce);
|
|
370
|
+
debounceRef.current = setTimeout(dispatch, searchDebounce);
|
|
358
371
|
} else {
|
|
359
|
-
|
|
360
|
-
fireParamsChange({ search: term, page: resetPageOnChange ? 1 : void 0 });
|
|
372
|
+
dispatch();
|
|
361
373
|
}
|
|
362
374
|
}, [searchDebounce, fireSearchCallback, fireParamsChange, resetPage, resetPageOnChange]);
|
|
363
375
|
useEffect(() => () => {
|
|
@@ -439,10 +451,23 @@ var DataTable = ({
|
|
|
439
451
|
if (serverSide) return filteredData;
|
|
440
452
|
const activeField = Object.keys(sortState).find((k) => sortState[k] !== "none");
|
|
441
453
|
if (!activeField) return filteredData;
|
|
454
|
+
const activeCol = columns.find((c) => c.field === activeField);
|
|
455
|
+
const sortOrder = Array.isArray(activeCol == null ? void 0 : activeCol.sortOrder) ? activeCol.sortOrder : null;
|
|
456
|
+
const sortOrderIndex = (val) => {
|
|
457
|
+
const idx = sortOrder.indexOf(val);
|
|
458
|
+
return idx === -1 ? sortOrder.length : idx;
|
|
459
|
+
};
|
|
442
460
|
return [...filteredData].sort((a, b) => {
|
|
443
461
|
const dir = sortState[activeField] === "ascending" ? 1 : -1;
|
|
444
462
|
const aVal = a[activeField];
|
|
445
463
|
const bVal = b[activeField];
|
|
464
|
+
if (typeof (activeCol == null ? void 0 : activeCol.sortComparator) === "function") {
|
|
465
|
+
return dir * activeCol.sortComparator(aVal, bVal, a, b);
|
|
466
|
+
}
|
|
467
|
+
if (sortOrder) {
|
|
468
|
+
const diff = sortOrderIndex(aVal) - sortOrderIndex(bVal);
|
|
469
|
+
if (diff !== 0) return dir * diff;
|
|
470
|
+
}
|
|
446
471
|
if (aVal == null && bVal == null) return 0;
|
|
447
472
|
if (aVal == null) return 1;
|
|
448
473
|
if (bVal == null) return -1;
|
|
@@ -450,7 +475,7 @@ var DataTable = ({
|
|
|
450
475
|
if (aVal > bVal) return dir;
|
|
451
476
|
return 0;
|
|
452
477
|
});
|
|
453
|
-
}, [filteredData, sortState, serverSide]);
|
|
478
|
+
}, [filteredData, sortState, serverSide, columns]);
|
|
454
479
|
const groupedData = useMemo(() => {
|
|
455
480
|
if (!groupBy) return null;
|
|
456
481
|
const source = serverSide ? data : sortedData;
|
|
@@ -502,28 +527,33 @@ var DataTable = ({
|
|
|
502
527
|
return next;
|
|
503
528
|
});
|
|
504
529
|
}, []);
|
|
505
|
-
const
|
|
506
|
-
if (!groupedData) return
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
if (expandedGroups.has(group.key)) {
|
|
511
|
-
group.rows.forEach((row) => flat.push({ type: "data", row }));
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
return flat;
|
|
515
|
-
}, [groupedData, sortedData, data, serverSide, expandedGroups]);
|
|
516
|
-
const totalItems = serverSide ? totalCount || data.length : flatRows.length;
|
|
530
|
+
const datasetRows = useMemo(() => {
|
|
531
|
+
if (!groupedData) return serverSide ? data : sortedData;
|
|
532
|
+
return groupedData.flatMap((group) => group.rows);
|
|
533
|
+
}, [groupedData, sortedData, data, serverSide]);
|
|
534
|
+
const totalItems = serverSide ? totalCount || data.length : datasetRows.length;
|
|
517
535
|
const pageCount = Math.ceil(totalItems / pageSize);
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
} else {
|
|
522
|
-
displayRows = flatRows.slice(
|
|
536
|
+
const paginatedRows = useMemo(() => {
|
|
537
|
+
if (serverSide) return datasetRows;
|
|
538
|
+
return datasetRows.slice(
|
|
523
539
|
(activePage - 1) * pageSize,
|
|
524
540
|
activePage * pageSize
|
|
525
541
|
);
|
|
526
|
-
}
|
|
542
|
+
}, [serverSide, datasetRows, activePage, pageSize]);
|
|
543
|
+
const displayRows = useMemo(() => {
|
|
544
|
+
if (!groupedData) return paginatedRows.map((row) => ({ type: "data", row }));
|
|
545
|
+
const pageRows = new Set(paginatedRows);
|
|
546
|
+
const rows = [];
|
|
547
|
+
groupedData.forEach((group) => {
|
|
548
|
+
const groupPageRows = group.rows.filter((row) => pageRows.has(row));
|
|
549
|
+
if (groupPageRows.length === 0) return;
|
|
550
|
+
rows.push({ type: "group-header", group });
|
|
551
|
+
if (expandedGroups.has(group.key)) {
|
|
552
|
+
groupPageRows.forEach((row) => rows.push({ type: "data", row }));
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
return rows;
|
|
556
|
+
}, [groupedData, paginatedRows, expandedGroups]);
|
|
527
557
|
const footerData = serverSide ? data : filteredData;
|
|
528
558
|
const activeChips = useMemo(() => {
|
|
529
559
|
const chips = [];
|
|
@@ -634,8 +664,8 @@ var DataTable = ({
|
|
|
634
664
|
return displayRows.filter((r) => r.type === "data").map((r) => r.row[rowIdField]).filter((id) => id != null);
|
|
635
665
|
}, [serverSide, data, displayRows, rowIdField]);
|
|
636
666
|
const allRowIds = useMemo(
|
|
637
|
-
() =>
|
|
638
|
-
[
|
|
667
|
+
() => datasetRows.map((row) => row[rowIdField]).filter((id) => id != null),
|
|
668
|
+
[datasetRows, rowIdField]
|
|
639
669
|
);
|
|
640
670
|
const handleSelectRow = useCallback((rowId, checked) => {
|
|
641
671
|
const next = new Set(selectedIds);
|
|
@@ -682,19 +712,25 @@ var DataTable = ({
|
|
|
682
712
|
if (row) onEditStart(row, field, currentValue);
|
|
683
713
|
}
|
|
684
714
|
}, [onEditStart, data, rowIdField]);
|
|
685
|
-
const commitEdit = useCallback((row, field, value) => {
|
|
715
|
+
const commitEdit = useCallback((row, field, value, options = {}) => {
|
|
716
|
+
const { keepEditing = false } = options;
|
|
686
717
|
const col = columns.find((c) => c.field === field);
|
|
687
718
|
if (col == null ? void 0 : col.editValidate) {
|
|
688
719
|
const result = col.editValidate(value, row);
|
|
689
720
|
if (result !== true && result !== void 0 && result !== null) {
|
|
690
721
|
setEditError(typeof result === "string" ? result : "Invalid value");
|
|
691
|
-
return;
|
|
722
|
+
return false;
|
|
692
723
|
}
|
|
693
724
|
}
|
|
694
725
|
if (onRowEdit) onRowEdit(row, field, value);
|
|
695
|
-
|
|
696
|
-
|
|
726
|
+
if (!keepEditing) {
|
|
727
|
+
setEditingCell(null);
|
|
728
|
+
setEditValue(null);
|
|
729
|
+
} else {
|
|
730
|
+
setEditValue(value);
|
|
731
|
+
}
|
|
697
732
|
setEditError(null);
|
|
733
|
+
return true;
|
|
698
734
|
}, [onRowEdit, columns]);
|
|
699
735
|
const renderEditControl = (col, row) => {
|
|
700
736
|
const type = col.editType || "text";
|
|
@@ -753,12 +789,12 @@ var DataTable = ({
|
|
|
753
789
|
case "datetime":
|
|
754
790
|
return /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "center", gap: "xs", wrap: "nowrap" }, /* @__PURE__ */ React.createElement(DateInput, { ...extra, name: `${fieldName}-date`, label: "", value: editValue == null ? void 0 : editValue.date, onChange: (val) => {
|
|
755
791
|
const next = { ...editValue, date: val };
|
|
756
|
-
|
|
757
|
-
|
|
792
|
+
handleInput(next);
|
|
793
|
+
commitEdit(row, col.field, next, { keepEditing: true });
|
|
758
794
|
}, onBlur: maybeExitDatetimeEdit }), /* @__PURE__ */ React.createElement(TimeInput, { ...extra.timeProps || {}, name: `${fieldName}-time`, label: "", value: editValue == null ? void 0 : editValue.time, onChange: (val) => {
|
|
759
795
|
const next = { ...editValue, time: val };
|
|
760
|
-
|
|
761
|
-
|
|
796
|
+
handleInput(next);
|
|
797
|
+
commitEdit(row, col.field, next, { keepEditing: true });
|
|
762
798
|
}, onBlur: maybeExitDatetimeEdit }));
|
|
763
799
|
case "toggle":
|
|
764
800
|
return /* @__PURE__ */ React.createElement(Toggle, { ...extra, name: fieldName, label: "", checked: !!editValue, onChange: commit });
|
|
@@ -963,12 +999,12 @@ var DataTable = ({
|
|
|
963
999
|
}
|
|
964
1000
|
);
|
|
965
1001
|
};
|
|
966
|
-
return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ React.createElement(Box, { flex: 3 }, /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "
|
|
1002
|
+
return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", gap: "sm" }, /* @__PURE__ */ React.createElement(Box, { flex: 3 }, /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "sm" }, /* @__PURE__ */ React.createElement(Flex, { direction: "row", align: "end", gap: "sm", wrap: "wrap" }, showSearch && searchFields.length > 0 && /* @__PURE__ */ React.createElement(
|
|
967
1003
|
SearchInput,
|
|
968
1004
|
{
|
|
969
1005
|
name: "datatable-search",
|
|
970
1006
|
placeholder: searchPlaceholder,
|
|
971
|
-
value:
|
|
1007
|
+
value: internalSearchTerm,
|
|
972
1008
|
onChange: handleSearchChange
|
|
973
1009
|
}
|
|
974
1010
|
), filters.slice(0, filterInlineLimit).map(renderFilterControl), filters.length > filterInlineLimit && /* @__PURE__ */ React.createElement(
|
|
@@ -1771,9 +1807,10 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1771
1807
|
const inputDebounceRef = useRef2(/* @__PURE__ */ new Map());
|
|
1772
1808
|
const rowKeyRef = useRef2(/* @__PURE__ */ new WeakMap());
|
|
1773
1809
|
const rowKeyCounterRef = useRef2(0);
|
|
1810
|
+
const controlledBaselineLockedRef = useRef2(false);
|
|
1774
1811
|
const initialSnapshot = useRef2(null);
|
|
1775
1812
|
if (initialSnapshot.current === null) {
|
|
1776
|
-
initialSnapshot.current = deepClone(computeInitialValues());
|
|
1813
|
+
initialSnapshot.current = deepClone(values != null ? values : computeInitialValues());
|
|
1777
1814
|
}
|
|
1778
1815
|
const formValues = values != null ? values : internalValues;
|
|
1779
1816
|
const formErrors = controlledErrors != null ? controlledErrors : internalErrors;
|
|
@@ -1785,6 +1822,10 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1785
1822
|
const draftValuesRef = useRef2(null);
|
|
1786
1823
|
formValuesRef.current = formValues;
|
|
1787
1824
|
formErrorsRef.current = formErrors;
|
|
1825
|
+
const syncDirtyBaseline = useCallback2((nextValues) => {
|
|
1826
|
+
initialSnapshot.current = deepClone(nextValues || {});
|
|
1827
|
+
prevAutoSaveValues.current = deepClone(nextValues || {});
|
|
1828
|
+
}, []);
|
|
1788
1829
|
const fieldByName = useMemo2(() => {
|
|
1789
1830
|
const map = /* @__PURE__ */ new Map();
|
|
1790
1831
|
for (const field of fields) {
|
|
@@ -1861,6 +1902,11 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1861
1902
|
if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
|
|
1862
1903
|
};
|
|
1863
1904
|
}, []);
|
|
1905
|
+
useEffect2(() => {
|
|
1906
|
+
if (values == null) return;
|
|
1907
|
+
if (controlledBaselineLockedRef.current) return;
|
|
1908
|
+
syncDirtyBaseline(values);
|
|
1909
|
+
}, [values, syncDirtyBaseline]);
|
|
1864
1910
|
const isDirty = useMemo2(() => {
|
|
1865
1911
|
return !deepEqual(formValues, initialSnapshot.current);
|
|
1866
1912
|
}, [formValues]);
|
|
@@ -1979,6 +2025,50 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1979
2025
|
},
|
|
1980
2026
|
[fieldTypes]
|
|
1981
2027
|
);
|
|
2028
|
+
const setRepeaterSubFieldError = useCallback2(
|
|
2029
|
+
(fieldName, rowIdx, subFieldName, errorMessage) => {
|
|
2030
|
+
const key = getRepeaterErrorKey(fieldName, rowIdx, subFieldName);
|
|
2031
|
+
const merged = { ...formErrorsRef.current };
|
|
2032
|
+
if (errorMessage) {
|
|
2033
|
+
merged[key] = errorMessage;
|
|
2034
|
+
} else {
|
|
2035
|
+
delete merged[key];
|
|
2036
|
+
}
|
|
2037
|
+
const subErrors = Object.keys(merged).filter((k) => k.startsWith(`${fieldName}[`)).map((k) => {
|
|
2038
|
+
const match = k.match(/\[(\d+)\]\./);
|
|
2039
|
+
const row = match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
|
|
2040
|
+
return { key: k, row };
|
|
2041
|
+
}).sort((a, b) => a.row - b.row);
|
|
2042
|
+
if (subErrors.length > 0) {
|
|
2043
|
+
const first = subErrors[0];
|
|
2044
|
+
merged[fieldName] = `Row ${first.row + 1}: ${merged[first.key]}`;
|
|
2045
|
+
} else if (!merged[fieldName] || merged[fieldName].startsWith("Row ")) {
|
|
2046
|
+
delete merged[fieldName];
|
|
2047
|
+
}
|
|
2048
|
+
replaceErrors(merged);
|
|
2049
|
+
},
|
|
2050
|
+
[replaceErrors]
|
|
2051
|
+
);
|
|
2052
|
+
const expandValidationFields = useCallback2(
|
|
2053
|
+
(fieldSubset) => {
|
|
2054
|
+
const toValidate = fieldSubset || visibleFields;
|
|
2055
|
+
const expanded = [];
|
|
2056
|
+
for (const field of toValidate) {
|
|
2057
|
+
if (field.type === "fieldGroup" && field.items && field.fields) {
|
|
2058
|
+
for (const item of field.items) {
|
|
2059
|
+
for (const subField of field.fields(item)) {
|
|
2060
|
+
if (subField.visible && !subField.visible(formValues)) continue;
|
|
2061
|
+
expanded.push(subField);
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
continue;
|
|
2065
|
+
}
|
|
2066
|
+
expanded.push(field);
|
|
2067
|
+
}
|
|
2068
|
+
return expanded;
|
|
2069
|
+
},
|
|
2070
|
+
[visibleFields, formValues]
|
|
2071
|
+
);
|
|
1982
2072
|
const validateField = useCallback2(
|
|
1983
2073
|
(name, value) => {
|
|
1984
2074
|
const field = fieldByName.get(name);
|
|
@@ -1998,7 +2088,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1998
2088
|
);
|
|
1999
2089
|
const validateVisibleFields = useCallback2(
|
|
2000
2090
|
(fieldSubset) => {
|
|
2001
|
-
const toValidate = fieldSubset
|
|
2091
|
+
const toValidate = expandValidationFields(fieldSubset);
|
|
2002
2092
|
const errors = {};
|
|
2003
2093
|
let hasErrors = false;
|
|
2004
2094
|
for (const field of toValidate) {
|
|
@@ -2018,52 +2108,54 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2018
2108
|
}
|
|
2019
2109
|
return { errors, hasErrors };
|
|
2020
2110
|
},
|
|
2021
|
-
[
|
|
2111
|
+
[expandValidationFields, formValues, validateRepeaterField, fieldTypes, validationMessages]
|
|
2022
2112
|
);
|
|
2023
|
-
const
|
|
2024
|
-
(
|
|
2025
|
-
const field =
|
|
2026
|
-
if (!field || field.type === "repeater") return null;
|
|
2027
|
-
const
|
|
2028
|
-
|
|
2029
|
-
|
|
2113
|
+
const runAsyncValidationTarget = useCallback2(
|
|
2114
|
+
(target) => {
|
|
2115
|
+
const { validationKey, field, value, allValues, applyError } = target || {};
|
|
2116
|
+
if (!field || !validationKey || field.type === "repeater" || field.type === "fieldGroup") return null;
|
|
2117
|
+
const syncError = runValidators(value, field, allValues, fieldTypes, {
|
|
2118
|
+
includeCustomValidators: false,
|
|
2119
|
+
messages: validationMessages
|
|
2120
|
+
});
|
|
2121
|
+
const prevController = asyncAbortRef.current.get(validationKey);
|
|
2030
2122
|
if (prevController) prevController.abort();
|
|
2031
|
-
asyncAbortRef.current.delete(
|
|
2123
|
+
asyncAbortRef.current.delete(validationKey);
|
|
2032
2124
|
setValidatingFields((prev) => {
|
|
2033
|
-
if (!prev[
|
|
2125
|
+
if (!prev[validationKey]) return prev;
|
|
2034
2126
|
const next = { ...prev };
|
|
2035
|
-
delete next[
|
|
2127
|
+
delete next[validationKey];
|
|
2036
2128
|
return next;
|
|
2037
2129
|
});
|
|
2038
2130
|
if (syncError) return null;
|
|
2039
|
-
const version = (asyncValidationVersionRef.current.get(
|
|
2040
|
-
asyncValidationVersionRef.current.set(
|
|
2131
|
+
const version = (asyncValidationVersionRef.current.get(validationKey) || 0) + 1;
|
|
2132
|
+
asyncValidationVersionRef.current.set(validationKey, version);
|
|
2041
2133
|
const controller = typeof AbortController !== "undefined" ? new AbortController() : null;
|
|
2042
|
-
if (controller) asyncAbortRef.current.set(
|
|
2134
|
+
if (controller) asyncAbortRef.current.set(validationKey, controller);
|
|
2043
2135
|
let asyncPromises;
|
|
2044
2136
|
try {
|
|
2045
2137
|
asyncPromises = collectAsyncValidatorPromises(
|
|
2046
|
-
|
|
2138
|
+
value,
|
|
2047
2139
|
field,
|
|
2048
|
-
|
|
2140
|
+
allValues,
|
|
2049
2141
|
controller ? { signal: controller.signal } : void 0
|
|
2050
2142
|
);
|
|
2051
2143
|
} catch (err) {
|
|
2052
|
-
|
|
2144
|
+
applyError((err == null ? void 0 : err.message) || "Validation failed");
|
|
2053
2145
|
return null;
|
|
2054
2146
|
}
|
|
2055
2147
|
if (asyncPromises.length === 0) {
|
|
2056
|
-
asyncAbortRef.current.delete(
|
|
2148
|
+
asyncAbortRef.current.delete(validationKey);
|
|
2057
2149
|
return null;
|
|
2058
2150
|
}
|
|
2059
2151
|
const validationPromise = Promise.all(asyncPromises).then(
|
|
2060
2152
|
(results) => {
|
|
2061
|
-
if (asyncValidationVersionRef.current.get(
|
|
2062
|
-
asyncValidationRef.current.delete(
|
|
2063
|
-
asyncAbortRef.current.delete(
|
|
2153
|
+
if (asyncValidationVersionRef.current.get(validationKey) !== version) return;
|
|
2154
|
+
asyncValidationRef.current.delete(validationKey);
|
|
2155
|
+
asyncAbortRef.current.delete(validationKey);
|
|
2064
2156
|
setValidatingFields((prev) => {
|
|
2065
2157
|
const next = { ...prev };
|
|
2066
|
-
delete next[
|
|
2158
|
+
delete next[validationKey];
|
|
2067
2159
|
return next;
|
|
2068
2160
|
});
|
|
2069
2161
|
let err = null;
|
|
@@ -2074,50 +2166,128 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2074
2166
|
break;
|
|
2075
2167
|
}
|
|
2076
2168
|
}
|
|
2077
|
-
|
|
2169
|
+
applyError(err);
|
|
2078
2170
|
},
|
|
2079
2171
|
(rejection) => {
|
|
2080
|
-
if (asyncValidationVersionRef.current.get(
|
|
2081
|
-
asyncValidationRef.current.delete(
|
|
2082
|
-
asyncAbortRef.current.delete(
|
|
2172
|
+
if (asyncValidationVersionRef.current.get(validationKey) !== version) return;
|
|
2173
|
+
asyncValidationRef.current.delete(validationKey);
|
|
2174
|
+
asyncAbortRef.current.delete(validationKey);
|
|
2083
2175
|
setValidatingFields((prev) => {
|
|
2084
2176
|
const next = { ...prev };
|
|
2085
|
-
delete next[
|
|
2177
|
+
delete next[validationKey];
|
|
2086
2178
|
return next;
|
|
2087
2179
|
});
|
|
2088
2180
|
if (rejection && rejection.name === "AbortError") return;
|
|
2089
|
-
|
|
2181
|
+
applyError((rejection == null ? void 0 : rejection.message) || "Validation failed");
|
|
2090
2182
|
}
|
|
2091
2183
|
);
|
|
2092
|
-
asyncValidationRef.current.set(
|
|
2093
|
-
setValidatingFields((prev) => ({ ...prev, [
|
|
2184
|
+
asyncValidationRef.current.set(validationKey, validationPromise);
|
|
2185
|
+
setValidatingFields((prev) => ({ ...prev, [validationKey]: true }));
|
|
2094
2186
|
return validationPromise;
|
|
2095
2187
|
},
|
|
2096
|
-
[
|
|
2188
|
+
[fieldTypes, validationMessages]
|
|
2097
2189
|
);
|
|
2098
|
-
const
|
|
2190
|
+
const runAsyncValidation = useCallback2(
|
|
2099
2191
|
(name, value) => {
|
|
2100
2192
|
const field = fieldByName.get(name);
|
|
2101
|
-
if (!field || field.type === "repeater") return;
|
|
2102
|
-
|
|
2193
|
+
if (!field || field.type === "repeater" || field.type === "fieldGroup") return null;
|
|
2194
|
+
return runAsyncValidationTarget({
|
|
2195
|
+
validationKey: name,
|
|
2196
|
+
field,
|
|
2197
|
+
value: value != null ? value : formValues[name],
|
|
2198
|
+
allValues: formValues,
|
|
2199
|
+
applyError: (errorMessage) => updateErrors({ [name]: errorMessage })
|
|
2200
|
+
});
|
|
2201
|
+
},
|
|
2202
|
+
[fieldByName, formValues, runAsyncValidationTarget, updateErrors]
|
|
2203
|
+
);
|
|
2204
|
+
const triggerAsyncValidationTarget = useCallback2(
|
|
2205
|
+
(target) => {
|
|
2206
|
+
if (!(target == null ? void 0 : target.field) || !target.validationKey) return;
|
|
2207
|
+
const debounceMs = target.field.validateDebounce;
|
|
2103
2208
|
if (debounceMs && debounceMs > 0) {
|
|
2104
|
-
const existing = debounceTimersRef.current.get(
|
|
2209
|
+
const existing = debounceTimersRef.current.get(target.validationKey);
|
|
2105
2210
|
if (existing) clearTimeout(existing);
|
|
2106
2211
|
const timer = setTimeout(() => {
|
|
2107
|
-
debounceTimersRef.current.delete(
|
|
2108
|
-
|
|
2212
|
+
debounceTimersRef.current.delete(target.validationKey);
|
|
2213
|
+
runAsyncValidationTarget(target);
|
|
2109
2214
|
}, debounceMs);
|
|
2110
|
-
debounceTimersRef.current.set(
|
|
2215
|
+
debounceTimersRef.current.set(target.validationKey, timer);
|
|
2111
2216
|
} else {
|
|
2112
|
-
|
|
2217
|
+
runAsyncValidationTarget(target);
|
|
2218
|
+
}
|
|
2219
|
+
},
|
|
2220
|
+
[runAsyncValidationTarget]
|
|
2221
|
+
);
|
|
2222
|
+
const triggerAsyncValidation = useCallback2(
|
|
2223
|
+
(name, value) => {
|
|
2224
|
+
const field = fieldByName.get(name);
|
|
2225
|
+
if (!field || field.type === "repeater" || field.type === "fieldGroup") return;
|
|
2226
|
+
triggerAsyncValidationTarget({
|
|
2227
|
+
validationKey: name,
|
|
2228
|
+
field,
|
|
2229
|
+
value: value != null ? value : formValuesRef.current[name],
|
|
2230
|
+
allValues: formValuesRef.current,
|
|
2231
|
+
applyError: (errorMessage) => updateErrors({ [name]: errorMessage })
|
|
2232
|
+
});
|
|
2233
|
+
},
|
|
2234
|
+
[fieldByName, triggerAsyncValidationTarget, updateErrors]
|
|
2235
|
+
);
|
|
2236
|
+
const getAsyncValidationTargets = useCallback2(
|
|
2237
|
+
(fieldSubset) => {
|
|
2238
|
+
const toValidate = fieldSubset || visibleFields;
|
|
2239
|
+
const targets = [];
|
|
2240
|
+
for (const field of toValidate) {
|
|
2241
|
+
if (field.type === "fieldGroup" && field.items && field.fields) {
|
|
2242
|
+
for (const item of field.items) {
|
|
2243
|
+
for (const subField of field.fields(item)) {
|
|
2244
|
+
if (subField.visible && !subField.visible(formValues)) continue;
|
|
2245
|
+
targets.push({
|
|
2246
|
+
validationKey: subField.name,
|
|
2247
|
+
field: subField,
|
|
2248
|
+
value: formValues[subField.name],
|
|
2249
|
+
allValues: formValues,
|
|
2250
|
+
applyError: (errorMessage) => updateErrors({ [subField.name]: errorMessage })
|
|
2251
|
+
});
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
continue;
|
|
2255
|
+
}
|
|
2256
|
+
if (field.type === "repeater") {
|
|
2257
|
+
const rows = Array.isArray(formValues[field.name]) ? formValues[field.name] : [];
|
|
2258
|
+
const subFields = field.fields || [];
|
|
2259
|
+
rows.forEach((row, rowIdx) => {
|
|
2260
|
+
const rowValues = { ...formValues, [field.name]: rows };
|
|
2261
|
+
subFields.forEach((subField) => {
|
|
2262
|
+
if (subField.visible && !subField.visible(rowValues)) return;
|
|
2263
|
+
targets.push({
|
|
2264
|
+
validationKey: getRepeaterErrorKey(field.name, rowIdx, subField.name),
|
|
2265
|
+
field: subField,
|
|
2266
|
+
value: row == null ? void 0 : row[subField.name],
|
|
2267
|
+
allValues: rowValues,
|
|
2268
|
+
applyError: (errorMessage) => setRepeaterSubFieldError(field.name, rowIdx, subField.name, errorMessage)
|
|
2269
|
+
});
|
|
2270
|
+
});
|
|
2271
|
+
});
|
|
2272
|
+
continue;
|
|
2273
|
+
}
|
|
2274
|
+
targets.push({
|
|
2275
|
+
validationKey: field.name,
|
|
2276
|
+
field,
|
|
2277
|
+
value: formValues[field.name],
|
|
2278
|
+
allValues: formValues,
|
|
2279
|
+
applyError: (errorMessage) => updateErrors({ [field.name]: errorMessage })
|
|
2280
|
+
});
|
|
2113
2281
|
}
|
|
2282
|
+
return targets;
|
|
2114
2283
|
},
|
|
2115
|
-
[
|
|
2284
|
+
[visibleFields, formValues, setRepeaterSubFieldError, updateErrors]
|
|
2116
2285
|
);
|
|
2117
2286
|
const commitValues = useCallback2(
|
|
2118
2287
|
(nextValues) => {
|
|
2119
2288
|
formValuesRef.current = nextValues;
|
|
2120
2289
|
if (values != null) {
|
|
2290
|
+
controlledBaselineLockedRef.current = true;
|
|
2121
2291
|
if (onChange) onChange(nextValues);
|
|
2122
2292
|
} else {
|
|
2123
2293
|
setInternalValues(nextValues);
|
|
@@ -2135,7 +2305,8 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2135
2305
|
[commitValues]
|
|
2136
2306
|
);
|
|
2137
2307
|
const handleFieldChange = useCallback2(
|
|
2138
|
-
(name, value) => {
|
|
2308
|
+
(name, value, options = {}) => {
|
|
2309
|
+
const { clearNestedErrors = true } = options;
|
|
2139
2310
|
const newValues = { ...formValuesRef.current, [name]: value };
|
|
2140
2311
|
const queue = [name];
|
|
2141
2312
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -2176,9 +2347,11 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2176
2347
|
if (formErrorsRef.current[name] != null) {
|
|
2177
2348
|
clearedErrors[name] = null;
|
|
2178
2349
|
}
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2350
|
+
if (clearNestedErrors) {
|
|
2351
|
+
for (const key of Object.keys(formErrorsRef.current)) {
|
|
2352
|
+
if (key.startsWith(`${name}[`)) {
|
|
2353
|
+
clearedErrors[key] = null;
|
|
2354
|
+
}
|
|
2182
2355
|
}
|
|
2183
2356
|
}
|
|
2184
2357
|
draftValuesRef.current = newValues;
|
|
@@ -2247,7 +2420,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2247
2420
|
replaceErrors(errors);
|
|
2248
2421
|
return;
|
|
2249
2422
|
}
|
|
2250
|
-
const asyncSubmitValidations = allVisibleFields.map((
|
|
2423
|
+
const asyncSubmitValidations = getAsyncValidationTargets(allVisibleFields).map((target) => runAsyncValidationTarget(target)).filter(Boolean);
|
|
2251
2424
|
if (asyncSubmitValidations.length > 0 || asyncValidationRef.current.size > 0) {
|
|
2252
2425
|
const pendingValidations = [
|
|
2253
2426
|
.../* @__PURE__ */ new Set([
|
|
@@ -2262,6 +2435,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2262
2435
|
const reset = () => {
|
|
2263
2436
|
const fresh = computeInitialValues();
|
|
2264
2437
|
if (values == null) setInternalValues(fresh);
|
|
2438
|
+
controlledBaselineLockedRef.current = false;
|
|
2265
2439
|
replaceErrors({});
|
|
2266
2440
|
initialSnapshot.current = deepClone(fresh);
|
|
2267
2441
|
prevAutoSaveValues.current = deepClone(fresh);
|
|
@@ -2301,7 +2475,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2301
2475
|
if (controlledLoading == null) setInternalLoading(false);
|
|
2302
2476
|
}
|
|
2303
2477
|
},
|
|
2304
|
-
[validateOnSubmit, allVisibleFields, validateVisibleFields, replaceErrors, onSubmit, values, controlledLoading, transformValues, onBeforeSubmit, onSubmitSuccess, onSubmitError, resetOnSuccess, formValues, fieldByName,
|
|
2478
|
+
[validateOnSubmit, allVisibleFields, validateVisibleFields, replaceErrors, onSubmit, values, controlledLoading, transformValues, onBeforeSubmit, onSubmitSuccess, onSubmitError, resetOnSuccess, formValues, fieldByName, getAsyncValidationTargets, runAsyncValidationTarget]
|
|
2305
2479
|
);
|
|
2306
2480
|
const handleNext = useCallback2(async () => {
|
|
2307
2481
|
if (!isMultiStep) return;
|
|
@@ -2313,7 +2487,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2313
2487
|
replaceErrors({ ...formErrorsRef.current, ...errors });
|
|
2314
2488
|
return;
|
|
2315
2489
|
}
|
|
2316
|
-
const asyncStepValidations = stepFields.map((
|
|
2490
|
+
const asyncStepValidations = getAsyncValidationTargets(stepFields).map((target) => runAsyncValidationTarget(target)).filter(Boolean);
|
|
2317
2491
|
if (asyncStepValidations.length > 0 || asyncValidationRef.current.size > 0) {
|
|
2318
2492
|
const pendingValidations = [
|
|
2319
2493
|
.../* @__PURE__ */ new Set([
|
|
@@ -2338,7 +2512,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2338
2512
|
} else {
|
|
2339
2513
|
setInternalStep(nextStep);
|
|
2340
2514
|
}
|
|
2341
|
-
}, [isMultiStep, validateStepOnNext, steps, currentStep, formValues, validateVisibleFields, controlledStep, onStepChange, replaceErrors, allVisibleFields,
|
|
2515
|
+
}, [isMultiStep, validateStepOnNext, steps, currentStep, formValues, validateVisibleFields, controlledStep, onStepChange, replaceErrors, allVisibleFields, getAsyncValidationTargets, runAsyncValidationTarget]);
|
|
2342
2516
|
const handleBack = useCallback2(() => {
|
|
2343
2517
|
if (!isMultiStep) return;
|
|
2344
2518
|
const prevStep = Math.max(currentStep - 1, 0);
|
|
@@ -2370,6 +2544,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2370
2544
|
reset: () => {
|
|
2371
2545
|
const fresh = computeInitialValues();
|
|
2372
2546
|
if (values == null) setInternalValues(fresh);
|
|
2547
|
+
controlledBaselineLockedRef.current = false;
|
|
2373
2548
|
replaceErrors({});
|
|
2374
2549
|
initialSnapshot.current = deepClone(fresh);
|
|
2375
2550
|
prevAutoSaveValues.current = deepClone(fresh);
|
|
@@ -2382,30 +2557,6 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2382
2557
|
replaceErrors(errors);
|
|
2383
2558
|
}
|
|
2384
2559
|
}));
|
|
2385
|
-
const setRepeaterSubFieldError = useCallback2(
|
|
2386
|
-
(fieldName, rowIdx, subFieldName, errorMessage) => {
|
|
2387
|
-
const key = getRepeaterErrorKey(fieldName, rowIdx, subFieldName);
|
|
2388
|
-
const merged = { ...formErrorsRef.current };
|
|
2389
|
-
if (errorMessage) {
|
|
2390
|
-
merged[key] = errorMessage;
|
|
2391
|
-
} else {
|
|
2392
|
-
delete merged[key];
|
|
2393
|
-
}
|
|
2394
|
-
const subErrors = Object.keys(merged).filter((k) => k.startsWith(`${fieldName}[`)).map((k) => {
|
|
2395
|
-
const match = k.match(/\[(\d+)\]\./);
|
|
2396
|
-
const row = match ? Number(match[1]) : Number.MAX_SAFE_INTEGER;
|
|
2397
|
-
return { key: k, row };
|
|
2398
|
-
}).sort((a, b) => a.row - b.row);
|
|
2399
|
-
if (subErrors.length > 0) {
|
|
2400
|
-
const first = subErrors[0];
|
|
2401
|
-
merged[fieldName] = `Row ${first.row + 1}: ${merged[first.key]}`;
|
|
2402
|
-
} else if (!merged[fieldName] || merged[fieldName].startsWith("Row ")) {
|
|
2403
|
-
delete merged[fieldName];
|
|
2404
|
-
}
|
|
2405
|
-
replaceErrors(merged);
|
|
2406
|
-
},
|
|
2407
|
-
[replaceErrors]
|
|
2408
|
-
);
|
|
2409
2560
|
const renderField = (field) => {
|
|
2410
2561
|
const fieldError = formErrors[field.name] || null;
|
|
2411
2562
|
const rendered = renderFieldInner(field);
|
|
@@ -2885,12 +3036,13 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2885
3036
|
const rowValues = { ...formValues, [field.name]: nextRows };
|
|
2886
3037
|
const err = runValidators(subValue, subField, rowValues, fieldTypes, { messages: validationMessages });
|
|
2887
3038
|
setRepeaterSubFieldError(field.name, rowIdx, subField.name, err);
|
|
3039
|
+
return err;
|
|
2888
3040
|
};
|
|
2889
3041
|
const handleSubFieldChange = (rowIdx, subField, subValue) => {
|
|
2890
3042
|
const updated = rows.map(
|
|
2891
3043
|
(row, i) => i === rowIdx ? { ...row, [subField.name]: subValue } : row
|
|
2892
3044
|
);
|
|
2893
|
-
handleFieldChange(field.name, updated);
|
|
3045
|
+
handleFieldChange(field.name, updated, { clearNestedErrors: false });
|
|
2894
3046
|
if (validateOnChange) {
|
|
2895
3047
|
validateSubField(rowIdx, subField, subValue, updated);
|
|
2896
3048
|
}
|
|
@@ -2900,13 +3052,24 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2900
3052
|
const nextRows = rows.map(
|
|
2901
3053
|
(row, i) => i === rowIdx ? { ...row, [subField.name]: subValue } : row
|
|
2902
3054
|
);
|
|
2903
|
-
validateSubField(rowIdx, subField, subValue, nextRows);
|
|
3055
|
+
const err = validateSubField(rowIdx, subField, subValue, nextRows);
|
|
3056
|
+
if (err) return;
|
|
3057
|
+
const validationKey = getRepeaterErrorKey(field.name, rowIdx, subField.name);
|
|
3058
|
+
const rowValues = { ...formValues, [field.name]: nextRows };
|
|
3059
|
+
triggerAsyncValidationTarget({
|
|
3060
|
+
validationKey,
|
|
3061
|
+
field: subField,
|
|
3062
|
+
value: subValue,
|
|
3063
|
+
allValues: rowValues,
|
|
3064
|
+
applyError: (errorMessage) => setRepeaterSubFieldError(field.name, rowIdx, subField.name, errorMessage)
|
|
3065
|
+
});
|
|
2904
3066
|
};
|
|
2905
3067
|
return /* @__PURE__ */ React2.createElement(Flex2, { direction: "column", gap: "xs" }, field.label && /* @__PURE__ */ React2.createElement(Text2, { format: { fontWeight: "demibold" } }, field.label, isRequired ? " *" : ""), field.description && /* @__PURE__ */ React2.createElement(Text2, { variant: "microcopy" }, field.description), rows.map((row, rowIdx) => /* @__PURE__ */ React2.createElement(Flex2, { key: getRowKey(field.name, row, rowIdx), direction: "row", gap: "xs", align: "end" }, subFields.map((sf) => {
|
|
2906
3068
|
const sfValue = row[sf.name];
|
|
2907
3069
|
const sfLabel = rowIdx === 0 ? sf.label : void 0;
|
|
2908
3070
|
const sfOptions = resolveOptions(sf, { ...formValues, [field.name]: rows });
|
|
2909
3071
|
const sfError = formErrors[getRepeaterErrorKey(field.name, rowIdx, sf.name)] || null;
|
|
3072
|
+
const validationKey = getRepeaterErrorKey(field.name, rowIdx, sf.name);
|
|
2910
3073
|
const sfProps = {
|
|
2911
3074
|
name: `${field.name}-${rowIdx}-${sf.name}`,
|
|
2912
3075
|
label: sfLabel,
|
|
@@ -2915,6 +3078,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
2915
3078
|
disabled: resolveDisabled(sf, formValues) || isDisabled,
|
|
2916
3079
|
error: !!sfError,
|
|
2917
3080
|
validationMessage: sfError || void 0,
|
|
3081
|
+
...validatingFields[validationKey] ? { loading: true } : {},
|
|
2918
3082
|
...sf.fieldProps || {}
|
|
2919
3083
|
};
|
|
2920
3084
|
let sfElement;
|
|
@@ -3343,8 +3507,211 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
3343
3507
|
formContent
|
|
3344
3508
|
);
|
|
3345
3509
|
});
|
|
3510
|
+
|
|
3511
|
+
// src/common-components/AutoTag.js
|
|
3512
|
+
import React3 from "react";
|
|
3513
|
+
import { Tag as Tag2 } from "@hubspot/ui-extensions";
|
|
3514
|
+
|
|
3515
|
+
// src/utils/tagVariants.js
|
|
3516
|
+
var DEFAULT_VARIANT = "default";
|
|
3517
|
+
var DANGER_VARIANT = "danger";
|
|
3518
|
+
var ERROR_VARIANT = "error";
|
|
3519
|
+
var SUCCESS_MATCHERS = [
|
|
3520
|
+
"active",
|
|
3521
|
+
"success",
|
|
3522
|
+
"succeeded",
|
|
3523
|
+
"complete",
|
|
3524
|
+
"completed",
|
|
3525
|
+
"approved",
|
|
3526
|
+
"won",
|
|
3527
|
+
"healthy",
|
|
3528
|
+
"enabled",
|
|
3529
|
+
"connected",
|
|
3530
|
+
"paid",
|
|
3531
|
+
"live",
|
|
3532
|
+
"published",
|
|
3533
|
+
"available",
|
|
3534
|
+
"synced",
|
|
3535
|
+
"resolved"
|
|
3536
|
+
];
|
|
3537
|
+
var WARNING_MATCHERS = [
|
|
3538
|
+
"warning",
|
|
3539
|
+
"at risk",
|
|
3540
|
+
"risky",
|
|
3541
|
+
"pending",
|
|
3542
|
+
"paused",
|
|
3543
|
+
"pause",
|
|
3544
|
+
"on hold",
|
|
3545
|
+
"hold",
|
|
3546
|
+
"review",
|
|
3547
|
+
"expiring",
|
|
3548
|
+
"trial",
|
|
3549
|
+
"in progress",
|
|
3550
|
+
"awaiting",
|
|
3551
|
+
"scheduled"
|
|
3552
|
+
];
|
|
3553
|
+
var DANGER_MATCHERS = [
|
|
3554
|
+
"danger",
|
|
3555
|
+
"error",
|
|
3556
|
+
"failed",
|
|
3557
|
+
"failure",
|
|
3558
|
+
"inactive",
|
|
3559
|
+
"disabled",
|
|
3560
|
+
"blocked",
|
|
3561
|
+
"cancelled",
|
|
3562
|
+
"canceled",
|
|
3563
|
+
"rejected",
|
|
3564
|
+
"denied",
|
|
3565
|
+
"churned",
|
|
3566
|
+
"lost",
|
|
3567
|
+
"overdue",
|
|
3568
|
+
"expired",
|
|
3569
|
+
"offline",
|
|
3570
|
+
"deleted",
|
|
3571
|
+
"archived",
|
|
3572
|
+
"unpaid"
|
|
3573
|
+
];
|
|
3574
|
+
var INFO_MATCHERS = [
|
|
3575
|
+
"info",
|
|
3576
|
+
"new",
|
|
3577
|
+
"queued",
|
|
3578
|
+
"processing",
|
|
3579
|
+
"progress",
|
|
3580
|
+
"upcoming",
|
|
3581
|
+
"draft",
|
|
3582
|
+
"open"
|
|
3583
|
+
];
|
|
3584
|
+
var normalizeTagValue = (value) => {
|
|
3585
|
+
if (value == null) return "";
|
|
3586
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
3587
|
+
return String(value).trim().toLowerCase().replace(/[_-]+/g, " ").replace(/\s+/g, " ");
|
|
3588
|
+
};
|
|
3589
|
+
var matchesAny = (value, matchers) => matchers.some((matcher) => {
|
|
3590
|
+
if (value === matcher) return true;
|
|
3591
|
+
return ` ${value} `.includes(` ${matcher} `);
|
|
3592
|
+
});
|
|
3593
|
+
var getSemanticVariant = (value, options = {}) => {
|
|
3594
|
+
const normalized = normalizeTagValue(value);
|
|
3595
|
+
const fallback = options.fallback || DEFAULT_VARIANT;
|
|
3596
|
+
if (!normalized) return fallback;
|
|
3597
|
+
if (options.overrides) {
|
|
3598
|
+
const overrideKey = Object.keys(options.overrides).find(
|
|
3599
|
+
(key) => normalizeTagValue(key) === normalized
|
|
3600
|
+
);
|
|
3601
|
+
if (overrideKey) return options.overrides[overrideKey];
|
|
3602
|
+
}
|
|
3603
|
+
if (normalized === "true") return "success";
|
|
3604
|
+
if (normalized === "false") return fallback;
|
|
3605
|
+
if (matchesAny(normalized, SUCCESS_MATCHERS)) return "success";
|
|
3606
|
+
if (matchesAny(normalized, DANGER_MATCHERS)) return DANGER_VARIANT;
|
|
3607
|
+
if (matchesAny(normalized, WARNING_MATCHERS)) return "warning";
|
|
3608
|
+
if (matchesAny(normalized, INFO_MATCHERS)) return "info";
|
|
3609
|
+
return fallback;
|
|
3610
|
+
};
|
|
3611
|
+
var getAutoTagVariant = (value, options = {}) => {
|
|
3612
|
+
const semanticVariant = getSemanticVariant(value, options);
|
|
3613
|
+
return semanticVariant === DANGER_VARIANT ? ERROR_VARIANT : semanticVariant;
|
|
3614
|
+
};
|
|
3615
|
+
var getAutoStatusTagVariant = (value, options = {}) => getSemanticVariant(value, options);
|
|
3616
|
+
var getAutoTagDisplayValue = (value) => {
|
|
3617
|
+
if (typeof value === "boolean") return value ? "True" : "False";
|
|
3618
|
+
return value;
|
|
3619
|
+
};
|
|
3620
|
+
var DEFAULT_STATUS_TAG_COLOR_ORDER = [
|
|
3621
|
+
"success",
|
|
3622
|
+
"warning",
|
|
3623
|
+
"danger",
|
|
3624
|
+
"error",
|
|
3625
|
+
"info",
|
|
3626
|
+
"default"
|
|
3627
|
+
];
|
|
3628
|
+
var createStatusTagSortComparator = (options = {}) => {
|
|
3629
|
+
const {
|
|
3630
|
+
variantOrder = DEFAULT_STATUS_TAG_COLOR_ORDER,
|
|
3631
|
+
overrides,
|
|
3632
|
+
fallback,
|
|
3633
|
+
getLabel
|
|
3634
|
+
} = options;
|
|
3635
|
+
const variantIndex = (variant) => {
|
|
3636
|
+
const idx = variantOrder.indexOf(variant);
|
|
3637
|
+
return idx === -1 ? variantOrder.length : idx;
|
|
3638
|
+
};
|
|
3639
|
+
const labelOf = (value) => {
|
|
3640
|
+
if (getLabel) return String(getLabel(value) ?? "");
|
|
3641
|
+
if (value == null) return "";
|
|
3642
|
+
return String(getAutoTagDisplayValue(value) ?? "");
|
|
3643
|
+
};
|
|
3644
|
+
return (aVal, bVal) => {
|
|
3645
|
+
const aVariant = getSemanticVariant(aVal, { overrides, fallback });
|
|
3646
|
+
const bVariant = getSemanticVariant(bVal, { overrides, fallback });
|
|
3647
|
+
const diff = variantIndex(aVariant) - variantIndex(bVariant);
|
|
3648
|
+
if (diff !== 0) return diff;
|
|
3649
|
+
return labelOf(aVal).localeCompare(labelOf(bVal));
|
|
3650
|
+
};
|
|
3651
|
+
};
|
|
3652
|
+
|
|
3653
|
+
// src/common-components/AutoTag.js
|
|
3654
|
+
var AutoTag = ({
|
|
3655
|
+
value,
|
|
3656
|
+
tag,
|
|
3657
|
+
children,
|
|
3658
|
+
variant,
|
|
3659
|
+
overrides,
|
|
3660
|
+
fallback,
|
|
3661
|
+
...props
|
|
3662
|
+
}) => {
|
|
3663
|
+
const resolvedValue = value ?? tag ?? children;
|
|
3664
|
+
const displayValue = children ?? getAutoTagDisplayValue(resolvedValue);
|
|
3665
|
+
const resolvedVariant = variant || getAutoTagVariant(resolvedValue, {
|
|
3666
|
+
overrides,
|
|
3667
|
+
fallback
|
|
3668
|
+
});
|
|
3669
|
+
return React3.createElement(
|
|
3670
|
+
Tag2,
|
|
3671
|
+
{ variant: resolvedVariant, ...props },
|
|
3672
|
+
displayValue
|
|
3673
|
+
);
|
|
3674
|
+
};
|
|
3675
|
+
|
|
3676
|
+
// src/common-components/AutoStatusTag.js
|
|
3677
|
+
import React4 from "react";
|
|
3678
|
+
import { StatusTag } from "@hubspot/ui-extensions";
|
|
3679
|
+
var AutoStatusTag = ({
|
|
3680
|
+
value,
|
|
3681
|
+
status,
|
|
3682
|
+
children,
|
|
3683
|
+
variant,
|
|
3684
|
+
overrides,
|
|
3685
|
+
fallback,
|
|
3686
|
+
...props
|
|
3687
|
+
}) => {
|
|
3688
|
+
const resolvedValue = value ?? status ?? children;
|
|
3689
|
+
const displayValue = children ?? getAutoTagDisplayValue(resolvedValue);
|
|
3690
|
+
const resolvedVariant = variant || getAutoStatusTagVariant(resolvedValue, {
|
|
3691
|
+
overrides,
|
|
3692
|
+
fallback
|
|
3693
|
+
});
|
|
3694
|
+
return React4.createElement(
|
|
3695
|
+
StatusTag,
|
|
3696
|
+
{ variant: resolvedVariant, ...props },
|
|
3697
|
+
displayValue
|
|
3698
|
+
);
|
|
3699
|
+
};
|
|
3700
|
+
|
|
3701
|
+
// src/common-components/KeyValueList.js
|
|
3702
|
+
import React5 from "react";
|
|
3703
|
+
import { DescriptionList, DescriptionListItem, Flex as Flex3 } from "@hubspot/ui-extensions";
|
|
3704
|
+
|
|
3705
|
+
// src/common-components/SectionHeader.js
|
|
3706
|
+
import React6 from "react";
|
|
3707
|
+
import { Flex as Flex4, Heading, Text as Text3 } from "@hubspot/ui-extensions";
|
|
3346
3708
|
export {
|
|
3709
|
+
AutoStatusTag,
|
|
3710
|
+
AutoTag,
|
|
3347
3711
|
DataTable,
|
|
3348
3712
|
FormBuilder,
|
|
3713
|
+
createStatusTagSortComparator,
|
|
3714
|
+
getAutoStatusTagVariant,
|
|
3715
|
+
getAutoTagVariant,
|
|
3349
3716
|
useFormPrefill
|
|
3350
3717
|
};
|