@vectoriox/iox-ui 5.26.0 → 5.28.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/design-core/index.d.ts +144 -4
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +153 -5
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-forms-core.mjs +40 -5
- package/fesm2022/vectoriox-iox-ui-forms-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +7018 -0
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -0
- package/fesm2022/vectoriox-iox-ui.mjs +72 -14
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/forms-core/index.d.ts +18 -2
- package/generation-core/index.d.ts +1397 -0
- package/generation-core/package.json +3 -0
- package/index.d.ts +13 -2
- package/package.json +5 -1
- package/src/design-core/flavor-spec.generated.ts +153 -5
- package/src/forms-core/collect.ts +3 -1
- package/src/forms-core/options.ts +29 -0
- package/src/forms-core/public-api.ts +1 -0
- package/src/forms-core/transport.ts +6 -2
- package/src/generation-core/compose-site.ts +474 -0
- package/src/generation-core/node-baseline.model.ts +10 -0
- package/src/generation-core/node-baselines.generated.ts +4841 -0
- package/src/generation-core/patterns.ts +125 -0
- package/src/generation-core/public-api.ts +20 -0
- package/src/generation-core/serialized-node.ts +91 -0
- package/src/generation-core/site-plan.model.ts +136 -0
- package/src/generation-core/site-spec.generated.ts +1111 -0
- package/src/generation-core/templates.ts +60 -0
- package/src/generation-core/validate-site-plan.ts +413 -0
- package/styles/iox-forms.css +136 -8
|
@@ -3289,6 +3289,36 @@ const files = (value) => Array.isArray(value) ? value
|
|
|
3289
3289
|
: value && typeof value === 'object' ? [value]
|
|
3290
3290
|
: [];
|
|
3291
3291
|
|
|
3292
|
+
/** `value|Label` separates a submitted value from what the visitor reads; a bare line is both. */
|
|
3293
|
+
const OPTION_SEPARATOR = '|';
|
|
3294
|
+
/**
|
|
3295
|
+
* A Field's `optionsText` trait — the author's choices, one per line — as options. ONE parser for the
|
|
3296
|
+
* builder canvas, both engine paths and iox-cms: until 2026-10-19 nothing parsed the trait, so a Radio
|
|
3297
|
+
* group or a Dropdown from the tray rendered no choices at all on the canvas and on the live site.
|
|
3298
|
+
*/
|
|
3299
|
+
function parseFieldOptions(text) {
|
|
3300
|
+
if (typeof text !== 'string')
|
|
3301
|
+
return [];
|
|
3302
|
+
const out = [];
|
|
3303
|
+
for (const line of text.split(/\r?\n/)) {
|
|
3304
|
+
const raw = line.trim();
|
|
3305
|
+
if (!raw)
|
|
3306
|
+
continue;
|
|
3307
|
+
const at = raw.indexOf(OPTION_SEPARATOR);
|
|
3308
|
+
const value = (at === -1 ? raw : raw.slice(0, at)).trim();
|
|
3309
|
+
const label = (at === -1 ? raw : raw.slice(at + 1)).trim() || value;
|
|
3310
|
+
if (value)
|
|
3311
|
+
out.push({ value, label });
|
|
3312
|
+
}
|
|
3313
|
+
return out;
|
|
3314
|
+
}
|
|
3315
|
+
/** The choices a saved Field offers: an explicit `options` list wins, else its `optionsText` parsed. */
|
|
3316
|
+
function fieldOptionsOf(props) {
|
|
3317
|
+
if (Array.isArray(props?.options) && props.options.length)
|
|
3318
|
+
return props.options;
|
|
3319
|
+
return parseFieldOptions(props?.optionsText);
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3292
3322
|
// Derive a FormSpec from a node tree.
|
|
3293
3323
|
//
|
|
3294
3324
|
// The tree the author edited is the SINGLE source of truth for "what fields does this form have".
|
|
@@ -3392,8 +3422,9 @@ function toFieldSpec(node, taken) {
|
|
|
3392
3422
|
const rules = normaliseRules(props['rules']);
|
|
3393
3423
|
if (rules.length)
|
|
3394
3424
|
spec.rules = rules;
|
|
3395
|
-
|
|
3396
|
-
|
|
3425
|
+
const options = fieldOptionsOf(props);
|
|
3426
|
+
if (options.length)
|
|
3427
|
+
spec.options = options;
|
|
3397
3428
|
if (props['optionsSource'])
|
|
3398
3429
|
spec.optionsSource = props['optionsSource'];
|
|
3399
3430
|
if (props['defaultValue'] !== undefined && props['defaultValue'] !== '') {
|
|
@@ -3609,10 +3640,14 @@ const RENDERED_AT_FIELD = '_iox_t';
|
|
|
3609
3640
|
* The public submit path. Built here rather than interpolated at each call site, so the engine and
|
|
3610
3641
|
* any future host cannot disagree about it — and so changing it is one edit.
|
|
3611
3642
|
*
|
|
3612
|
-
*
|
|
3643
|
+
* ⚠️ ROOT-relative (leading slash), never base-relative. A live site is served under a per-org
|
|
3644
|
+
* `<base href="/<label>/">`, so a relative `api/…` resolved to `/<label>/api/…` — a path the reverse
|
|
3645
|
+
* proxy (`/api` → iox-cms, everything else → the engine) hands to the ENGINE, which answers a POST with
|
|
3646
|
+
* 404: no visitor submission ever reached iox-cms from an org path (found 2026-10-19 by
|
|
3647
|
+
* e2e:forminsert:real). The org is already in the path segment after `site/`.
|
|
3613
3648
|
*/
|
|
3614
3649
|
function submitEndpointPath(orgId, formId) {
|
|
3615
|
-
return
|
|
3650
|
+
return `/api/site/${encodeURIComponent(orgId)}/forms/${encodeURIComponent(formId)}/submit`;
|
|
3616
3651
|
}
|
|
3617
3652
|
/**
|
|
3618
3653
|
* Add the anti-spam fields to the collected values.
|
|
@@ -4068,6 +4103,19 @@ let fieldSeq = 0;
|
|
|
4068
4103
|
* and choosing `email` also chooses email validation.
|
|
4069
4104
|
*/
|
|
4070
4105
|
class IoxFieldComponent {
|
|
4106
|
+
/** Explicit choices (bound data, a hand-built node). Wins over `optionsText`. */
|
|
4107
|
+
set options(value) {
|
|
4108
|
+
this._options = Array.isArray(value) ? value : [];
|
|
4109
|
+
this.refreshChoices();
|
|
4110
|
+
}
|
|
4111
|
+
get options() { return this._options; }
|
|
4112
|
+
/** The author's choices, one per line (`value|Label`) — the Field's trait. A SETTER: the builder
|
|
4113
|
+
* assigns traits directly, with no ngOnChanges. */
|
|
4114
|
+
set optionsText(value) {
|
|
4115
|
+
this._optionsText = value ?? '';
|
|
4116
|
+
this.refreshChoices();
|
|
4117
|
+
}
|
|
4118
|
+
get optionsText() { return this._optionsText; }
|
|
4071
4119
|
/**
|
|
4072
4120
|
* Classic constructor injection, not `inject()`: this library's specs construct components
|
|
4073
4121
|
* directly (its vitest setup cannot run `TestBed.createComponent`), and a field initializer
|
|
@@ -4095,7 +4143,10 @@ class IoxFieldComponent {
|
|
|
4095
4143
|
this.rangeMax = 100;
|
|
4096
4144
|
this.rangeStep = 1;
|
|
4097
4145
|
this.accept = '';
|
|
4098
|
-
|
|
4146
|
+
/** What the radio group / dropdown renders: the shared forms-core reading of the two inputs above. */
|
|
4147
|
+
this.choices = [];
|
|
4148
|
+
this._options = [];
|
|
4149
|
+
this._optionsText = '';
|
|
4099
4150
|
this.value = '';
|
|
4100
4151
|
/** Rules beyond `required` — carried on the node, interpreted by forms-core. */
|
|
4101
4152
|
this.rules = [];
|
|
@@ -4150,10 +4201,13 @@ class IoxFieldComponent {
|
|
|
4150
4201
|
spec.required = true;
|
|
4151
4202
|
if (this.rules?.length)
|
|
4152
4203
|
spec.rules = this.rules;
|
|
4153
|
-
if (this.
|
|
4154
|
-
spec.options = this.
|
|
4204
|
+
if (this.choices.length)
|
|
4205
|
+
spec.options = this.choices;
|
|
4155
4206
|
return spec;
|
|
4156
4207
|
}
|
|
4208
|
+
refreshChoices() {
|
|
4209
|
+
this.choices = fieldOptionsOf({ options: this._options, optionsText: this._optionsText });
|
|
4210
|
+
}
|
|
4157
4211
|
/** `file`, `date`, `number`… map straight through; everything else is a text input. */
|
|
4158
4212
|
get inputType() {
|
|
4159
4213
|
const passthrough = ['email', 'tel', 'url', 'number', 'password', 'date', 'time', 'file', 'hidden'];
|
|
@@ -4179,7 +4233,7 @@ class IoxFieldComponent {
|
|
|
4179
4233
|
this.touched.emit();
|
|
4180
4234
|
}
|
|
4181
4235
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: IoxFieldComponent, deps: [{ token: FormRuntimeService, optional: true }, { token: IOX_FORM_MESSAGES }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4182
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: IoxFieldComponent, isStandalone: false, selector: "div[iox-field]", inputs: { nodeId: "nodeId", name: "name", label: "label", control: "control", placeholder: "placeholder", help: "help", required: "required", disabled: "disabled", labelHidden: "labelHidden", requiredMark: "requiredMark", rows: "rows", rangeMin: "rangeMin", rangeMax: "rangeMax", rangeStep: "rangeStep", accept: "accept", options: "options", value: "value", rules: "rules", forceInvalid: "forceInvalid", designErrorText: "designErrorText", showValid: "showValid" }, outputs: { valueChange: "valueChange", touched: "touched" }, host: { properties: { "class": "'iox-field iox-node-' + nodeId", "class.iox-invalid": "invalid", "class.iox-valid": "showValid", "attr.data-iox-field": "fieldName || null", "hidden": "control === 'hidden' ? true : null" } }, ngImport: i0, template: `
|
|
4236
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.31", type: IoxFieldComponent, isStandalone: false, selector: "div[iox-field]", inputs: { nodeId: "nodeId", name: "name", label: "label", control: "control", placeholder: "placeholder", help: "help", required: "required", disabled: "disabled", labelHidden: "labelHidden", requiredMark: "requiredMark", rows: "rows", rangeMin: "rangeMin", rangeMax: "rangeMax", rangeStep: "rangeStep", accept: "accept", options: "options", optionsText: "optionsText", value: "value", rules: "rules", forceInvalid: "forceInvalid", designErrorText: "designErrorText", showValid: "showValid" }, outputs: { valueChange: "valueChange", touched: "touched" }, host: { properties: { "class": "'iox-field iox-node-' + nodeId", "class.iox-invalid": "invalid", "class.iox-valid": "showValid", "attr.data-iox-field": "fieldName || null", "hidden": "control === 'hidden' ? true : null" } }, ngImport: i0, template: `
|
|
4183
4237
|
<label class="iox-field__label"
|
|
4184
4238
|
[class.iox-field__label--hidden]="labelHidden"
|
|
4185
4239
|
[attr.for]="controlId">
|
|
@@ -4215,7 +4269,7 @@ class IoxFieldComponent {
|
|
|
4215
4269
|
(change)="emit($any($event.target).value)"
|
|
4216
4270
|
(blur)="touch()">
|
|
4217
4271
|
<option value="" [selected]="!value">{{ placeholder || '' }}</option>
|
|
4218
|
-
@for (option of
|
|
4272
|
+
@for (option of choices; track option.value) {
|
|
4219
4273
|
<option [value]="option.value" [selected]="option.value === value">{{ option.label }}</option>
|
|
4220
4274
|
}
|
|
4221
4275
|
</select>
|
|
@@ -4262,9 +4316,10 @@ class IoxFieldComponent {
|
|
|
4262
4316
|
}
|
|
4263
4317
|
@case ('radio') {
|
|
4264
4318
|
<div class="iox-field__group" role="radiogroup" [attr.aria-labelledby]="controlId + '-label'">
|
|
4265
|
-
@for (option of
|
|
4319
|
+
@for (option of choices; track option.value) {
|
|
4266
4320
|
<label class="iox-field__option">
|
|
4267
|
-
<input
|
|
4321
|
+
<input class="iox-field__control iox-field__control--radio"
|
|
4322
|
+
type="radio"
|
|
4268
4323
|
[name]="fieldName"
|
|
4269
4324
|
[value]="option.value"
|
|
4270
4325
|
[checked]="option.value === value"
|
|
@@ -4339,7 +4394,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
4339
4394
|
(change)="emit($any($event.target).value)"
|
|
4340
4395
|
(blur)="touch()">
|
|
4341
4396
|
<option value="" [selected]="!value">{{ placeholder || '' }}</option>
|
|
4342
|
-
@for (option of
|
|
4397
|
+
@for (option of choices; track option.value) {
|
|
4343
4398
|
<option [value]="option.value" [selected]="option.value === value">{{ option.label }}</option>
|
|
4344
4399
|
}
|
|
4345
4400
|
</select>
|
|
@@ -4386,9 +4441,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
4386
4441
|
}
|
|
4387
4442
|
@case ('radio') {
|
|
4388
4443
|
<div class="iox-field__group" role="radiogroup" [attr.aria-labelledby]="controlId + '-label'">
|
|
4389
|
-
@for (option of
|
|
4444
|
+
@for (option of choices; track option.value) {
|
|
4390
4445
|
<label class="iox-field__option">
|
|
4391
|
-
<input
|
|
4446
|
+
<input class="iox-field__control iox-field__control--radio"
|
|
4447
|
+
type="radio"
|
|
4392
4448
|
[name]="fieldName"
|
|
4393
4449
|
[value]="option.value"
|
|
4394
4450
|
[checked]="option.value === value"
|
|
@@ -4467,6 +4523,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
4467
4523
|
type: Input
|
|
4468
4524
|
}], options: [{
|
|
4469
4525
|
type: Input
|
|
4526
|
+
}], optionsText: [{
|
|
4527
|
+
type: Input
|
|
4470
4528
|
}], value: [{
|
|
4471
4529
|
type: Input
|
|
4472
4530
|
}], rules: [{
|