@vectoriox/iox-ui 5.28.0 → 5.29.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.
@@ -1245,6 +1245,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
1245
1245
  args: ['childrenHost', { read: ViewContainerRef, static: true }]
1246
1246
  }] } });
1247
1247
 
1248
+ /**
1249
+ * Where a node links (W1.1). Link and LinkedContainer always had two link types — an external URL or a
1250
+ * website PAGE by its route — and ButtonBlock now has the same pair, so a composed "Get in touch" button
1251
+ * is a page link the builder shows as `/contact`, not a hand-built URL. Framework-free: the composer
1252
+ * (generation-core) writes it, the builder canvas and both engine render paths read it.
1253
+ */
1254
+ var LinkType;
1255
+ (function (LinkType) {
1256
+ LinkType["External"] = "external";
1257
+ LinkType["Page"] = "page";
1258
+ })(LinkType || (LinkType = {}));
1259
+ const ANCHOR_TAG = 'a';
1260
+ /**
1261
+ * The href a ButtonBlock renders, or `null` for none (it is a `<button>`, or a link with no target).
1262
+ * Only an `<a>` links. A page link's route goes through `pageHref` — the engine's `resolvePageHref`
1263
+ * (`:params` substituted, base-relative); the builder canvas passes none and shows the route as authored,
1264
+ * as its Link does.
1265
+ */
1266
+ function buttonBlockHref(props, pageHref = route => route) {
1267
+ if (props.tag !== ANCHOR_TAG)
1268
+ return null;
1269
+ const href = props.linkType === LinkType.Page ? pageHref(String(props.pageRoute ?? '')) : String(props.href ?? '');
1270
+ return href || null;
1271
+ }
1272
+
1248
1273
  /**
1249
1274
  * Directive-host ButtonBlock: the real `<a>`/`<button>` IS the host — no `app-button-block`
1250
1275
  * wrapper, no inner/outer split. The tag is chosen by whoever CREATES the component (engine
@@ -1252,30 +1277,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
1252
1277
  * The `iox-btn-block` class (UA resets: inline-flex, color/font inherit, no border) matches the
1253
1278
  * string renderer and lives in the engine's global styles.scss — kept OFF `:host` so styleProps
1254
1279
  * (`.iox-node-{id}`) can override it. Children render into the host via `childrenHost`.
1280
+ * A page link (`linkType: page`) arrives with its `pageRoute` already resolved by the engine (params
1281
+ * substituted, base-relative — the Link's resolver); `buttonBlockHref` decides the href for every renderer.
1255
1282
  */
1256
1283
  class ButtonBlockComponent {
1257
1284
  constructor() {
1258
1285
  this.tag = 'button';
1286
+ this.linkType = LinkType.External;
1259
1287
  this.href = '';
1288
+ this.pageRoute = '';
1260
1289
  this.target = '_self';
1261
1290
  this.type = 'button';
1262
1291
  this.nodeId = '';
1263
1292
  }
1293
+ get resolvedHref() {
1294
+ return buttonBlockHref(this);
1295
+ }
1264
1296
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: ButtonBlockComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1265
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.31", type: ButtonBlockComponent, isStandalone: false, selector: "a[iox-button-block],button[iox-button-block]", inputs: { tag: "tag", href: "href", target: "target", type: "type", nodeId: "nodeId" }, host: { properties: { "class": "'iox-btn-block iox-node-' + nodeId", "attr.href": "tag === 'a' ? (href || null) : null", "attr.target": "tag === 'a' ? (target || null) : null", "attr.type": "tag === 'a' ? null : type" } }, viewQueries: [{ propertyName: "childrenHost", first: true, predicate: ["childrenHost"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `<ng-container #childrenHost></ng-container>`, isInline: true, styles: [":host{box-sizing:border-box}\n"] }); }
1297
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.31", type: ButtonBlockComponent, isStandalone: false, selector: "a[iox-button-block],button[iox-button-block]", inputs: { tag: "tag", linkType: "linkType", href: "href", pageRoute: "pageRoute", target: "target", type: "type", nodeId: "nodeId" }, host: { properties: { "class": "'iox-btn-block iox-node-' + nodeId", "attr.href": "resolvedHref", "attr.target": "tag === 'a' ? (target || null) : null", "attr.type": "tag === 'a' ? null : type" } }, viewQueries: [{ propertyName: "childrenHost", first: true, predicate: ["childrenHost"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: `<ng-container #childrenHost></ng-container>`, isInline: true, styles: [":host{box-sizing:border-box}\n"] }); }
1266
1298
  }
1267
1299
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImport: i0, type: ButtonBlockComponent, decorators: [{
1268
1300
  type: Component,
1269
1301
  args: [{ selector: 'a[iox-button-block],button[iox-button-block]', template: `<ng-container #childrenHost></ng-container>`, host: {
1270
1302
  '[class]': "'iox-btn-block iox-node-' + nodeId",
1271
- '[attr.href]': "tag === 'a' ? (href || null) : null",
1303
+ '[attr.href]': 'resolvedHref',
1272
1304
  '[attr.target]': "tag === 'a' ? (target || null) : null",
1273
1305
  '[attr.type]': "tag === 'a' ? null : type",
1274
1306
  }, standalone: false, styles: [":host{box-sizing:border-box}\n"] }]
1275
1307
  }], propDecorators: { tag: [{
1276
1308
  type: Input
1309
+ }], linkType: [{
1310
+ type: Input
1277
1311
  }], href: [{
1278
1312
  type: Input
1313
+ }], pageRoute: [{
1314
+ type: Input
1279
1315
  }], target: [{
1280
1316
  type: Input
1281
1317
  }], type: [{
@@ -3692,6 +3728,85 @@ function normaliseErrors(raw) {
3692
3728
  return Object.keys(errors).length ? errors : undefined;
3693
3729
  }
3694
3730
 
3731
+ /**
3732
+ * FORM PRESETS — a complete, working form as one insert: its fields, its submit label and the words of
3733
+ * its Success and Error blocks. ONE definition (W1.1): the builder's Forms tray builds a preset from
3734
+ * here (`buildFormPreset`, iox-builder), and the site composer (`generation-core`) stamps the SAME preset
3735
+ * into a composed page, so a generated contact form is the real one — never a second, drifting copy.
3736
+ * Data only: framework-free, like the rest of forms-core.
3737
+ */
3738
+ var FormPresetId;
3739
+ (function (FormPresetId) {
3740
+ FormPresetId["Contact"] = "contact";
3741
+ FormPresetId["Newsletter"] = "newsletter";
3742
+ FormPresetId["Application"] = "application";
3743
+ FormPresetId["Booking"] = "booking";
3744
+ })(FormPresetId || (FormPresetId = {}));
3745
+ const FORM_PRESETS = Object.freeze([
3746
+ {
3747
+ id: FormPresetId.Contact, name: 'Contact', icon: 'ph-thin ph-envelope-simple',
3748
+ description: 'Name, email and a message. Stored, and emailed to you.',
3749
+ formName: 'Contact form',
3750
+ fields: [
3751
+ { label: 'Full name', control: 'text', required: true },
3752
+ { label: 'Email', control: 'email', required: true },
3753
+ { label: 'Message', control: 'textarea', required: true, rows: 5 },
3754
+ ],
3755
+ submitLabel: 'Send message',
3756
+ successText: 'Thanks — we’ll be in touch shortly.',
3757
+ errorText: 'We couldn’t send your message. Please try again — your answers are still here.',
3758
+ },
3759
+ {
3760
+ id: FormPresetId.Newsletter, name: 'Newsletter', icon: 'ph-thin ph-paper-plane-tilt',
3761
+ description: 'One email field plus consent. Stored.',
3762
+ formName: 'Newsletter signup',
3763
+ fields: [
3764
+ { label: 'Email', control: 'email', required: true, placeholder: 'you@company.com' },
3765
+ // Consent is a checkbox that must be TICKED — `required` on a checkbox becomes the
3766
+ // `accepted` rule, with its own message, rather than a generic "this is required".
3767
+ { label: 'Email me occasional updates', control: 'checkbox', required: true },
3768
+ ],
3769
+ submitLabel: 'Subscribe',
3770
+ successText: 'You’re on the list.',
3771
+ errorText: 'We couldn’t sign you up. Please try again.',
3772
+ },
3773
+ {
3774
+ id: FormPresetId.Application, name: 'Application', icon: 'ph-thin ph-read-cv-logo',
3775
+ description: 'Details plus a CV upload. Stored, with an auto-reply.',
3776
+ formName: 'Application',
3777
+ fields: [
3778
+ { label: 'Full name', control: 'text', required: true },
3779
+ { label: 'Email', control: 'email', required: true },
3780
+ { label: 'Phone', control: 'tel' },
3781
+ { label: 'Role', control: 'select', required: true, optionsText: 'Design\nEngineering\nOther' },
3782
+ { label: 'CV', control: 'file', required: true, help: 'PDF or Word, up to 5MB' },
3783
+ { label: 'Anything else', control: 'textarea', rows: 4 },
3784
+ ],
3785
+ submitLabel: 'Apply',
3786
+ successText: 'Application received — we’ll read it properly and reply.',
3787
+ errorText: 'We couldn’t submit your application. Please try again.',
3788
+ },
3789
+ {
3790
+ id: FormPresetId.Booking, name: 'Booking request', icon: 'ph-thin ph-calendar-check',
3791
+ description: 'Date and party size. Stored, and it notifies you.',
3792
+ formName: 'Booking request',
3793
+ fields: [
3794
+ { label: 'Name', control: 'text', required: true },
3795
+ { label: 'Email', control: 'email', required: true },
3796
+ { label: 'Date', control: 'date', required: true },
3797
+ { label: 'People', control: 'number', required: true },
3798
+ { label: 'Notes', control: 'textarea', rows: 3, help: 'Allergies, access needs, anything useful' },
3799
+ ],
3800
+ submitLabel: 'Request a booking',
3801
+ successText: 'Request received — we’ll confirm by email.',
3802
+ errorText: 'We couldn’t send your request. Please try again.',
3803
+ },
3804
+ ]);
3805
+ /** The preset with this id, or undefined. */
3806
+ function formPresetById(id) {
3807
+ return FORM_PRESETS.find(p => p.id === id);
3808
+ }
3809
+
3695
3810
  /*
3696
3811
  * @vectoriox/iox-ui/forms-core — the shared, FRAMEWORK-FREE core of the forms feature.
3697
3812
  *