@vectoriox/iox-builder 4.31.1 → 4.31.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.
|
@@ -1631,7 +1631,11 @@ class OverlayService {
|
|
|
1631
1631
|
if (host.classList[i].startsWith('iox-node-'))
|
|
1632
1632
|
return host;
|
|
1633
1633
|
}
|
|
1634
|
-
|
|
1634
|
+
// The node's own styled element always precedes its children in document order; for the
|
|
1635
|
+
// Dialog it sits BELOW a classless fixed stage, where firstElementChild pointed the
|
|
1636
|
+
// outline at the stage (live find 2026-10-10 — "can't select the white box").
|
|
1637
|
+
const styled = host.querySelector('[class*="iox-node-"]');
|
|
1638
|
+
return styled || host.firstElementChild || host;
|
|
1635
1639
|
}
|
|
1636
1640
|
// ── Node → Element registry ──────────────────────────────
|
|
1637
1641
|
registerNode(node, element, componentRef) {
|
|
@@ -8490,10 +8494,21 @@ class BuilderDialogComponent {
|
|
|
8490
8494
|
this.selectSub?.unsubscribe();
|
|
8491
8495
|
this.instanceRegistry.unregister(this.nodeId);
|
|
8492
8496
|
}
|
|
8493
|
-
/** A click on the stage ITSELF is the backdrop click — children swallow everything else.
|
|
8497
|
+
/** A click on the stage ITSELF is the backdrop click — children swallow everything else.
|
|
8498
|
+
* Closing clicks STOP here: the same click would bubble into canvas selection, and
|
|
8499
|
+
* select$ would reopen the dialog in the same breath (live find 2026-10-10 — "the X
|
|
8500
|
+
* doesn't work"). */
|
|
8494
8501
|
onStageClick(event) {
|
|
8495
|
-
if (event.target
|
|
8496
|
-
|
|
8502
|
+
if (event.target !== event.currentTarget)
|
|
8503
|
+
return;
|
|
8504
|
+
if (this.closeOnBackdrop !== false && this.closeOnBackdrop !== 'false') {
|
|
8505
|
+
event.stopPropagation();
|
|
8506
|
+
this.designOpen = false;
|
|
8507
|
+
}
|
|
8508
|
+
}
|
|
8509
|
+
onCloseClick(event) {
|
|
8510
|
+
event.stopPropagation();
|
|
8511
|
+
this.designOpen = false;
|
|
8497
8512
|
}
|
|
8498
8513
|
onBackdrop() {
|
|
8499
8514
|
if (this.closeOnBackdrop !== false && this.closeOnBackdrop !== 'false')
|
|
@@ -8517,7 +8532,8 @@ class BuilderDialogComponent {
|
|
|
8517
8532
|
type="button"
|
|
8518
8533
|
class="dialog-close"
|
|
8519
8534
|
aria-label="Close dialog"
|
|
8520
|
-
(
|
|
8535
|
+
(mousedown)="$event.stopPropagation()"
|
|
8536
|
+
(click)="onCloseClick($event)">
|
|
8521
8537
|
<i class="ph-thin ph-x"></i>
|
|
8522
8538
|
</button>
|
|
8523
8539
|
|
|
@@ -8553,7 +8569,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.31", ngImpo
|
|
|
8553
8569
|
type="button"
|
|
8554
8570
|
class="dialog-close"
|
|
8555
8571
|
aria-label="Close dialog"
|
|
8556
|
-
(
|
|
8572
|
+
(mousedown)="$event.stopPropagation()"
|
|
8573
|
+
(click)="onCloseClick($event)">
|
|
8557
8574
|
<i class="ph-thin ph-x"></i>
|
|
8558
8575
|
</button>
|
|
8559
8576
|
|
|
@@ -9993,6 +10010,13 @@ function setTrait(node, name, value) {
|
|
|
9993
10010
|
trait.default = value;
|
|
9994
10011
|
}
|
|
9995
10012
|
|
|
10013
|
+
function text$1(content, styles, createConfig) {
|
|
10014
|
+
const node = textNode(content, createConfig);
|
|
10015
|
+
if (node)
|
|
10016
|
+
for (const [prop, value] of Object.entries(styles))
|
|
10017
|
+
setStyleTrait(node, prop, value);
|
|
10018
|
+
return node;
|
|
10019
|
+
}
|
|
9996
10020
|
/**
|
|
9997
10021
|
* THE CONSENT PRESET (consent plan C3) — the banner as builder elements, which is the whole bet:
|
|
9998
10022
|
* Wix ships a banner you cannot design, Webflow ships a design system and no banner; ours is a
|
|
@@ -10019,16 +10043,50 @@ const click = (actions) => ({
|
|
|
10019
10043
|
target: 'self', duration: 0, delay: 0, easing: 'ease', ...a,
|
|
10020
10044
|
})),
|
|
10021
10045
|
});
|
|
10022
|
-
|
|
10046
|
+
const TOKEN$1 = (name, fallback) => `var(--iox-${name}, ${fallback})`;
|
|
10047
|
+
function button(label, createConfig, interaction, styles = {}) {
|
|
10023
10048
|
const btn = createConfig('ButtonBlock');
|
|
10024
10049
|
const text = textNode(label, createConfig);
|
|
10025
10050
|
if (!btn || !text)
|
|
10026
10051
|
return null;
|
|
10027
10052
|
setTrait(btn, 'tag', 'button');
|
|
10053
|
+
setStyleTrait(text, 'fontSize', 'inherit');
|
|
10054
|
+
setStyleTrait(text, 'fontWeight', 'inherit');
|
|
10055
|
+
setStyleTrait(text, 'color', 'inherit');
|
|
10056
|
+
for (const [prop, value] of Object.entries(styles))
|
|
10057
|
+
setStyleTrait(btn, prop, value);
|
|
10028
10058
|
btn.children = [text];
|
|
10029
10059
|
btn.interactions = [interaction];
|
|
10030
10060
|
return btn;
|
|
10031
10061
|
}
|
|
10062
|
+
/** The C1/C2 board button voices — Swiss by fallback, the brand's the moment tokens seed. */
|
|
10063
|
+
const SOLID = {
|
|
10064
|
+
backgroundColor: TOKEN$1('brand-500', '#1f1d1b'), color: TOKEN$1('brandInk', '#ffffff'),
|
|
10065
|
+
fontSize: '12px', fontWeight: '600', padding: '9px 16px',
|
|
10066
|
+
borderRadius: TOKEN$1('radius-control', '4px'),
|
|
10067
|
+
};
|
|
10068
|
+
const OUTLINED = {
|
|
10069
|
+
backgroundColor: 'transparent', color: TOKEN$1('ink', '#1f1d1b'),
|
|
10070
|
+
borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('ink', '#1f1d1b'),
|
|
10071
|
+
fontSize: '12px', fontWeight: '600', padding: '8px 16px',
|
|
10072
|
+
borderRadius: TOKEN$1('radius-control', '4px'),
|
|
10073
|
+
};
|
|
10074
|
+
const QUIET = {
|
|
10075
|
+
backgroundColor: 'transparent', color: TOKEN$1('inkMuted', '#4a453f'),
|
|
10076
|
+
fontSize: '11px', fontWeight: '400', padding: '2px 4px', textDecoration: 'underline',
|
|
10077
|
+
};
|
|
10078
|
+
const SMALL_ALLOW = {
|
|
10079
|
+
backgroundColor: 'transparent', color: TOKEN$1('ink', '#1f1d1b'),
|
|
10080
|
+
borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('ink', '#1f1d1b'),
|
|
10081
|
+
fontSize: '11px', fontWeight: '600', padding: '5px 10px',
|
|
10082
|
+
borderRadius: TOKEN$1('radius-control', '4px'),
|
|
10083
|
+
};
|
|
10084
|
+
const SMALL_REFUSE = {
|
|
10085
|
+
backgroundColor: 'transparent', color: TOKEN$1('inkMuted', '#6b6560'),
|
|
10086
|
+
borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('line', '#d8d4d1'),
|
|
10087
|
+
fontSize: '11px', fontWeight: '600', padding: '5px 10px',
|
|
10088
|
+
borderRadius: TOKEN$1('radius-control', '4px'),
|
|
10089
|
+
};
|
|
10032
10090
|
function row(createConfig, styles, children) {
|
|
10033
10091
|
const container = createConfig('Container');
|
|
10034
10092
|
if (!container || children.some(c => !c))
|
|
@@ -10050,57 +10108,97 @@ function buildConsentPreset(createConfig) {
|
|
|
10050
10108
|
setTrait(banner, 'closeOnBackdrop', false); // clicking away is NOT consent
|
|
10051
10109
|
setTrait(banner, 'showCloseButton', true); // the runtime records X as a "no"
|
|
10052
10110
|
setTrait(banner, 'placement', 'bottom'); // A5: placement is the Dialog's own choice
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10111
|
+
// Board C1, Swiss column: a full-width bottom bar, hairline-ruled, surface-on-surface.
|
|
10112
|
+
setStyleTrait(banner, 'width', '100%');
|
|
10113
|
+
setStyleTrait(banner, 'borderRadius', '0px');
|
|
10114
|
+
setStyleTrait(banner, 'padding', '14px 20px');
|
|
10115
|
+
setStyleTrait(banner, 'backgroundColor', TOKEN$1('surface', '#ffffff'));
|
|
10116
|
+
setStyleTrait(banner, 'borderWidth', '1px');
|
|
10117
|
+
setStyleTrait(banner, 'borderStyle', 'solid');
|
|
10118
|
+
setStyleTrait(banner, 'borderColor', TOKEN$1('ink', '#1f1d1b'));
|
|
10119
|
+
setStyleTrait(banner, 'boxShadow', 'none');
|
|
10120
|
+
const heading = text$1('Cookies on this site', { fontSize: '13px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
|
|
10121
|
+
// The first layer NAMES the three categories (plan §7) — the board does it in the copy.
|
|
10122
|
+
const body = text$1('We use analytics and marketing cookies only if you allow them. Necessary ones always run.', { fontSize: '11px', color: TOKEN$1('inkMuted', '#4a453f'), lineHeight: '1.5', maxWidth: '330px' }, createConfig);
|
|
10123
|
+
const textCol = row(createConfig, { display: 'flex', flexDirection: 'column', gap: '4px', flexGrow: '1' }, [heading, body]);
|
|
10059
10124
|
const accept = button('Accept all', createConfig, click([
|
|
10060
10125
|
{ type: 'grantConsent' },
|
|
10061
10126
|
{ type: 'closeDialog', target: banner.id },
|
|
10062
|
-
]));
|
|
10127
|
+
]), SOLID);
|
|
10063
10128
|
const reject = button('Reject all', createConfig, click([
|
|
10064
10129
|
{ type: 'denyConsent' },
|
|
10065
10130
|
{ type: 'closeDialog', target: banner.id },
|
|
10066
|
-
]));
|
|
10131
|
+
]), OUTLINED);
|
|
10067
10132
|
const prefs = button('Preferences', createConfig, click([
|
|
10068
10133
|
{ type: 'openConsentPreferences', target: preferences.id },
|
|
10069
|
-
]));
|
|
10070
|
-
const
|
|
10071
|
-
|
|
10134
|
+
]), QUIET);
|
|
10135
|
+
const acceptRejectRow = row(createConfig, { display: 'flex', gap: '7px' }, [accept, reject]);
|
|
10136
|
+
const buttonsCol = row(createConfig, { display: 'flex', flexDirection: 'column', gap: '7px', alignItems: 'center' }, [acceptRejectRow, prefs]);
|
|
10137
|
+
const bannerRow = row(createConfig, { display: 'flex', gap: '18px', alignItems: 'flex-start', flexWrap: 'wrap' }, [textCol, buttonsCol]);
|
|
10138
|
+
if (!bannerRow)
|
|
10072
10139
|
return null;
|
|
10073
|
-
banner.children = [
|
|
10140
|
+
banner.children = [bannerRow];
|
|
10074
10141
|
// ── the preferences modal ────────────────────────────────────────────────
|
|
10075
10142
|
preferences.label = 'Consent preferences';
|
|
10076
10143
|
setTrait(preferences, 'closeOnBackdrop', true);
|
|
10077
10144
|
setTrait(preferences, 'showCloseButton', true);
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10145
|
+
setStyleTrait(preferences, 'width', 'min(480px, calc(100vw - 48px))');
|
|
10146
|
+
setStyleTrait(preferences, 'padding', '18px 20px');
|
|
10147
|
+
setStyleTrait(preferences, 'display', 'flex');
|
|
10148
|
+
setStyleTrait(preferences, 'flexDirection', 'column');
|
|
10149
|
+
setStyleTrait(preferences, 'gap', '12px');
|
|
10150
|
+
const prefsHeading = text$1('Your privacy choices', { fontSize: '16px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
|
|
10151
|
+
const prefsSub = text$1('Change these any time from “Cookie settings” in the footer.', { fontSize: '12px', color: TOKEN$1('inkMuted', '#6b6560') }, createConfig);
|
|
10152
|
+
const CARD = {
|
|
10153
|
+
display: 'flex', gap: '12px', alignItems: 'flex-start',
|
|
10154
|
+
borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('line', '#e6e3e1'),
|
|
10155
|
+
borderRadius: TOKEN$1('radius-surface', '8px'), padding: '12px 14px',
|
|
10156
|
+
};
|
|
10157
|
+
const nameText = (s) => text$1(s, { fontSize: '13px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
|
|
10158
|
+
const descText = (s) => text$1(s, { fontSize: '11px', color: TOKEN$1('inkMuted', '#6b6560'), lineHeight: '1.5' }, createConfig);
|
|
10159
|
+
const textColOf = (name, desc) => row(createConfig, { display: 'flex', flexDirection: 'column', gap: '2px', flexGrow: '1' }, [nameText(name), descText(desc)]);
|
|
10160
|
+
const alwaysOn = text$1('ALWAYS ON', {
|
|
10161
|
+
fontSize: '10px', fontWeight: '600', color: TOKEN$1('inkMuted', '#6b6560'),
|
|
10162
|
+
borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('line', '#e6e3e1'),
|
|
10163
|
+
borderRadius: '999px', padding: '3px 8px',
|
|
10164
|
+
}, createConfig);
|
|
10165
|
+
const necessaryCard = row(createConfig, CARD, [
|
|
10166
|
+
textColOf('Necessary', 'Keeps the site working: your session, your language, this very choice. Always on.'),
|
|
10167
|
+
alwaysOn,
|
|
10168
|
+
]);
|
|
10169
|
+
const categoryCard = (category, name, desc) => {
|
|
10082
10170
|
const allow = button('Allow', createConfig, click([
|
|
10083
10171
|
{ type: 'setConsentCategory', params: { category, granted: true } },
|
|
10084
|
-
]));
|
|
10172
|
+
]), SMALL_ALLOW);
|
|
10085
10173
|
const refuse = button('Refuse', createConfig, click([
|
|
10086
10174
|
{ type: 'setConsentCategory', params: { category, granted: false } },
|
|
10087
|
-
]));
|
|
10088
|
-
const pair = row(createConfig, { display: 'flex', gap: '
|
|
10089
|
-
return row(createConfig,
|
|
10175
|
+
]), SMALL_REFUSE);
|
|
10176
|
+
const pair = row(createConfig, { display: 'flex', gap: '6px' }, [allow, refuse]);
|
|
10177
|
+
return row(createConfig, CARD, [textColOf(name, desc), pair]);
|
|
10090
10178
|
};
|
|
10091
|
-
const
|
|
10092
|
-
const
|
|
10093
|
-
|
|
10094
|
-
const
|
|
10179
|
+
const analyticsCard = categoryCard('analytics', 'Analytics', 'Anonymous counts of visits and pages. Off means the analytics script never loads.');
|
|
10180
|
+
const marketingCard = categoryCard('marketing', 'Marketing', 'Ads measurement and remarketing. Off means no ad cookies and no data shared.');
|
|
10181
|
+
// Board C2's footer: bulk exits live here too — Reject | (grow) | Done | Accept.
|
|
10182
|
+
const prefsReject = button('Reject all', createConfig, click([
|
|
10183
|
+
{ type: 'denyConsent' },
|
|
10184
|
+
{ type: 'closeDialog', target: preferences.id },
|
|
10185
|
+
]), OUTLINED);
|
|
10186
|
+
const prefsDone = button('Done', createConfig, click([
|
|
10187
|
+
{ type: 'closeDialog', target: preferences.id },
|
|
10188
|
+
]), { ...OUTLINED, color: TOKEN$1('inkMuted', '#3d3833'), borderColor: TOKEN$1('line', '#d8d4d1') });
|
|
10189
|
+
const prefsAccept = button('Accept all', createConfig, click([
|
|
10190
|
+
{ type: 'grantConsent' },
|
|
10095
10191
|
{ type: 'closeDialog', target: preferences.id },
|
|
10096
|
-
]));
|
|
10097
|
-
|
|
10192
|
+
]), SOLID);
|
|
10193
|
+
const spacer = row(createConfig, { flexGrow: '1' }, []);
|
|
10194
|
+
const footer = row(createConfig, { display: 'flex', gap: '8px', alignItems: 'center' }, [prefsReject, spacer, prefsDone, prefsAccept]);
|
|
10195
|
+
if (!prefsHeading || !prefsSub || !necessaryCard || !analyticsCard || !marketingCard || !footer)
|
|
10098
10196
|
return null;
|
|
10099
|
-
preferences.children = [prefsHeading,
|
|
10197
|
+
preferences.children = [prefsHeading, prefsSub, necessaryCard, analyticsCard, marketingCard, footer];
|
|
10100
10198
|
// ── the withdrawal path (§7.3) ───────────────────────────────────────────
|
|
10101
10199
|
const withdrawal = button('Cookie settings', createConfig, click([
|
|
10102
10200
|
{ type: 'openConsentPreferences', target: preferences.id },
|
|
10103
|
-
]));
|
|
10201
|
+
]), QUIET);
|
|
10104
10202
|
if (!withdrawal)
|
|
10105
10203
|
return null;
|
|
10106
10204
|
withdrawal.label = 'Cookie settings';
|