@vectoriox/iox-builder 4.32.2 → 4.32.3

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.
@@ -10063,25 +10063,34 @@ function button(label, createConfig, interaction, styles = {}) {
10063
10063
  return btn;
10064
10064
  }
10065
10065
  /** The C1/C2 board button voices — Swiss by fallback, the brand's the moment tokens seed. */
10066
+ // width:'auto' + flexShrink:'0' on every voice: a consent button never stretches to its row's
10067
+ // height nor shrinks until its label wraps — both happened on the canvas (Rule 0, 2026-10-10).
10066
10068
  const SOLID = {
10067
10069
  backgroundColor: TOKEN$1('brand-500', '#1f1d1b'), color: TOKEN$1('brandInk', '#ffffff'),
10068
10070
  fontSize: '12px', fontWeight: '600', padding: '9px 16px',
10069
10071
  borderRadius: TOKEN$1('radius-control', '4px'),
10072
+ width: 'auto', flexShrink: '0',
10070
10073
  };
10071
10074
  const OUTLINED = {
10072
10075
  backgroundColor: 'transparent', color: TOKEN$1('ink', '#1f1d1b'),
10073
10076
  borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('ink', '#1f1d1b'),
10074
10077
  fontSize: '12px', fontWeight: '600', padding: '8px 16px',
10075
10078
  borderRadius: TOKEN$1('radius-control', '4px'),
10079
+ width: 'auto', flexShrink: '0',
10076
10080
  };
10077
10081
  const QUIET = {
10078
10082
  backgroundColor: 'transparent', color: TOKEN$1('inkMuted', '#4a453f'),
10079
10083
  fontSize: '11px', fontWeight: '400', padding: '2px 4px', textDecoration: 'underline',
10084
+ width: 'auto', flexShrink: '0',
10080
10085
  };
10081
10086
  function row(createConfig, styles, children) {
10082
10087
  const container = createConfig('Container');
10083
10088
  if (!container || children.some(c => !c))
10084
10089
  return null;
10090
+ // The Container config defaults (minHeight 200px — the canvas droppability affordance) are
10091
+ // serialized with the node, so a preset box must OWN its height or every card ships 200px
10092
+ // tall with dead space (Rule 0 catch, 2026-10-10). Callers may still override.
10093
+ setStyleTrait(container, 'minHeight', 'auto');
10085
10094
  for (const [prop, value] of Object.entries(styles))
10086
10095
  setStyleTrait(container, prop, value);
10087
10096
  container.children = children;
@@ -10111,7 +10120,9 @@ function buildConsentPreset(createConfig) {
10111
10120
  const heading = text$1('Cookies on this site', { fontSize: '13px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
10112
10121
  // The first layer NAMES the three categories (plan §7) — the board does it in the copy.
10113
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);
10114
- const textCol = row(createConfig, { display: 'flex', flexDirection: 'column', gap: '4px', flexGrow: '1' }, [heading, body]);
10123
+ // width:'auto' throughout — the Container default is 100%, and two 100%-wide columns
10124
+ // cannot share the bar's row (they wrap into a stack; Rule 0 catch, 2026-10-10).
10125
+ const textCol = row(createConfig, { display: 'flex', flexDirection: 'column', gap: '4px', flexGrow: '1', width: 'auto' }, [heading, body]);
10115
10126
  const accept = button('Accept all', createConfig, click([
10116
10127
  { type: 'grantConsent' },
10117
10128
  { type: 'closeDialog', target: banner.id },
@@ -10123,9 +10134,9 @@ function buildConsentPreset(createConfig) {
10123
10134
  const prefs = button('Preferences', createConfig, click([
10124
10135
  { type: 'openConsentPreferences', target: preferences.id },
10125
10136
  ]), QUIET);
10126
- const acceptRejectRow = row(createConfig, { display: 'flex', gap: '7px' }, [accept, reject]);
10127
- const buttonsCol = row(createConfig, { display: 'flex', flexDirection: 'column', gap: '7px', alignItems: 'center' }, [acceptRejectRow, prefs]);
10128
- const bannerRow = row(createConfig, { display: 'flex', gap: '18px', alignItems: 'flex-start', flexWrap: 'wrap' }, [textCol, buttonsCol]);
10137
+ const acceptRejectRow = row(createConfig, { display: 'flex', gap: '7px', alignItems: 'center', width: 'auto' }, [accept, reject]);
10138
+ const buttonsCol = row(createConfig, { display: 'flex', flexDirection: 'column', gap: '7px', alignItems: 'center', width: 'auto', flexShrink: '0' }, [acceptRejectRow, prefs]);
10139
+ const bannerRow = row(createConfig, { display: 'flex', gap: '18px', alignItems: 'center', flexWrap: 'wrap' }, [textCol, buttonsCol]);
10129
10140
  if (!bannerRow)
10130
10141
  return null;
10131
10142
  banner.children = [bannerRow];
@@ -10147,11 +10158,12 @@ function buildConsentPreset(createConfig) {
10147
10158
  };
10148
10159
  const nameText = (s) => text$1(s, { fontSize: '13px', fontWeight: '600', color: TOKEN$1('ink', '#1f1d1b') }, createConfig);
10149
10160
  const descText = (s) => text$1(s, { fontSize: '11px', color: TOKEN$1('inkMuted', '#6b6560'), lineHeight: '1.5' }, createConfig);
10150
- const textColOf = (name, desc) => row(createConfig, { display: 'flex', flexDirection: 'column', gap: '2px', flexGrow: '1' }, [nameText(name), descText(desc)]);
10161
+ const textColOf = (name, desc) => row(createConfig, { display: 'flex', flexDirection: 'column', gap: '2px', flexGrow: '1', width: 'auto' }, [nameText(name), descText(desc)]);
10151
10162
  const alwaysOn = text$1('ALWAYS ON', {
10152
10163
  fontSize: '10px', fontWeight: '600', color: TOKEN$1('inkMuted', '#6b6560'),
10153
10164
  borderWidth: '1px', borderStyle: 'solid', borderColor: TOKEN$1('line', '#e6e3e1'),
10154
10165
  borderRadius: '999px', padding: '3px 8px',
10166
+ width: 'auto', flexShrink: '0', // a chip hugs its word (Text defaults to 100%)
10155
10167
  }, createConfig);
10156
10168
  const necessaryCard = row(createConfig, CARD, [
10157
10169
  textColOf('Necessary', 'Keeps the site working: your session, your language, this very choice. Always on.'),
@@ -10169,6 +10181,7 @@ function buildConsentPreset(createConfig) {
10169
10181
  setTrait(sw, 'control', 'switch');
10170
10182
  setTrait(sw, 'name', `consent-${category}`);
10171
10183
  setStyleTrait(sw, 'width', 'auto');
10184
+ setStyleTrait(sw, 'flexShrink', '0');
10172
10185
  return row(createConfig, CARD, [textColOf(name, desc), sw]);
10173
10186
  };
10174
10187
  const analyticsCard = categoryCard('analytics', 'Analytics', 'Anonymous counts of visits and pages. Off means the analytics script never loads.');
@@ -10185,8 +10198,11 @@ function buildConsentPreset(createConfig) {
10185
10198
  { type: 'grantConsent' },
10186
10199
  { type: 'closeDialog', target: preferences.id },
10187
10200
  ]), SOLID);
10188
- const spacer = row(createConfig, { flexGrow: '1' }, []);
10189
- const footer = row(createConfig, { display: 'flex', gap: '8px', alignItems: 'center' }, [prefsReject, spacer, prefsDone, prefsAccept]);
10201
+ // No spacer Container — an EMPTY container paints the canvas "click to select" placeholder
10202
+ // and squeezes the buttons until their labels wrap (Rule 0 catch). space-between + an end
10203
+ // group is the same board layout with no empty node.
10204
+ const footerEnd = row(createConfig, { display: 'flex', gap: '8px', alignItems: 'center', width: 'auto', flexShrink: '0' }, [prefsDone, prefsAccept]);
10205
+ const footer = row(createConfig, { display: 'flex', gap: '8px', alignItems: 'center', justifyContent: 'space-between' }, [prefsReject, footerEnd]);
10190
10206
  if (!prefsHeading || !prefsSub || !necessaryCard || !analyticsCard || !marketingCard || !footer)
10191
10207
  return null;
10192
10208
  preferences.children = [prefsHeading, prefsSub, necessaryCard, analyticsCard, marketingCard, footer];