hs-uix 1.1.0 → 1.2.1
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/datatable.js +23 -9
- package/dist/datatable.mjs +23 -9
- package/dist/form.js +187 -44
- package/dist/form.mjs +187 -44
- package/dist/index.js +210 -53
- package/dist/index.mjs +210 -53
- package/form.d.ts +1 -0
- package/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/form.mjs
CHANGED
|
@@ -136,7 +136,6 @@ var runDefaultFieldValidator = (value, field, allValues) => {
|
|
|
136
136
|
if (!isTimeValueObject(value)) return `${errorPrefix} has an invalid time`;
|
|
137
137
|
break;
|
|
138
138
|
case "datetime": {
|
|
139
|
-
if (isDateValueObject(value)) break;
|
|
140
139
|
if (!isPlainObject(value)) return `${errorPrefix} has an invalid date/time`;
|
|
141
140
|
const hasDate = value.date !== void 0;
|
|
142
141
|
const hasTime = value.time !== void 0;
|
|
@@ -203,7 +202,7 @@ var collectAsyncValidatorPromises = (value, field, allValues, context) => {
|
|
|
203
202
|
var runValidators = (value, field, allValues, fieldTypes, options = {}) => {
|
|
204
203
|
const includeCustomValidators = options.includeCustomValidators !== false;
|
|
205
204
|
const msg = options.messages || {};
|
|
206
|
-
if (field.type === "display" || field.type === "crmPropertyList" || field.type === "crmAssociationPropertyList") return null;
|
|
205
|
+
if (field.type === "display" || field.type === "crmPropertyList" || field.type === "crmAssociationPropertyList" || field.type === "fieldGroup") return null;
|
|
207
206
|
const isRequired = resolveRequired(field, allValues);
|
|
208
207
|
const plugin = fieldTypes && fieldTypes[field.type];
|
|
209
208
|
const empty = plugin && plugin.isEmpty ? plugin.isEmpty(value) : isValueEmpty(value, field);
|
|
@@ -350,6 +349,8 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
350
349
|
// (values, { reset, rawValues }) => void | Promise
|
|
351
350
|
transformValues,
|
|
352
351
|
// (values) => values — reshape before submit
|
|
352
|
+
transformInitialValues,
|
|
353
|
+
// (rawInitialValues) => values — reshape raw data on load
|
|
353
354
|
onBeforeSubmit,
|
|
354
355
|
// (values) => boolean | Promise<boolean> — intercept submit
|
|
355
356
|
onSubmitSuccess,
|
|
@@ -513,12 +514,27 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
513
514
|
prevSuccessRef.current = formSuccess;
|
|
514
515
|
}, [addAlert, formSuccess, successTitle]);
|
|
515
516
|
const computeInitialValues = () => {
|
|
517
|
+
const resolved = transformInitialValues && initialValues ? transformInitialValues(initialValues) : initialValues;
|
|
516
518
|
const vals = {};
|
|
517
519
|
for (const field of fields) {
|
|
518
520
|
if (field.type === "display" || field.type === "crmPropertyList" || field.type === "crmAssociationPropertyList") continue;
|
|
521
|
+
if (field.type === "fieldGroup" && field.items && field.fields) {
|
|
522
|
+
for (const item of field.items) {
|
|
523
|
+
const subFields = field.fields(item);
|
|
524
|
+
for (const sf of subFields) {
|
|
525
|
+
const plugin2 = fieldTypes && fieldTypes[sf.type];
|
|
526
|
+
const emptyValue2 = plugin2 && plugin2.getEmptyValue ? plugin2.getEmptyValue() : getEmptyValue(sf);
|
|
527
|
+
let init2 = resolved && resolved[sf.name] !== void 0 ? resolved[sf.name] : sf.defaultValue !== void 0 ? sf.defaultValue : emptyValue2;
|
|
528
|
+
if (sf.transformIn) init2 = sf.transformIn(init2);
|
|
529
|
+
vals[sf.name] = init2;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
519
534
|
const plugin = fieldTypes && fieldTypes[field.type];
|
|
520
535
|
const emptyValue = plugin && plugin.getEmptyValue ? plugin.getEmptyValue() : getEmptyValue(field);
|
|
521
|
-
|
|
536
|
+
let init = resolved && resolved[field.name] !== void 0 ? resolved[field.name] : field.defaultValue !== void 0 ? field.defaultValue : emptyValue;
|
|
537
|
+
if (field.transformIn) init = field.transformIn(init);
|
|
522
538
|
vals[field.name] = init;
|
|
523
539
|
}
|
|
524
540
|
return vals;
|
|
@@ -551,7 +567,14 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
551
567
|
formErrorsRef.current = formErrors;
|
|
552
568
|
const fieldByName = useMemo(() => {
|
|
553
569
|
const map = /* @__PURE__ */ new Map();
|
|
554
|
-
for (const field of fields)
|
|
570
|
+
for (const field of fields) {
|
|
571
|
+
map.set(field.name, field);
|
|
572
|
+
if (field.type === "fieldGroup" && field.items && field.fields) {
|
|
573
|
+
for (const item of field.items) {
|
|
574
|
+
for (const sf of field.fields(item)) map.set(sf.name, sf);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
555
578
|
return map;
|
|
556
579
|
}, [fields]);
|
|
557
580
|
const isDev = typeof process === "undefined" || !process.env || process.env.NODE_ENV !== "production";
|
|
@@ -973,23 +996,27 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
973
996
|
);
|
|
974
997
|
const handleFieldInput = useCallback(
|
|
975
998
|
(name, value) => {
|
|
999
|
+
handleFieldChange(name, value);
|
|
976
1000
|
if (!validateOnChange) return;
|
|
977
1001
|
const err = validateField(name, value);
|
|
978
1002
|
updateErrors({ [name]: err });
|
|
979
1003
|
},
|
|
980
|
-
[validateOnChange, validateField, updateErrors]
|
|
1004
|
+
[validateOnChange, validateField, updateErrors, handleFieldChange]
|
|
981
1005
|
);
|
|
982
1006
|
const handleFieldBlur = useCallback(
|
|
983
1007
|
(name, value) => {
|
|
984
|
-
if (!validateOnBlur) return;
|
|
985
1008
|
const resolvedValue = value != null ? value : formValuesRef.current[name];
|
|
1009
|
+
if (value != null && value !== formValuesRef.current[name]) {
|
|
1010
|
+
handleFieldChange(name, value);
|
|
1011
|
+
}
|
|
1012
|
+
if (!validateOnBlur) return;
|
|
986
1013
|
const err = validateField(name, resolvedValue);
|
|
987
1014
|
updateErrors({ [name]: err });
|
|
988
1015
|
if (!err) {
|
|
989
1016
|
triggerAsyncValidation(name, resolvedValue);
|
|
990
1017
|
}
|
|
991
1018
|
},
|
|
992
|
-
[validateOnBlur, validateField, updateErrors, triggerAsyncValidation]
|
|
1019
|
+
[validateOnBlur, validateField, updateErrors, triggerAsyncValidation, handleFieldChange]
|
|
993
1020
|
);
|
|
994
1021
|
const handleSubmit = useCallback(
|
|
995
1022
|
async (e) => {
|
|
@@ -1022,8 +1049,17 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1022
1049
|
const rawValues = {};
|
|
1023
1050
|
for (const key of Object.keys(formValues)) {
|
|
1024
1051
|
const f = fieldByName.get(key);
|
|
1025
|
-
if (f && (f.type === "display" || f.type === "crmPropertyList" || f.type === "crmAssociationPropertyList")) continue;
|
|
1026
|
-
rawValues[key] = formValues[key];
|
|
1052
|
+
if (f && (f.type === "display" || f.type === "crmPropertyList" || f.type === "crmAssociationPropertyList" || f.type === "fieldGroup")) continue;
|
|
1053
|
+
rawValues[key] = f && f.transformOut ? f.transformOut(formValues[key]) : formValues[key];
|
|
1054
|
+
}
|
|
1055
|
+
for (const f of fields) {
|
|
1056
|
+
if (f.type !== "fieldGroup" || !f.items || !f.fields) continue;
|
|
1057
|
+
for (const item of f.items) {
|
|
1058
|
+
for (const sf of f.fields(item)) {
|
|
1059
|
+
if (formValues[sf.name] === void 0) continue;
|
|
1060
|
+
rawValues[sf.name] = sf.transformOut ? sf.transformOut(formValues[sf.name]) : formValues[sf.name];
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1027
1063
|
}
|
|
1028
1064
|
const submitValues = transformValues ? transformValues(rawValues) : rawValues;
|
|
1029
1065
|
if (onBeforeSubmit) {
|
|
@@ -1166,10 +1202,125 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1166
1202
|
const fieldOnChange = field.debounce ? (v) => handleDebouncedFieldChange(field.name, v) : (v) => handleFieldChange(field.name, v);
|
|
1167
1203
|
if (field.type === "display") {
|
|
1168
1204
|
if (field.render) {
|
|
1169
|
-
return field.render({
|
|
1205
|
+
return field.render({
|
|
1206
|
+
allValues: formValues,
|
|
1207
|
+
setFieldValue: (name, value) => handleFieldChange(name, value),
|
|
1208
|
+
setFieldError: (name, message) => updateErrors({ [name]: message })
|
|
1209
|
+
});
|
|
1170
1210
|
}
|
|
1171
1211
|
return null;
|
|
1172
1212
|
}
|
|
1213
|
+
if (field.type === "fieldGroup") {
|
|
1214
|
+
const items = field.items || [];
|
|
1215
|
+
const fieldsFn = field.fields;
|
|
1216
|
+
if (!fieldsFn) return null;
|
|
1217
|
+
const groupColumns = field.columns || 1;
|
|
1218
|
+
const showItemLabel = field.showItemLabel !== false;
|
|
1219
|
+
return /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "xs" }, field.label && /* @__PURE__ */ React.createElement(Text, { format: { fontWeight: "demibold" } }, field.label), field.description && /* @__PURE__ */ React.createElement(Text, { variant: "microcopy" }, field.description), items.map((item, itemIdx) => {
|
|
1220
|
+
const subFields = fieldsFn(item);
|
|
1221
|
+
return /* @__PURE__ */ React.createElement(Flex, { key: item.key || itemIdx, direction: "row", gap: "xs", align: "end" }, showItemLabel && item.label && /* @__PURE__ */ React.createElement(Box, { flex: 1 }, itemIdx === 0 ? /* @__PURE__ */ React.createElement(
|
|
1222
|
+
Input,
|
|
1223
|
+
{
|
|
1224
|
+
name: `_fieldGroup-label-${field.name}-${itemIdx}`,
|
|
1225
|
+
label: "\xA0",
|
|
1226
|
+
value: item.label,
|
|
1227
|
+
readOnly: true,
|
|
1228
|
+
disabled: true
|
|
1229
|
+
}
|
|
1230
|
+
) : /* @__PURE__ */ React.createElement(
|
|
1231
|
+
Input,
|
|
1232
|
+
{
|
|
1233
|
+
name: `_fieldGroup-label-${field.name}-${itemIdx}`,
|
|
1234
|
+
value: item.label,
|
|
1235
|
+
readOnly: true,
|
|
1236
|
+
disabled: true
|
|
1237
|
+
}
|
|
1238
|
+
)), subFields.map((sf) => {
|
|
1239
|
+
const sfValue = formValues[sf.name];
|
|
1240
|
+
const sfError = formErrors[sf.name] || null;
|
|
1241
|
+
const sfLabel = itemIdx === 0 ? sf.label : void 0;
|
|
1242
|
+
const sfReadOnly = sf.readOnly || formReadOnly;
|
|
1243
|
+
const sfDisabled = disabled || sf.disabled || formReadOnly;
|
|
1244
|
+
const sfOnChange = sf.debounce ? (v) => handleDebouncedFieldChange(sf.name, v) : (v) => handleFieldChange(sf.name, v);
|
|
1245
|
+
const sfProps = {
|
|
1246
|
+
name: sf.name,
|
|
1247
|
+
label: sfLabel,
|
|
1248
|
+
placeholder: sf.placeholder,
|
|
1249
|
+
description: itemIdx === 0 ? sf.description : void 0,
|
|
1250
|
+
readOnly: sfReadOnly,
|
|
1251
|
+
disabled: sfDisabled,
|
|
1252
|
+
error: !!sfError,
|
|
1253
|
+
validationMessage: sfError || void 0,
|
|
1254
|
+
...sf.fieldProps || {}
|
|
1255
|
+
};
|
|
1256
|
+
let sfElement;
|
|
1257
|
+
switch (sf.type) {
|
|
1258
|
+
case "select":
|
|
1259
|
+
sfElement = /* @__PURE__ */ React.createElement(
|
|
1260
|
+
Select,
|
|
1261
|
+
{
|
|
1262
|
+
...sfProps,
|
|
1263
|
+
value: sfValue,
|
|
1264
|
+
options: resolveOptions(sf, formValues),
|
|
1265
|
+
onChange: sfOnChange
|
|
1266
|
+
}
|
|
1267
|
+
);
|
|
1268
|
+
break;
|
|
1269
|
+
case "number":
|
|
1270
|
+
sfElement = /* @__PURE__ */ React.createElement(
|
|
1271
|
+
NumberInput,
|
|
1272
|
+
{
|
|
1273
|
+
...sfProps,
|
|
1274
|
+
value: sfValue,
|
|
1275
|
+
onChange: sfOnChange,
|
|
1276
|
+
onBlur: (v) => handleFieldBlur(sf.name, v)
|
|
1277
|
+
}
|
|
1278
|
+
);
|
|
1279
|
+
break;
|
|
1280
|
+
case "toggle":
|
|
1281
|
+
sfElement = /* @__PURE__ */ React.createElement(
|
|
1282
|
+
Toggle,
|
|
1283
|
+
{
|
|
1284
|
+
name: sf.name,
|
|
1285
|
+
label: sfLabel || sf.label,
|
|
1286
|
+
checked: !!sfValue,
|
|
1287
|
+
size: sf.size || "md",
|
|
1288
|
+
labelDisplay: sf.labelDisplay || "top",
|
|
1289
|
+
readonly: sfReadOnly,
|
|
1290
|
+
disabled: sfDisabled,
|
|
1291
|
+
onChange: sfOnChange,
|
|
1292
|
+
...sf.fieldProps || {}
|
|
1293
|
+
}
|
|
1294
|
+
);
|
|
1295
|
+
break;
|
|
1296
|
+
case "time":
|
|
1297
|
+
sfElement = /* @__PURE__ */ React.createElement(
|
|
1298
|
+
TimeInput,
|
|
1299
|
+
{
|
|
1300
|
+
...sfProps,
|
|
1301
|
+
value: sfValue,
|
|
1302
|
+
interval: sf.interval,
|
|
1303
|
+
onChange: sfOnChange,
|
|
1304
|
+
onBlur: (v) => handleFieldBlur(sf.name, v)
|
|
1305
|
+
}
|
|
1306
|
+
);
|
|
1307
|
+
break;
|
|
1308
|
+
default:
|
|
1309
|
+
sfElement = /* @__PURE__ */ React.createElement(
|
|
1310
|
+
Input,
|
|
1311
|
+
{
|
|
1312
|
+
...sfProps,
|
|
1313
|
+
value: sfValue || "",
|
|
1314
|
+
onChange: sfOnChange,
|
|
1315
|
+
onInput: (v) => handleFieldInput(sf.name, v),
|
|
1316
|
+
onBlur: (v) => handleFieldBlur(sf.name, v)
|
|
1317
|
+
}
|
|
1318
|
+
);
|
|
1319
|
+
}
|
|
1320
|
+
return /* @__PURE__ */ React.createElement(Box, { key: sf.name, flex: 1 }, sfElement);
|
|
1321
|
+
}));
|
|
1322
|
+
}));
|
|
1323
|
+
}
|
|
1173
1324
|
if (field.type === "crmPropertyList") {
|
|
1174
1325
|
return /* @__PURE__ */ React.createElement(
|
|
1175
1326
|
CrmPropertyList,
|
|
@@ -1714,38 +1865,19 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1714
1865
|
}
|
|
1715
1866
|
return elements;
|
|
1716
1867
|
};
|
|
1717
|
-
const
|
|
1868
|
+
const renderSingleColumnLayout = (fieldSubset) => {
|
|
1718
1869
|
const fieldList = fieldSubset || visibleFields;
|
|
1719
|
-
const rows = [];
|
|
1720
|
-
let i = 0;
|
|
1721
|
-
while (i < fieldList.length) {
|
|
1722
|
-
const field = fieldList[i];
|
|
1723
|
-
if (field.width === "half" && i + 1 < fieldList.length && fieldList[i + 1].width === "half" && !getDependsOnName(field)) {
|
|
1724
|
-
rows.push({ type: "pair", fields: [fieldList[i], fieldList[i + 1]] });
|
|
1725
|
-
i += 2;
|
|
1726
|
-
} else {
|
|
1727
|
-
rows.push({ type: "single", field });
|
|
1728
|
-
i++;
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
1870
|
const elements = [];
|
|
1732
1871
|
const processedDeps = /* @__PURE__ */ new Set();
|
|
1733
|
-
for (const
|
|
1734
|
-
if (
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
elements.push(
|
|
1742
|
-
/* @__PURE__ */ React.createElement(React.Fragment, { key: field.name }, renderField(field))
|
|
1743
|
-
);
|
|
1744
|
-
const dependents = getDependents(field);
|
|
1745
|
-
if (dependents.length > 0) {
|
|
1746
|
-
for (const dep of dependents) processedDeps.add(dep.name);
|
|
1747
|
-
elements.push(renderDependentGroup(field, dependents));
|
|
1748
|
-
}
|
|
1872
|
+
for (const field of fieldList) {
|
|
1873
|
+
if (processedDeps.has(field.name)) continue;
|
|
1874
|
+
elements.push(
|
|
1875
|
+
/* @__PURE__ */ React.createElement(React.Fragment, { key: field.name }, renderField(field))
|
|
1876
|
+
);
|
|
1877
|
+
const dependents = getDependents(field);
|
|
1878
|
+
if (dependents.length > 0) {
|
|
1879
|
+
for (const dep of dependents) processedDeps.add(dep.name);
|
|
1880
|
+
elements.push(renderDependentGroup(field, dependents));
|
|
1749
1881
|
}
|
|
1750
1882
|
}
|
|
1751
1883
|
return elements;
|
|
@@ -1756,10 +1888,20 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1756
1888
|
let batch = [];
|
|
1757
1889
|
const flushBatch = () => {
|
|
1758
1890
|
if (batch.length === 0) return;
|
|
1759
|
-
|
|
1760
|
-
|
|
1891
|
+
if (maxColumns) {
|
|
1892
|
+
const chunks = Array.from(
|
|
1893
|
+
{ length: Math.ceil(batch.length / maxColumns) },
|
|
1894
|
+
(_, i) => batch.slice(i * maxColumns, i * maxColumns + maxColumns)
|
|
1895
|
+
);
|
|
1896
|
+
for (const chunk of chunks) {
|
|
1897
|
+
const remainder = maxColumns - chunk.length;
|
|
1898
|
+
elements.push(
|
|
1899
|
+
/* @__PURE__ */ React.createElement(Flex, { key: `ag-${chunk[0].name}`, direction: "row", gap }, chunk.map((f) => /* @__PURE__ */ React.createElement(Box, { key: f.name, flex: 1 }, renderField(f))), remainder > 0 && /* @__PURE__ */ React.createElement(Box, { flex: remainder }))
|
|
1900
|
+
);
|
|
1901
|
+
}
|
|
1902
|
+
} else {
|
|
1761
1903
|
elements.push(
|
|
1762
|
-
/* @__PURE__ */ React.createElement(AutoGrid, { key: `ag-${
|
|
1904
|
+
/* @__PURE__ */ React.createElement(AutoGrid, { key: `ag-${batch[0].name}`, columnWidth, flexible: true, gap }, batch.map((f) => /* @__PURE__ */ React.createElement(React.Fragment, { key: f.name }, renderField(f))))
|
|
1763
1905
|
);
|
|
1764
1906
|
}
|
|
1765
1907
|
batch = [];
|
|
@@ -1818,7 +1960,7 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1818
1960
|
if (layout && fieldSubset === visibleFields) return renderExplicitLayout();
|
|
1819
1961
|
if (columnWidth) return renderAutoGridLayout(fieldSubset);
|
|
1820
1962
|
if (columns > 1) return renderGridLayout(fieldSubset);
|
|
1821
|
-
return
|
|
1963
|
+
return renderSingleColumnLayout(fieldSubset);
|
|
1822
1964
|
};
|
|
1823
1965
|
const renderSections = () => {
|
|
1824
1966
|
const hasSections = Array.isArray(sections) && sections.length > 0;
|
|
@@ -1831,7 +1973,8 @@ var FormBuilder = forwardRef(function FormBuilder2(props, ref) {
|
|
|
1831
1973
|
for (const sec of sections) {
|
|
1832
1974
|
const sectionFields = sec.fields ? visibleFields.filter((f) => sec.fields.includes(f.name)) : [];
|
|
1833
1975
|
if (sectionFields.length === 0) continue;
|
|
1834
|
-
const
|
|
1976
|
+
const sectionContext = { values: formValues, errors: formErrors };
|
|
1977
|
+
const accordionContent = /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap }, sec.renderBefore && sec.renderBefore(sectionContext), renderFieldSubset(sectionFields), sec.renderAfter && sec.renderAfter(sectionContext));
|
|
1835
1978
|
const accordion = /* @__PURE__ */ React.createElement(
|
|
1836
1979
|
Accordion,
|
|
1837
1980
|
{
|