@qoretechnologies/reqraft 0.10.2 → 0.10.4
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/design/COMPACT_ENGINE_REDESIGN.md +156 -0
- package/design/FORM_ENGINE_COMPACT_UX_PLAN.md +353 -0
- package/dist/components/form/engine/CompactRow.d.ts.map +1 -1
- package/dist/components/form/engine/CompactRow.js +153 -94
- package/dist/components/form/engine/CompactRow.js.map +1 -1
- package/dist/components/form/engine/CompactToolbar.d.ts.map +1 -1
- package/dist/components/form/engine/CompactToolbar.js +130 -94
- package/dist/components/form/engine/CompactToolbar.js.map +1 -1
- package/dist/components/form/engine/FormEngine.d.ts.map +1 -1
- package/dist/components/form/engine/FormEngine.js +181 -45
- package/dist/components/form/engine/FormEngine.js.map +1 -1
- package/dist/components/form/engine/compactRowStyles.d.ts +6 -3
- package/dist/components/form/engine/compactRowStyles.d.ts.map +1 -1
- package/dist/components/form/engine/compactRowStyles.js +70 -48
- package/dist/components/form/engine/compactRowStyles.js.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.d.ts +1 -0
- package/dist/components/form/engine/compactToolbarContext.d.ts.map +1 -1
- package/dist/components/form/engine/compactToolbarContext.js.map +1 -1
- package/dist/components/form/engine/readFirst.d.ts +19 -0
- package/dist/components/form/engine/readFirst.d.ts.map +1 -1
- package/dist/components/form/engine/readFirst.js +22 -1
- package/dist/components/form/engine/readFirst.js.map +1 -1
- package/dist/components/form/engine/variants/VariantCalmTable.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantCalmTable.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantCalmTable.js +94 -0
- package/dist/components/form/engine/variants/VariantCalmTable.js.map +1 -0
- package/dist/components/form/engine/variants/VariantCards.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantCards.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantCards.js +80 -0
- package/dist/components/form/engine/variants/VariantCards.js.map +1 -0
- package/dist/components/form/engine/variants/VariantFocus.d.ts +7 -0
- package/dist/components/form/engine/variants/VariantFocus.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantFocus.js +138 -0
- package/dist/components/form/engine/variants/VariantFocus.js.map +1 -0
- package/dist/components/form/engine/variants/VariantMinimal.d.ts +6 -0
- package/dist/components/form/engine/variants/VariantMinimal.d.ts.map +1 -0
- package/dist/components/form/engine/variants/VariantMinimal.js +73 -0
- package/dist/components/form/engine/variants/VariantMinimal.js.map +1 -0
- package/dist/components/form/engine/variants/focusDemo.d.ts +13 -0
- package/dist/components/form/engine/variants/focusDemo.d.ts.map +1 -0
- package/dist/components/form/engine/variants/focusDemo.js +139 -0
- package/dist/components/form/engine/variants/focusDemo.js.map +1 -0
- package/dist/components/form/engine/variants/variantModel.d.ts +70 -0
- package/dist/components/form/engine/variants/variantModel.d.ts.map +1 -0
- package/dist/components/form/engine/variants/variantModel.js +133 -0
- package/dist/components/form/engine/variants/variantModel.js.map +1 -0
- package/dist/components/form/engine/variants/variantParts.d.ts +79 -0
- package/dist/components/form/engine/variants/variantParts.d.ts.map +1 -0
- package/dist/components/form/engine/variants/variantParts.js +191 -0
- package/dist/components/form/engine/variants/variantParts.js.map +1 -0
- package/dist/components/form/fields/auto/AutoFormField.d.ts +3 -0
- package/dist/components/form/fields/auto/AutoFormField.d.ts.map +1 -1
- package/dist/components/form/fields/auto/AutoFormField.js +2 -2
- package/dist/components/form/fields/auto/AutoFormField.js.map +1 -1
- package/package.json +1 -1
- package/src/components/form/engine/CompactRow.tsx +256 -234
- package/src/components/form/engine/CompactToolbar.tsx +108 -68
- package/src/components/form/engine/FormEngine.stories.tsx +127 -110
- package/src/components/form/engine/FormEngine.tsx +248 -67
- package/src/components/form/engine/compactRowStyles.ts +207 -134
- package/src/components/form/engine/compactToolbarContext.ts +1 -0
- package/src/components/form/engine/readFirst.ts +35 -0
- package/src/components/form/engine/variants/FormEngineVariants.stories.tsx +119 -0
- package/src/components/form/engine/variants/VariantCalmTable.tsx +242 -0
- package/src/components/form/engine/variants/VariantCards.tsx +212 -0
- package/src/components/form/engine/variants/VariantFocus.tsx +382 -0
- package/src/components/form/engine/variants/VariantMinimal.tsx +170 -0
- package/src/components/form/engine/variants/focusDemo.ts +145 -0
- package/src/components/form/engine/variants/variantModel.ts +216 -0
- package/src/components/form/engine/variants/variantParts.tsx +313 -0
- package/src/components/form/fields/auto/AutoFormField.tsx +5 -0
|
@@ -322,6 +322,10 @@ var FormEngine = function (_a) {
|
|
|
322
322
|
var _x = (0, react_2.useState)(false), showInvalidOptionsOnly = _x[0], setShowInvalidOptionsOnly = _x[1];
|
|
323
323
|
// Which options are expanded into their editor (several can be open at once).
|
|
324
324
|
var _y = (0, react_2.useState)([]), expandedOptions = _y[0], setExpandedOptions = _y[1];
|
|
325
|
+
// Remembers each row's last settled status box, so an actively-edited field
|
|
326
|
+
// stays put when its status flips (e.g. becomes valid) instead of jumping to
|
|
327
|
+
// another box mid-edit and stealing focus. Keyed by option name.
|
|
328
|
+
var settledBucket = (0, react_2.useRef)({});
|
|
325
329
|
// Measured form width (not viewport — the form lives in drawers/panels of
|
|
326
330
|
// arbitrary width) drives the stacked narrow layout.
|
|
327
331
|
var _z = (0, react_use_1.useMeasure)(), compactWrapRef = _z[0], compactWrapWidth = _z[1].width;
|
|
@@ -889,6 +893,67 @@ var FormEngine = function (_a) {
|
|
|
889
893
|
return __assign(__assign({}, newValue), (_a = {}, _a[optionName] = option, _a));
|
|
890
894
|
}, {});
|
|
891
895
|
}, [showInvalidOptionsOnly, JSON.stringify(availableOptions)]);
|
|
896
|
+
// Read-first STATUS / BOX for one option — lifted to component scope so the
|
|
897
|
+
// status boxes (renderCompact) and the header's "needs attention" count share
|
|
898
|
+
// exactly one definition. One-of group members travel together (bucket by the
|
|
899
|
+
// group's satisfaction); everything else by its own status.
|
|
900
|
+
var schemaMsgIntent = (0, react_2.useCallback)(function (name) {
|
|
901
|
+
var _a;
|
|
902
|
+
var msgs = (((_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.messages) || []);
|
|
903
|
+
if (msgs.some(function (m) { return m.intent === 'danger'; }))
|
|
904
|
+
return 'danger';
|
|
905
|
+
if (msgs.some(function (m) { return m.intent === 'warning'; }))
|
|
906
|
+
return 'warning';
|
|
907
|
+
return undefined;
|
|
908
|
+
}, [JSON.stringify(options)]);
|
|
909
|
+
var getOptionStatus = (0, react_2.useCallback)(function (name, hidden) {
|
|
910
|
+
var _a;
|
|
911
|
+
if (hidden === void 0) { hidden = false; }
|
|
912
|
+
if (hidden)
|
|
913
|
+
return 'optional';
|
|
914
|
+
var schema = options === null || options === void 0 ? void 0 : options[name];
|
|
915
|
+
var type = ((schema === null || schema === void 0 ? void 0 : schema.ui_type) || (schema === null || schema === void 0 ? void 0 : schema.type));
|
|
916
|
+
var value = (_a = availableOptions === null || availableOptions === void 0 ? void 0 : availableOptions[name]) === null || _a === void 0 ? void 0 : _a.value;
|
|
917
|
+
var empty = (0, readFirst_1.isOptionValueEmpty)(value);
|
|
918
|
+
var reqGroups = (schema === null || schema === void 0 ? void 0 : schema.required_groups) || [];
|
|
919
|
+
var required = !!((schema === null || schema === void 0 ? void 0 : schema.required) || reqGroups.length);
|
|
920
|
+
var covered = empty &&
|
|
921
|
+
reqGroups.some(function (g) {
|
|
922
|
+
var by = requiredGroupsInfo.satisfiedBy[g];
|
|
923
|
+
return !!by && by !== name;
|
|
924
|
+
});
|
|
925
|
+
var msgIntent = schemaMsgIntent(name);
|
|
926
|
+
var invalid = (!empty && !isOptionValid(name, type, value)) || msgIntent === 'danger';
|
|
927
|
+
return (0, readFirst_1.getReadFirstStatus)({
|
|
928
|
+
empty: empty,
|
|
929
|
+
required: required,
|
|
930
|
+
covered: covered,
|
|
931
|
+
invalid: invalid,
|
|
932
|
+
warned: msgIntent === 'warning',
|
|
933
|
+
});
|
|
934
|
+
}, [
|
|
935
|
+
JSON.stringify(options),
|
|
936
|
+
JSON.stringify(availableOptions),
|
|
937
|
+
isOptionValid,
|
|
938
|
+
requiredGroupsInfo,
|
|
939
|
+
schemaMsgIntent,
|
|
940
|
+
]);
|
|
941
|
+
var getOptionBucket = (0, react_2.useCallback)(function (name, hidden) {
|
|
942
|
+
var _a;
|
|
943
|
+
if (hidden === void 0) { hidden = false; }
|
|
944
|
+
if (!hidden) {
|
|
945
|
+
var reqGroups = ((_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.required_groups) || [];
|
|
946
|
+
if (reqGroups.length) {
|
|
947
|
+
return reqGroups.some(function (g) { return !requiredGroupsInfo.satisfiedBy[g]; }) ? 'attention' : 'set';
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
return (0, readFirst_1.getReadFirstBucket)(getOptionStatus(name, hidden));
|
|
951
|
+
}, [JSON.stringify(options), requiredGroupsInfo, getOptionStatus]);
|
|
952
|
+
// How many fields are in the "Needs attention" box — drives the header link.
|
|
953
|
+
var readFirstAttentionCount = (0, react_2.useMemo)(function () {
|
|
954
|
+
return Object.keys(availableOptions || {}).filter(function (name) { return getOptionBucket(name) === 'attention'; })
|
|
955
|
+
.length;
|
|
956
|
+
}, [JSON.stringify(availableOptions), getOptionBucket]);
|
|
892
957
|
var getIntent = (0, react_2.useCallback)(
|
|
893
958
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
894
959
|
function (optName, type, optValue, _op) {
|
|
@@ -1011,13 +1076,27 @@ var FormEngine = function (_a) {
|
|
|
1011
1076
|
// The info panel below the row keeps showing schema messages while editing —
|
|
1012
1077
|
// rendering them in the editor too would balloon a one-line edit.
|
|
1013
1078
|
suppressSchemaMessages) {
|
|
1014
|
-
var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p
|
|
1079
|
+
var _b, _c, _d, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
1015
1080
|
var type = _a.type, other = __rest(_a, ["type"]);
|
|
1016
1081
|
var operatorParts = (0, exports.fixOperatorValue)(other.op);
|
|
1017
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(
|
|
1018
|
-
var
|
|
1019
|
-
|
|
1020
|
-
|
|
1082
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(function () {
|
|
1083
|
+
var _a;
|
|
1084
|
+
var schemaMsgs = (suppressSchemaMessages ? [] : ((_a = options === null || options === void 0 ? void 0 : options[optionName]) === null || _a === void 0 ? void 0 : _a.messages) || []);
|
|
1085
|
+
if (!schemaMsgs.length)
|
|
1086
|
+
return null;
|
|
1087
|
+
var items = schemaMsgs.map(function (_a, index) {
|
|
1088
|
+
var intent = _a.intent, title = _a.title, content = _a.content;
|
|
1089
|
+
return ((0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { intent: intent, title: title, opaque: false, size: 'small',
|
|
1090
|
+
// Compact: flat (no border) to match the read-row info panels;
|
|
1091
|
+
// classic forms keep the bordered, bottom-margined message.
|
|
1092
|
+
flat: compact || undefined, margin: compact ? undefined : 'bottom', children: content }, title || index));
|
|
1093
|
+
});
|
|
1094
|
+
// Compact: stack them in a 4px-gap panel so a field's messages look
|
|
1095
|
+
// identical whether the row is collapsed (read panel) or expanded.
|
|
1096
|
+
return compact ?
|
|
1097
|
+
(0, jsx_runtime_1.jsx)("div", { className: 'options-readfirst-info-panel', style: { display: 'flex', flexFlow: 'column', gap: 4, marginBottom: 8 }, children: items })
|
|
1098
|
+
: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: items });
|
|
1099
|
+
})(), operators && (0, size_1.default)(operators) ?
|
|
1021
1100
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreControlGroup, { fill: true, wrap: true, className: 'operators', children: operatorParts.map(function (operator, index) {
|
|
1022
1101
|
var _a, _b;
|
|
1023
1102
|
return ((0, jsx_runtime_1.jsxs)(react_2.default.Fragment, { children: [(0, jsx_runtime_1.jsx)(Select_1.SelectFormField, { items: (0, map_1.default)(operators, function (op) { return (__assign(__assign({}, op), { value: op.name })); }), disabled: readOnly, value: operator && "".concat((_a = operators === null || operators === void 0 ? void 0 : operators[operator]) === null || _a === void 0 ? void 0 : _a.name), onChange: function (val) {
|
|
@@ -1033,18 +1112,21 @@ var FormEngine = function (_a) {
|
|
|
1033
1112
|
: null] }, index));
|
|
1034
1113
|
}) }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 5 })] })
|
|
1035
1114
|
: null, (0, react_1.createElement)(TemplateField_1.TemplateField, __assign({ fluid: true }, options === null || options === void 0 ? void 0 : options[optionName], {
|
|
1115
|
+
// Propagate compact so an arg_schema field renders a COMPACT sub-form
|
|
1116
|
+
// (consistent with the parent) rather than the classic FormEngine.
|
|
1117
|
+
compact: compact,
|
|
1036
1118
|
// SEAM: forwarded through TemplateField's rest-spread to AutoFormField,
|
|
1037
1119
|
// which renders consumer-injected editors by field type/ui_type.
|
|
1038
|
-
componentOverrides: componentOverrides, allowTemplates: !!(allowTemplates && ((
|
|
1120
|
+
componentOverrides: componentOverrides, allowTemplates: !!(allowTemplates && ((_b = options === null || options === void 0 ? void 0 : options[optionName]) === null || _b === void 0 ? void 0 : _b.supports_templates)), allowFunctions: !!((_c = options === null || options === void 0 ? void 0 : options[optionName]) === null || _c === void 0 ? void 0 : _c.supports_expressions),
|
|
1039
1121
|
// reqraft: form-level expression fields get the Visual/Text shell
|
|
1040
1122
|
// (DPQL text mode); opt out per-form via `templateFieldProps`.
|
|
1041
|
-
allowTextExpressions: true, allowCustomValues: ((
|
|
1123
|
+
allowTextExpressions: true, allowCustomValues: ((_d = options === null || options === void 0 ? void 0 : options[optionName]) === null || _d === void 0 ? void 0 : _d.supports_custom_values) !== false && type !== 'any', templates: templates.value }, (0, exports.getTypeAndCanBeNull)(type, (_f = options === null || options === void 0 ? void 0 : options[optionName]) === null || _f === void 0 ? void 0 : _f.allowed_values, other.op), { ui_type: type, name: optionName, uniqueName: "".concat(uniqueName ? "".concat(uniqueName, ".") : "".concat(name ? "".concat(name, ".") : '')).concat(optionName), onChange:
|
|
1042
1124
|
// Identity-stable on purpose: the typed fields debounce on
|
|
1043
1125
|
// `[localValue, onChange]` — an inline lambda resets the pending emit
|
|
1044
1126
|
// every render and the typed value can starve.
|
|
1045
|
-
handleValueChange, key: optionName, arg_schema: (
|
|
1127
|
+
handleValueChange, key: optionName, arg_schema: (_g = options === null || options === void 0 ? void 0 : options[optionName]) === null || _g === void 0 ? void 0 : _g.arg_schema, noSoft: !!(rest === null || rest === void 0 ? void 0 : rest.options), value: other.value, isFunction: other.is_expression, isDefaultFunction: ((_h = options === null || options === void 0 ? void 0 : options[optionName]) === null || _h === void 0 ? void 0 : _h.default_view) === 'expression', sensitive: (_j = options === null || options === void 0 ? void 0 : options[optionName]) === null || _j === void 0 ? void 0 : _j.sensitive, default_value: (0, common_1.getDefaultValue)(options === null || options === void 0 ? void 0 : options[optionName]), isDefaultTemplate: ((_k = options === null || options === void 0 ? void 0 : options[optionName]) === null || _k === void 0 ? void 0 : _k.default_view) === 'template', allowed_values: (_l = options === null || options === void 0 ? void 0 : options[optionName]) === null || _l === void 0 ? void 0 : _l.allowed_values, disabled: ((_m = options === null || options === void 0 ? void 0 : options[optionName]) === null || _m === void 0 ? void 0 : _m.disabled) ||
|
|
1046
1128
|
readOnly ||
|
|
1047
|
-
!(0, validations_1.hasAllDependenciesFullfilled)((
|
|
1129
|
+
!(0, validations_1.hasAllDependenciesFullfilled)((_o = options === null || options === void 0 ? void 0 : options[optionName]) === null || _o === void 0 ? void 0 : _o.depends_on, availableOptions, options || {}), readOnly: readOnly, size: editorSize || rest.size, menuItems: ((_p = options === null || options === void 0 ? void 0 : options[optionName]) === null || _p === void 0 ? void 0 : _p.ui_type) === 'any' ?
|
|
1048
1130
|
getCustomMenuTemplateItems(optionName)
|
|
1049
1131
|
: undefined }, templateFieldProps)), (0, jsx_runtime_1.jsx)(OptionFieldMessages_1.OptionFieldMessages, { schema: options || {}, allOptions: availableOptions, name: optionName, option: __assign({ type: type }, other), getType: getTypeForOption }), operators && (0, size_1.default)(operators) && (0, size_1.default)(other.op) ?
|
|
1050
1132
|
(0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreVerticalSpacer, { height: 5 }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { size: 'small', children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreTagGroup, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', labelKey: 'WHERE', label: optionName }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', labelKey: 'IS', label: operatorParts.join(' ') }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', intent: 'info', label: other.value ?
|
|
@@ -1187,6 +1269,7 @@ var FormEngine = function (_a) {
|
|
|
1187
1269
|
var compactToolbarContextValue = (0, react_2.useMemo)(function () { return ({
|
|
1188
1270
|
readOnly: readOnly,
|
|
1189
1271
|
invalidCount: (0, size_1.default)(validityData.invalidFields),
|
|
1272
|
+
attentionCount: readFirstAttentionCount,
|
|
1190
1273
|
completion: readFirstCompletion,
|
|
1191
1274
|
showInvalidOnly: showInvalidOptionsOnly,
|
|
1192
1275
|
onToggleInvalidOnly: handleToggleInvalidOnly,
|
|
@@ -1211,6 +1294,7 @@ var FormEngine = function (_a) {
|
|
|
1211
1294
|
}); }, [
|
|
1212
1295
|
readOnly,
|
|
1213
1296
|
validityData,
|
|
1297
|
+
readFirstAttentionCount,
|
|
1214
1298
|
readFirstCompletion,
|
|
1215
1299
|
showInvalidOptionsOnly,
|
|
1216
1300
|
handleToggleInvalidOnly,
|
|
@@ -1317,6 +1401,57 @@ var FormEngine = function (_a) {
|
|
|
1317
1401
|
return 1;
|
|
1318
1402
|
return groupOrder.indexOf(a) - groupOrder.indexOf(b);
|
|
1319
1403
|
});
|
|
1404
|
+
var buckets = {
|
|
1405
|
+
attention: {},
|
|
1406
|
+
set: {},
|
|
1407
|
+
optional: {},
|
|
1408
|
+
};
|
|
1409
|
+
var bucketGroups = { attention: [], set: [], optional: [] };
|
|
1410
|
+
// Freeze the box of any field currently being edited (or whose one-of group
|
|
1411
|
+
// has an edited member) to its last settled box — so finishing an edit that
|
|
1412
|
+
// flips its status doesn't remount it in another box and steal focus.
|
|
1413
|
+
var stableBucketOf = function (entry) {
|
|
1414
|
+
var _a;
|
|
1415
|
+
var fresh = getOptionBucket(entry.name, entry.hidden);
|
|
1416
|
+
var groupBeingEdited = !entry.hidden &&
|
|
1417
|
+
(((_a = options === null || options === void 0 ? void 0 : options[entry.name]) === null || _a === void 0 ? void 0 : _a.required_groups) || []).some(function (g) {
|
|
1418
|
+
return (requiredGroupsInfo.members[g] || []).some(function (m) { return expandedOptions.includes(m); });
|
|
1419
|
+
});
|
|
1420
|
+
if (!entry.hidden && (expandedOptions.includes(entry.name) || groupBeingEdited)) {
|
|
1421
|
+
var memo = settledBucket.current[entry.name];
|
|
1422
|
+
if (memo)
|
|
1423
|
+
return memo;
|
|
1424
|
+
}
|
|
1425
|
+
settledBucket.current[entry.name] = fresh;
|
|
1426
|
+
return fresh;
|
|
1427
|
+
};
|
|
1428
|
+
groupKeys.forEach(function (groupName) {
|
|
1429
|
+
grouped[groupName].forEach(function (entry) {
|
|
1430
|
+
var b = stableBucketOf(entry);
|
|
1431
|
+
if (!buckets[b][groupName]) {
|
|
1432
|
+
buckets[b][groupName] = [];
|
|
1433
|
+
bucketGroups[b].push(groupName);
|
|
1434
|
+
}
|
|
1435
|
+
buckets[b][groupName].push(entry);
|
|
1436
|
+
});
|
|
1437
|
+
});
|
|
1438
|
+
var bucketCount = function (b) {
|
|
1439
|
+
return bucketGroups[b].reduce(function (n, g) { return n + buckets[b][g].length; }, 0);
|
|
1440
|
+
};
|
|
1441
|
+
// 'general' / 'optional' are the SYNTHETIC fallback group keys getOptionGroup
|
|
1442
|
+
// assigns to fields with no explicit `group` — printing a "General"/"Optional"
|
|
1443
|
+
// sub-label for those is just noise, so suppress it. BUT a consumer may also
|
|
1444
|
+
// use 'general' as a REAL group (defining it in the `groups` prop and tagging
|
|
1445
|
+
// fields with `group: 'general'`); in that case it's a named group like any
|
|
1446
|
+
// other and DOES get its sub-label.
|
|
1447
|
+
var showGroupSubLabel = function (groupName) {
|
|
1448
|
+
return (groupName !== 'general' && groupName !== 'optional') || !!(groups === null || groups === void 0 ? void 0 : groups[groupName]);
|
|
1449
|
+
};
|
|
1450
|
+
var STATUS_BOXES = [
|
|
1451
|
+
{ key: 'attention', label: 'Needs attention', intent: 'warning', icon: 'ErrorWarningLine' },
|
|
1452
|
+
{ key: 'set', label: 'Set', intent: 'success', icon: 'CheckLine' },
|
|
1453
|
+
{ key: 'optional', label: 'Optional', icon: 'CheckboxBlankCircleLine' },
|
|
1454
|
+
];
|
|
1320
1455
|
// Build the rows for one group: contiguous required-group members are pulled
|
|
1321
1456
|
// together at the first member's slot and rendered as a connected rail (flat
|
|
1322
1457
|
// rows — no wrapper — so the value surface applies normally; the rail + nodes
|
|
@@ -1331,8 +1466,9 @@ var FormEngine = function (_a) {
|
|
|
1331
1466
|
}
|
|
1332
1467
|
: shownOptions[entry.name], hidden: entry.hidden, clustered: clustered, clusterFirst: clusterFirst, clusterLast: clusterLast }, entry.name));
|
|
1333
1468
|
};
|
|
1334
|
-
|
|
1335
|
-
|
|
1469
|
+
// (Clustering runs in narrow mode too now — the "One of the below is
|
|
1470
|
+
// required" box wraps the members regardless of width; it no longer relies
|
|
1471
|
+
// on a contiguous rail.)
|
|
1336
1472
|
var emitted = new Set();
|
|
1337
1473
|
var groupOf = function (name) { var _a, _b; return (_b = (_a = options === null || options === void 0 ? void 0 : options[name]) === null || _a === void 0 ? void 0 : _a.required_groups) === null || _b === void 0 ? void 0 : _b[0]; };
|
|
1338
1474
|
return names.map(function (entry) {
|
|
@@ -1345,9 +1481,15 @@ var FormEngine = function (_a) {
|
|
|
1345
1481
|
if (memberEntries.length < 2)
|
|
1346
1482
|
return renderRow(entry, false);
|
|
1347
1483
|
emitted.add(grp);
|
|
1348
|
-
|
|
1484
|
+
var railed = memberEntries.map(function (e, idx) {
|
|
1349
1485
|
return renderRow(e, true, idx === 0, idx === memberEntries.length - 1);
|
|
1350
1486
|
});
|
|
1487
|
+
// An UNMET one-of group gets the explicit "One of the below is required"
|
|
1488
|
+
// box (the Focus cluster). A met group needs no banner — the rail + the
|
|
1489
|
+
// "Covers"/"Covered by" chips already say which member satisfies it.
|
|
1490
|
+
if (requiredGroupsInfo.satisfiedBy[grp])
|
|
1491
|
+
return railed;
|
|
1492
|
+
return ((0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledRequiredClusterBox, { className: 'options-readfirst-required-cluster', "$border": "".concat(cWarning, "33"), "$tint": "".concat(cWarning, "0d"), children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledRequiredClusterHeader, { "$color": cWarning, children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreIcon, { icon: 'LinkM', size: '11px', style: { color: cWarning } }), "One of the below is required"] }), railed] }, grp));
|
|
1351
1493
|
});
|
|
1352
1494
|
};
|
|
1353
1495
|
return ((0, jsx_runtime_1.jsx)(exports.OptionsContext.Provider, { value: { schema: options, value: availableOptions }, children: (0, jsx_runtime_1.jsx)(compactRowContext_1.CompactRowContext.Provider, { value: compactRowContextValue, children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreErrorBoundary, { children: [showHelpForOption && ((0, jsx_runtime_1.jsx)(OptionsHelpDialog_1.OptionsHelpDialog, { onClose: function () { return setShowHelpForOption(undefined); }, option: options[showHelpForOption] })), (0, jsx_runtime_1.jsx)(compactToolbarContext_1.CompactToolbarContext.Provider, { value: compactToolbarContextValue, children: (0, jsx_runtime_1.jsxs)(StyledCompactWrap, { ref: setCompactWrap, className: 'options-readfirst-scroll', "$flush": compactFlush, children: [(0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledCompactPanel, { "$headerBg": headerBg, flat: true, stickyHeader: true, padded: false, actions: compactHeaderActions, contentStyle: {
|
|
@@ -1357,39 +1499,33 @@ var FormEngine = function (_a) {
|
|
|
1357
1499
|
padding: '0 0 12px',
|
|
1358
1500
|
}, children: [(0, size_1.default)(groupKeys) === 0 ?
|
|
1359
1501
|
(0, jsx_runtime_1.jsx)(reqore_1.ReqoreMessage, { flat: true, opaque: false, size: 'small', children: "No fields match the current filters." })
|
|
1360
|
-
: null,
|
|
1361
|
-
var
|
|
1362
|
-
var
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
marginTop: 2,
|
|
1388
|
-
marginBottom: 8,
|
|
1389
|
-
marginLeft: compactRowStyles_1.GROUP_INDENT,
|
|
1390
|
-
paddingRight: 10,
|
|
1391
|
-
}, children: groupConfig.subtitle })
|
|
1392
|
-
: null, (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledGroupBody, { "$divider": cDivider, "$hover": cHover, "$focus": cWarning, "$success": cSuccess, "$rowBg": cRowBg, "$lineColor": cGroupLine, className: compactNarrow ? 'readfirst-narrow' : undefined, children: renderGroupRows(names) })] }, groupName));
|
|
1502
|
+
: null, STATUS_BOXES.map(function (box) {
|
|
1503
|
+
var groupsInBox = bucketGroups[box.key];
|
|
1504
|
+
var count = bucketCount(box.key);
|
|
1505
|
+
if (!count)
|
|
1506
|
+
return null;
|
|
1507
|
+
var accent = box.key === 'attention' ? cWarning
|
|
1508
|
+
: box.key === 'set' ? cSuccess
|
|
1509
|
+
: cMuted;
|
|
1510
|
+
// The muted "Optional" box reads as a quieter, recessed
|
|
1511
|
+
// surface — a touch darker than the page rather than the
|
|
1512
|
+
// faint grey tint the accent would give.
|
|
1513
|
+
var boxBg = box.key === 'optional' ?
|
|
1514
|
+
(0, colors_1.changeDarkness)((0, colors_1.getMainBackgroundColor)(theme), 0.06)
|
|
1515
|
+
: undefined;
|
|
1516
|
+
return ((0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBox, { "$accent": accent, "$bg": boxBg, flat: true, minimal: true, collapseButtonProps: { flat: true, minimal: true, size: 'small' }, collapsible: true, label: (0, jsx_runtime_1.jsxs)(compactRowStyles_1.StyledGroupHeader, { children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { effect: { weight: 'bold' }, size: 'normal', children: box.label }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'small', minimal: true, compact: true, intent: box.intent, label: String(count) })] }), icon: box.icon, className: 'options-readfirst-group', padded: false, contentStyle: { padding: '4px 4px 6px' }, children: (0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledGroupBody, { "$divider": cDivider, "$hover": cHover, "$focus": cWarning, "$success": cSuccess, "$rowBg": cRowBg, "$lineColor": cGroupLine, className: compactNarrow ? 'readfirst-narrow' : undefined, children: groupsInBox.map(function (groupName) {
|
|
1517
|
+
var groupConfig = groups === null || groups === void 0 ? void 0 : groups[groupName];
|
|
1518
|
+
return ((0, jsx_runtime_1.jsxs)(react_2.default.Fragment, { children: [showGroupSubLabel(groupName) ?
|
|
1519
|
+
(0, jsx_runtime_1.jsx)(compactRowStyles_1.StyledStatusBoxGroupLabel, { children: (0, readFirst_1.getOptionGroupLabel)(groupName, groups) })
|
|
1520
|
+
: null, showGroupSubLabel(groupName) && (groupConfig === null || groupConfig === void 0 ? void 0 : groupConfig.subtitle) ?
|
|
1521
|
+
(0, jsx_runtime_1.jsx)(reqore_1.ReqoreP, { size: 'small', effect: { opacity: 0.6 }, style: {
|
|
1522
|
+
marginTop: 2,
|
|
1523
|
+
marginBottom: 8,
|
|
1524
|
+
marginLeft: compactRowStyles_1.GROUP_INDENT,
|
|
1525
|
+
paddingRight: 10,
|
|
1526
|
+
}, children: groupConfig.subtitle })
|
|
1527
|
+
: null, renderGroupRows(buckets[box.key][groupName])] }, groupName));
|
|
1528
|
+
}) }) }, box.key));
|
|
1393
1529
|
})] }), commitMode === 'batched' && !readOnly && dirtyOptionNames.length ?
|
|
1394
1530
|
(0, jsx_runtime_1.jsx)(StyledCommitDock, { "$bg": cBg, "$border": cDivider, children: (0, jsx_runtime_1.jsxs)(reqore_1.ReqoreControlGroup, { className: 'options-readfirst-commitbar', verticalAlign: 'center', wrap: true, children: [(0, jsx_runtime_1.jsx)(reqore_1.ReqoreTag, { size: 'tiny', minimal: true, flat: true, compact: true, effect: { uppercase: true, spaced: 1 }, intent: 'warning', icon: 'EditLine', label: "".concat(dirtyOptionNames.length, " unsaved change").concat(dirtyOptionNames.length === 1 ? '' : 's') }), (0, jsx_runtime_1.jsx)(reqore_1.ReqoreButton, { size: 'small', intent: 'success', icon: 'CheckLine', fixed: true, className: 'options-readfirst-save', disabled: !validityData.isValid, tooltip: validityData.isValid ?
|
|
1395
1531
|
'Apply the staged changes'
|