formeo 5.2.0 → 5.2.2
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 +1 -1
- package/dist/demo/assets/css/demo.min.css +1 -1
- package/dist/demo/assets/css/demo.min.css.gz +0 -0
- package/dist/demo/assets/css/formeo.min.css +1 -1
- package/dist/demo/assets/js/demo.min.js +56 -56
- package/dist/demo/assets/js/demo.min.js.gz +0 -0
- package/dist/demo/assets/js/form.min.js +1 -1
- package/dist/demo/assets/js/formeo.cjs.js +179 -45
- package/dist/demo/assets/js/formeo.es.js +179 -45
- package/dist/demo/assets/js/formeo.min.cjs.js +2 -2
- package/dist/demo/assets/js/formeo.min.es.js +2 -2
- package/dist/demo/assets/js/formeo.min.js +179 -45
- package/dist/demo/assets/js/formeo.min.umd.js +2 -2
- package/dist/demo/assets/js/formeo.umd.js +179 -45
- package/dist/demo/assets/js/html.min.js +1 -1
- package/dist/demo/assets/js/layout.min.js +1 -1
- package/dist/demo/assets/js/mode-json.min.js +1 -1
- package/dist/demo/assets/js/mode-json.min.js.gz +0 -0
- package/dist/demo/assets/js/theme-github_light_default.min.js +1 -1
- package/dist/demo/index.html +1 -1
- package/dist/formData_schema.json +730 -1
- package/dist/formeo.cjs.js +179 -45
- package/dist/formeo.css +1 -1
- package/dist/formeo.es.js +179 -45
- package/dist/formeo.min.cjs.js +2 -2
- package/dist/formeo.min.css +1 -1
- package/dist/formeo.min.es.js +2 -2
- package/dist/formeo.min.js +179 -45
- package/dist/formeo.min.umd.js +2 -2
- package/dist/formeo.umd.js +179 -45
- package/package.json +3 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
/**
|
|
3
3
|
formeo - https://formeo.io
|
|
4
|
-
Version: 5.1
|
|
4
|
+
Version: 5.2.1
|
|
5
5
|
Author: Draggable https://draggable.io
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -6060,7 +6060,7 @@ if (globalThis !== void 0) globalThis.SmartTooltip = SmartTooltip;
|
|
|
6060
6060
|
var name$1, version$2, type, main, module$1, unpkg, exports$1, files, homepage, repository, author, contributors, bugs, description, keywords, ignore, config, scripts, devDependencies, dependencies, release, commitlint, package_default;
|
|
6061
6061
|
var init_package = __esmMin((() => {
|
|
6062
6062
|
name$1 = "formeo";
|
|
6063
|
-
version$2 = "5.1
|
|
6063
|
+
version$2 = "5.2.1";
|
|
6064
6064
|
type = "module";
|
|
6065
6065
|
main = "dist/formeo.cjs.js";
|
|
6066
6066
|
module$1 = "dist/formeo.es.js";
|
|
@@ -6122,7 +6122,7 @@ var init_package = __esmMin((() => {
|
|
|
6122
6122
|
"postbuild:demo": "node --no-warnings tools/copy-assets.mjs",
|
|
6123
6123
|
"build:demo:watch": "vite build --mode demo --watch",
|
|
6124
6124
|
"build:icons": "node ./tools/generate-sprite",
|
|
6125
|
-
"lint": "biome check ./src && node tools/check-color-literals.mjs",
|
|
6125
|
+
"lint": "biome check ./src && node tools/check-color-literals.mjs && node tools/check-doc-links.mjs",
|
|
6126
6126
|
"lint:fix": "biome check --write ./src",
|
|
6127
6127
|
"format": "biome format --write .",
|
|
6128
6128
|
"test": "node --loader=./tools/svg-loader.mjs --import=./tools/__mocks__/sprite-init.mjs --experimental-test-snapshots --require ./tools/test-setup.cjs --test --no-warnings src/**/*.test.{js,mjs}",
|
|
@@ -6164,8 +6164,7 @@ var init_package = __esmMin((() => {
|
|
|
6164
6164
|
"vite-plugin-banner": "^0.8.0",
|
|
6165
6165
|
"vite-plugin-compression": "^0.5.1",
|
|
6166
6166
|
"vite-plugin-html": "^3.2.2",
|
|
6167
|
-
"zod": "^4.4.3"
|
|
6168
|
-
"zod-to-json-schema": "^3.23.5"
|
|
6167
|
+
"zod": "^4.4.3"
|
|
6169
6168
|
};
|
|
6170
6169
|
dependencies = {
|
|
6171
6170
|
"@draggable/formeo-languages": "^3.4.1",
|
|
@@ -12086,7 +12085,7 @@ var init_loaders = __esmMin((() => {
|
|
|
12086
12085
|
}));
|
|
12087
12086
|
//#endregion
|
|
12088
12087
|
//#region src/lib/js/common/dom.js
|
|
12089
|
-
var iconFontTemplates, inputTags, stripOn, useCaptureEvts, defaultActionHandler, getName, DOM, dom;
|
|
12088
|
+
var iconFontTemplates, inputTags, REQUIRED_GROUP_ATTR, OPTION_INPUT_ATTRS, GROUP_CONSUMED_ATTRS, groupWrapperAttrs, stripOn, useCaptureEvts, defaultActionHandler, getName, DOM, dom;
|
|
12090
12089
|
var init_dom = __esmMin((() => {
|
|
12091
12090
|
init_components();
|
|
12092
12091
|
init_constants();
|
|
@@ -12108,6 +12107,18 @@ var init_dom = __esmMin((() => {
|
|
|
12108
12107
|
"textarea",
|
|
12109
12108
|
"select"
|
|
12110
12109
|
]);
|
|
12110
|
+
REQUIRED_GROUP_ATTR = "formeo-required-group";
|
|
12111
|
+
OPTION_INPUT_ATTRS = ["disabled", "form"];
|
|
12112
|
+
GROUP_CONSUMED_ATTRS = new Set([
|
|
12113
|
+
"type",
|
|
12114
|
+
"id",
|
|
12115
|
+
"name",
|
|
12116
|
+
"className",
|
|
12117
|
+
"value",
|
|
12118
|
+
"required",
|
|
12119
|
+
...OPTION_INPUT_ATTRS
|
|
12120
|
+
]);
|
|
12121
|
+
groupWrapperAttrs = (attrs = {}) => Object.fromEntries(Object.entries(attrs).filter(([key]) => !GROUP_CONSUMED_ATTRS.has(key)));
|
|
12111
12122
|
stripOn = (str) => str.replace(/^on([A-Z])/, (_, l) => l.toLowerCase());
|
|
12112
12123
|
useCaptureEvts = new Set(["focus", "blur"]);
|
|
12113
12124
|
defaultActionHandler = (event) => {
|
|
@@ -12231,9 +12242,18 @@ var init_dom = __esmMin((() => {
|
|
|
12231
12242
|
helpers.forEach(processedOptions, (option) => {
|
|
12232
12243
|
wrap.children.push(_this.create(option, isPreview));
|
|
12233
12244
|
});
|
|
12234
|
-
|
|
12245
|
+
const groupAttrs = elem.attrs || {};
|
|
12246
|
+
if (groupAttrs.className) wrap.className = groupAttrs.className;
|
|
12235
12247
|
wrap.id = elem.id;
|
|
12236
|
-
wrap.
|
|
12248
|
+
wrap.attrs = groupWrapperAttrs(groupAttrs);
|
|
12249
|
+
wrap.config = {
|
|
12250
|
+
...elem.config,
|
|
12251
|
+
required: Boolean(groupAttrs.required)
|
|
12252
|
+
};
|
|
12253
|
+
if (!isPreview && groupAttrs.type === "checkbox" && groupAttrs.required) {
|
|
12254
|
+
wrap.attrs[`data-${REQUIRED_GROUP_ATTR}`] = "true";
|
|
12255
|
+
wrap.action = { change: ({ currentTarget }) => this.syncCheckboxGroupRequired(currentTarget) };
|
|
12256
|
+
}
|
|
12237
12257
|
return this.create(wrap, isPreview);
|
|
12238
12258
|
}
|
|
12239
12259
|
processed.push("options");
|
|
@@ -12436,16 +12456,20 @@ var init_dom = __esmMin((() => {
|
|
|
12436
12456
|
const { action, attrs = {} } = elem;
|
|
12437
12457
|
const fieldType = attrs.type || elem.tag;
|
|
12438
12458
|
const id = attrs.id || elem.id;
|
|
12459
|
+
const name = !isPreview && attrs.name || id;
|
|
12460
|
+
const sharedInputAttrs = Object.fromEntries(OPTION_INPUT_ATTRS.filter((key) => key in attrs).map((key) => [key, attrs[key]]));
|
|
12461
|
+
if (attrs.required) sharedInputAttrs.required = fieldType !== "checkbox" || !options.some(({ selected, checked }) => selected || checked);
|
|
12439
12462
|
const optionMap = (option, i) => {
|
|
12440
12463
|
const { label, value, ...rest } = option;
|
|
12441
12464
|
const defaultInput = () => {
|
|
12442
12465
|
const input = {
|
|
12443
12466
|
tag: "input",
|
|
12444
12467
|
attrs: {
|
|
12445
|
-
name
|
|
12468
|
+
name,
|
|
12446
12469
|
type: fieldType,
|
|
12447
12470
|
value: value || "",
|
|
12448
12471
|
id: `${id}-${i}`,
|
|
12472
|
+
...sharedInputAttrs,
|
|
12449
12473
|
...rest
|
|
12450
12474
|
},
|
|
12451
12475
|
action
|
|
@@ -12547,6 +12571,18 @@ var init_dom = __esmMin((() => {
|
|
|
12547
12571
|
const labelAfter = helpers.get(elem, "config.labelAfter");
|
|
12548
12572
|
return labelAfter === void 0 ? type === "checkbox" || type === "radio" : labelAfter;
|
|
12549
12573
|
}
|
|
12574
|
+
/**
|
|
12575
|
+
* A required checkbox group needs at least one checked box, not every box.
|
|
12576
|
+
* Every box stays `required` while none is checked; once one is checked none is.
|
|
12577
|
+
* Boxes inside a hidden container are never required.
|
|
12578
|
+
* @param {Element} groupElem wrapper holding the group's checkboxes
|
|
12579
|
+
*/
|
|
12580
|
+
syncCheckboxGroupRequired(groupElem) {
|
|
12581
|
+
const boxes = Array.from(groupElem.querySelectorAll("input[type=\"checkbox\"]"));
|
|
12582
|
+
const isHidden = Boolean(groupElem.closest("[hidden]"));
|
|
12583
|
+
const noneChecked = !boxes.some((box) => box.checked);
|
|
12584
|
+
for (const box of boxes) box.required = !isHidden && noneChecked;
|
|
12585
|
+
}
|
|
12550
12586
|
requiredMark = () => ({
|
|
12551
12587
|
tag: "span",
|
|
12552
12588
|
className: "text-error",
|
|
@@ -12570,7 +12606,7 @@ var init_dom = __esmMin((() => {
|
|
|
12570
12606
|
* @return {Object} config object
|
|
12571
12607
|
*/
|
|
12572
12608
|
label(elem, fMap) {
|
|
12573
|
-
const required = helpers.get(elem, "attrs.required");
|
|
12609
|
+
const required = helpers.get(elem, "attrs.required") || helpers.get(elem, "config.required");
|
|
12574
12610
|
let { config: { label: labelText = "", helpText = "", tooltip = null } } = elem;
|
|
12575
12611
|
const { id: elemId, attrs } = elem;
|
|
12576
12612
|
if (typeof labelText === "function") labelText = labelText();
|
|
@@ -18165,12 +18201,23 @@ var assignmentMap = Object.entries(ASSIGNMENT_OPERATORS).reduce((acc, [key, valu
|
|
|
18165
18201
|
acc[key] = assignmentHandlers[key];
|
|
18166
18202
|
return acc;
|
|
18167
18203
|
}, {});
|
|
18204
|
+
/**
|
|
18205
|
+
* Setting `checked` fires no `change`, so a required checkbox group the box belongs to is
|
|
18206
|
+
* re-synced directly. A synthetic `change` could re-trigger conditions.
|
|
18207
|
+
* @param {Element} elem checkbox or radio input
|
|
18208
|
+
*/
|
|
18209
|
+
var syncRequiredGroupOf = (elem) => {
|
|
18210
|
+
const group = elem.closest?.(REQUIRED_GROUP_SELECTOR);
|
|
18211
|
+
if (group) dom.syncCheckboxGroupRequired(group);
|
|
18212
|
+
};
|
|
18168
18213
|
var targetPropertyMap = {
|
|
18169
18214
|
isChecked: (elem) => {
|
|
18170
18215
|
elem.checked = true;
|
|
18216
|
+
syncRequiredGroupOf(elem);
|
|
18171
18217
|
},
|
|
18172
18218
|
isNotChecked: (elem) => {
|
|
18173
18219
|
elem.checked = false;
|
|
18220
|
+
syncRequiredGroupOf(elem);
|
|
18174
18221
|
},
|
|
18175
18222
|
value: (elem, { assignment, ...rest }) => {
|
|
18176
18223
|
const assignmentAction = assignmentMap[assignment]?.(elem, rest);
|
|
@@ -18179,15 +18226,60 @@ var targetPropertyMap = {
|
|
|
18179
18226
|
return assignmentAction;
|
|
18180
18227
|
},
|
|
18181
18228
|
isNotVisible: (elem) => {
|
|
18182
|
-
if (elem?._required === void 0) elem._required = elem.required;
|
|
18183
18229
|
elem.parentElement.setAttribute("hidden", true);
|
|
18184
|
-
elem
|
|
18230
|
+
suspendRequired(elem);
|
|
18185
18231
|
},
|
|
18186
18232
|
isVisible: (elem) => {
|
|
18187
18233
|
elem.parentElement.removeAttribute("hidden");
|
|
18188
|
-
elem
|
|
18234
|
+
restoreRequired(elem);
|
|
18235
|
+
}
|
|
18236
|
+
};
|
|
18237
|
+
var FORM_CONTROL_SELECTOR = "input, select, textarea";
|
|
18238
|
+
var REQUIRED_GROUP_SELECTOR = `[data-${REQUIRED_GROUP_ATTR}]`;
|
|
18239
|
+
/**
|
|
18240
|
+
* The element itself when it matches, plus every descendant that does
|
|
18241
|
+
* @param {Element} elem
|
|
18242
|
+
* @param {String} selector
|
|
18243
|
+
* @return {Array<Element>}
|
|
18244
|
+
*/
|
|
18245
|
+
var selfAndDescendants = (elem, selector) => [...elem.matches(selector) ? [elem] : [], ...elem.querySelectorAll(selector)];
|
|
18246
|
+
/**
|
|
18247
|
+
* A hidden control can't be filled in, so it must not be required. Remembers each control's
|
|
18248
|
+
* `required` so that restoreRequired can put it back. Works for a field, a group or a whole row.
|
|
18249
|
+
* @param {Element} elem condition target
|
|
18250
|
+
*/
|
|
18251
|
+
var suspendRequired = (elem) => {
|
|
18252
|
+
for (const control of selfAndDescendants(elem, FORM_CONTROL_SELECTOR)) {
|
|
18253
|
+
if (control._required === void 0) control._required = control.required;
|
|
18254
|
+
control.required = false;
|
|
18255
|
+
}
|
|
18256
|
+
};
|
|
18257
|
+
/**
|
|
18258
|
+
* Undoes suspendRequired. Controls that were never suspended are left alone, and so are controls
|
|
18259
|
+
* still inside a hidden container: they keep their saved `required` until that container is shown.
|
|
18260
|
+
* @param {Element} elem condition target
|
|
18261
|
+
*/
|
|
18262
|
+
var restoreRequired = (elem) => {
|
|
18263
|
+
for (const control of selfAndDescendants(elem, FORM_CONTROL_SELECTOR)) if (control._required !== void 0 && !control.closest("[hidden]")) {
|
|
18264
|
+
control.required = control._required;
|
|
18265
|
+
delete control._required;
|
|
18189
18266
|
}
|
|
18267
|
+
for (const group of selfAndDescendants(elem, REQUIRED_GROUP_SELECTOR)) dom.syncCheckboxGroupRequired(group);
|
|
18190
18268
|
};
|
|
18269
|
+
var LOGICAL_AND = new Set(["&&", "and"]);
|
|
18270
|
+
/**
|
|
18271
|
+
* Splits a condition's if-clauses into OR-groups of AND-ed clauses. A clause's `logical`
|
|
18272
|
+
* ('&&' / '||', or 'and' / 'or') joins it to the clause before it, and '&&' binds tighter
|
|
18273
|
+
* than '||' as in JavaScript. The first clause's `logical` is ignored, and a missing
|
|
18274
|
+
* `logical` means OR, which is how every clause behaved before AND was supported.
|
|
18275
|
+
* @param {Array<Object>} ifConditions
|
|
18276
|
+
* @return {Array<Array<Object>>} e.g. A || B && C -> [[A], [B, C]]
|
|
18277
|
+
*/
|
|
18278
|
+
var groupIfConditions = (ifConditions = []) => ifConditions.reduce((groups, clause, index) => {
|
|
18279
|
+
if (index > 0 && LOGICAL_AND.has(clause.logical)) groups[groups.length - 1].push(clause);
|
|
18280
|
+
else groups.push([clause]);
|
|
18281
|
+
return groups;
|
|
18282
|
+
}, []);
|
|
18191
18283
|
//#endregion
|
|
18192
18284
|
//#region src/lib/js/renderer/index.js
|
|
18193
18285
|
init_dom();
|
|
@@ -18252,20 +18344,31 @@ var FormeoRenderer$1 = class {
|
|
|
18252
18344
|
const fieldData = {
|
|
18253
18345
|
key,
|
|
18254
18346
|
value,
|
|
18255
|
-
label: this.
|
|
18347
|
+
label: this.componentByName(key)?.config?.label || ""
|
|
18256
18348
|
};
|
|
18257
18349
|
userFormData.push(fieldData);
|
|
18258
18350
|
}
|
|
18259
18351
|
return userFormData;
|
|
18260
18352
|
}
|
|
18353
|
+
/**
|
|
18354
|
+
* Finds the component data behind a submitted field name
|
|
18355
|
+
* @param {String} name
|
|
18356
|
+
* @return {Object|undefined}
|
|
18357
|
+
*/
|
|
18358
|
+
componentByName(name) {
|
|
18359
|
+
return this.components[baseId(name)] || Object.values(this.components).find((component) => component.attrs?.name === name);
|
|
18360
|
+
}
|
|
18261
18361
|
set userData(data = {}) {
|
|
18262
18362
|
const form = this.container.querySelector("form");
|
|
18263
18363
|
for (const key of Object.keys(data)) {
|
|
18264
18364
|
const fields = form.elements[key];
|
|
18265
|
-
|
|
18365
|
+
const checkables = checkableInputs(fields);
|
|
18366
|
+
if (checkables?.[0].type === "checkbox") {
|
|
18266
18367
|
const values = Array.isArray(data[key]) ? data[key] : [data[key]];
|
|
18267
|
-
for (const field of
|
|
18268
|
-
|
|
18368
|
+
for (const field of checkables) field.checked = values.includes(field.value);
|
|
18369
|
+
const group = checkables[0].closest(`[data-${REQUIRED_GROUP_ATTR}]`);
|
|
18370
|
+
if (group) dom.syncCheckboxGroupRequired(group);
|
|
18371
|
+
} else if (checkables?.[0].type === "radio") for (const field of checkables) field.checked = field.value === data[key];
|
|
18269
18372
|
else if (fields.type) fields.value = data[key];
|
|
18270
18373
|
}
|
|
18271
18374
|
}
|
|
@@ -18291,9 +18394,20 @@ var FormeoRenderer$1 = class {
|
|
|
18291
18394
|
children: this.processedData
|
|
18292
18395
|
};
|
|
18293
18396
|
this.renderedForm = dom.render(config);
|
|
18397
|
+
this.renderedForm.addEventListener("reset", this.syncRequiredGroupsAfterReset);
|
|
18294
18398
|
this.applyConditions();
|
|
18295
18399
|
return this.renderedForm;
|
|
18296
18400
|
}
|
|
18401
|
+
/**
|
|
18402
|
+
* A reset changes checkedness without firing `change`, so required checkbox groups are re-synced.
|
|
18403
|
+
* The `reset` event fires before the controls revert, hence the deferral.
|
|
18404
|
+
* @param {Event} evt the form's reset event
|
|
18405
|
+
*/
|
|
18406
|
+
syncRequiredGroupsAfterReset = ({ currentTarget: form }) => {
|
|
18407
|
+
setTimeout(() => {
|
|
18408
|
+
for (const group of form.querySelectorAll(`[data-${REQUIRED_GROUP_ATTR}]`)) dom.syncCheckboxGroupRequired(group);
|
|
18409
|
+
}, 0);
|
|
18410
|
+
};
|
|
18297
18411
|
get html() {
|
|
18298
18412
|
return (this.renderedForm || this.getRenderedForm()).outerHTML;
|
|
18299
18413
|
}
|
|
@@ -18368,7 +18482,8 @@ var FormeoRenderer$1 = class {
|
|
|
18368
18482
|
...attrs,
|
|
18369
18483
|
"data-clone-of": id
|
|
18370
18484
|
};
|
|
18371
|
-
if (rest.
|
|
18485
|
+
if (rest.options && ["checkbox", "radio"].includes(attrs.type)) delete updatedAttrs.name;
|
|
18486
|
+
else if (rest.tag === "input") updatedAttrs.name = getName(this.components[componentId]);
|
|
18372
18487
|
return {
|
|
18373
18488
|
...rest,
|
|
18374
18489
|
id: "f-" + uuid(id),
|
|
@@ -18413,46 +18528,57 @@ var FormeoRenderer$1 = class {
|
|
|
18413
18528
|
});
|
|
18414
18529
|
}
|
|
18415
18530
|
/**
|
|
18416
|
-
*
|
|
18417
|
-
*
|
|
18531
|
+
* Wires every condition of every rendered component: evaluates it once on render and again
|
|
18532
|
+
* whenever a component one of its if-clauses reads from changes.
|
|
18418
18533
|
*/
|
|
18419
|
-
handleComponentCondition = (component, ifRest, thenConditions) => {
|
|
18420
|
-
if (!component) return;
|
|
18421
|
-
if (isNodeCollection(component)) {
|
|
18422
|
-
for (const elem of component) this.handleComponentCondition(elem, ifRest, thenConditions);
|
|
18423
|
-
return;
|
|
18424
|
-
}
|
|
18425
|
-
const listenerEvent = LISTEN_TYPE_MAP(component);
|
|
18426
|
-
if (listenerEvent) component.addEventListener(listenerEvent, (evt) => {
|
|
18427
|
-
if (this.evaluateCondition(ifRest, evt)) for (const thenCondition of thenConditions) this.execResult(thenCondition, evt);
|
|
18428
|
-
}, false);
|
|
18429
|
-
const fakeEvt = { target: component };
|
|
18430
|
-
if (this.evaluateCondition(ifRest, fakeEvt)) for (const thenCondition of thenConditions) this.execResult(thenCondition, fakeEvt);
|
|
18431
|
-
};
|
|
18432
18534
|
applyConditions = () => {
|
|
18433
18535
|
for (const { conditions } of Object.values(this.components)) {
|
|
18434
18536
|
if (!conditions) continue;
|
|
18435
|
-
for (const condition of conditions) {
|
|
18436
|
-
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
} catch (err) {
|
|
18440
|
-
console.error("formeo: condition skipped", ifCondition, err);
|
|
18441
|
-
}
|
|
18537
|
+
for (const condition of conditions) try {
|
|
18538
|
+
this.applyCondition(condition);
|
|
18539
|
+
} catch (err) {
|
|
18540
|
+
console.error("formeo: condition skipped", condition, err);
|
|
18442
18541
|
}
|
|
18443
18542
|
}
|
|
18444
18543
|
};
|
|
18445
|
-
applyCondition = (
|
|
18446
|
-
|
|
18447
|
-
|
|
18544
|
+
applyCondition = ({ if: ifConditions = [], then: thenConditions = [] }) => {
|
|
18545
|
+
const clauseGroups = groupIfConditions(ifConditions);
|
|
18546
|
+
let running = false;
|
|
18547
|
+
const run = (evt) => {
|
|
18548
|
+
if (running) return;
|
|
18549
|
+
running = true;
|
|
18550
|
+
try {
|
|
18551
|
+
if (this.evaluateClauseGroups(clauseGroups)) for (const thenCondition of thenConditions) this.execResult(thenCondition, evt);
|
|
18552
|
+
} finally {
|
|
18553
|
+
running = false;
|
|
18554
|
+
}
|
|
18555
|
+
};
|
|
18556
|
+
const watchedAddresses = new Set(ifConditions.flatMap(({ source, target }) => [source, target]).filter(isAddress));
|
|
18557
|
+
for (const address of watchedAddresses) {
|
|
18448
18558
|
const { component, options } = this.getComponent(address);
|
|
18449
|
-
this.
|
|
18559
|
+
this.listenForChanges(options || component, run);
|
|
18560
|
+
}
|
|
18561
|
+
run({ target: null });
|
|
18562
|
+
};
|
|
18563
|
+
/**
|
|
18564
|
+
* @param {Array<Array<Object>>} clauseGroups output of groupIfConditions
|
|
18565
|
+
* @return {Boolean} true when every clause of at least one group matches
|
|
18566
|
+
*/
|
|
18567
|
+
evaluateClauseGroups = (clauseGroups) => clauseGroups.some((group) => group.length && group.every((clause) => this.evaluateCondition(clause)));
|
|
18568
|
+
listenForChanges = (component, handler) => {
|
|
18569
|
+
if (!component) return;
|
|
18570
|
+
if (isNodeCollection(component)) {
|
|
18571
|
+
for (const elem of component) this.listenForChanges(elem, handler);
|
|
18572
|
+
return;
|
|
18450
18573
|
}
|
|
18574
|
+
const listenerEvent = LISTEN_TYPE_MAP(component);
|
|
18575
|
+
if (listenerEvent) component.addEventListener(listenerEvent, handler, false);
|
|
18451
18576
|
};
|
|
18452
18577
|
/**
|
|
18453
18578
|
* Evaulate conditions
|
|
18454
18579
|
*/
|
|
18455
18580
|
evaluateCondition = ({ source, sourceProperty, targetProperty, comparison, target }) => {
|
|
18581
|
+
if (!isAddress(source) || !this.getComponent(source)?.component) return false;
|
|
18456
18582
|
const sourceValue = this.getComponentProperty(source, sourceProperty);
|
|
18457
18583
|
if (typeof sourceValue === "boolean") return sourceValue;
|
|
18458
18584
|
const targetValue = String(isAddress(target) ? this.getComponentProperty(target, targetProperty) : target);
|
|
@@ -18479,7 +18605,10 @@ var FormeoRenderer$1 = class {
|
|
|
18479
18605
|
const result = { component: null };
|
|
18480
18606
|
if (!isAddress(address)) return null;
|
|
18481
18607
|
const [, componentId, optionsKey, optionIndex] = splitAddress(address);
|
|
18482
|
-
|
|
18608
|
+
let component = null;
|
|
18609
|
+
try {
|
|
18610
|
+
component = this.renderedForm.querySelector(`#f-${componentId}`);
|
|
18611
|
+
} catch {}
|
|
18483
18612
|
if (!component) return result;
|
|
18484
18613
|
result.component = component;
|
|
18485
18614
|
if (optionsKey) {
|
|
@@ -18498,6 +18627,11 @@ var FormeoRenderer$1 = class {
|
|
|
18498
18627
|
return components;
|
|
18499
18628
|
};
|
|
18500
18629
|
};
|
|
18630
|
+
var isCheckable = (elem) => ["checkbox", "radio"].includes(elem?.type);
|
|
18631
|
+
var checkableInputs = (fields) => {
|
|
18632
|
+
if (isCheckable(fields)) return [fields];
|
|
18633
|
+
return fields?.length && isCheckable(fields[0]) ? Array.from(fields) : null;
|
|
18634
|
+
};
|
|
18501
18635
|
var isDomNode = (value) => Boolean(value) && typeof value.nodeType === "number";
|
|
18502
18636
|
var isNodeCollection = (value) => Boolean(value) && !isDomNode(value) && typeof value.length === "number";
|
|
18503
18637
|
var tagName = (component) => component.tagName?.toLowerCase();
|