@adia-ai/web-components 0.8.39 → 0.8.40

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.
Files changed (89) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/MIGRATION.md +240 -0
  3. package/components/agent-artifact/agent-artifact.css +1 -1
  4. package/components/agent-reasoning/agent-reasoning.css +2 -2
  5. package/components/agent-trace/agent-trace.css +3 -3
  6. package/components/alert/alert.css +1 -1
  7. package/components/avatar/avatar.css +1 -1
  8. package/components/badge/badge.css +1 -1
  9. package/components/button/button.css +6 -5
  10. package/components/calendar-picker/calendar-picker.css +1 -1
  11. package/components/card/card.css +3 -3
  12. package/components/chart/chart.a2ui.json +5 -5
  13. package/components/chart/chart.class.js +4 -4
  14. package/components/chart/chart.css +6 -6
  15. package/components/chart/chart.d.ts +2 -2
  16. package/components/chart/chart.yaml +3 -2
  17. package/components/chat-thread/chat-thread.css +1 -1
  18. package/components/code/code.css +6 -6
  19. package/components/combobox/combobox.css +2 -2
  20. package/components/command/command.css +3 -3
  21. package/components/date-range-picker/date-range-picker.css +1 -1
  22. package/components/datetime-picker/datetime-picker.css +1 -1
  23. package/components/description-list/description-list.css +2 -2
  24. package/components/display-field/display-field.css +3 -3
  25. package/components/divider/divider.css +1 -1
  26. package/components/drawer/drawer.css +2 -2
  27. package/components/drilldown/drilldown.css +2 -2
  28. package/components/empty-state/empty-state.css +2 -2
  29. package/components/field/field.css +1 -1
  30. package/components/heatmap/heatmap.css +2 -2
  31. package/components/inline-message/inline-message.css +1 -1
  32. package/components/input/input.css +5 -4
  33. package/components/integration-card/integration-card.css +4 -4
  34. package/components/kbd/kbd.css +1 -1
  35. package/components/list/list.css +2 -2
  36. package/components/nav/nav.css +2 -2
  37. package/components/nav-group/nav-group.css +3 -3
  38. package/components/nav-item/nav-item.css +2 -2
  39. package/components/option-card/option-card.css +1 -1
  40. package/components/otp-input/otp-input.css +1 -1
  41. package/components/page/page.css +2 -2
  42. package/components/pagination/pagination.css +1 -1
  43. package/components/pane/pane.css +1 -1
  44. package/components/progress-row/progress-row.css +2 -2
  45. package/components/qr-code/qr-code.a2ui.json +10 -10
  46. package/components/qr-code/qr-code.class.js +3 -3
  47. package/components/qr-code/qr-code.d.ts +10 -7
  48. package/components/qr-code/qr-code.yaml +13 -9
  49. package/components/range/range.css +1 -1
  50. package/components/rating/rating.css +1 -1
  51. package/components/richtext/richtext.css +3 -3
  52. package/components/segment/segment.css +5 -4
  53. package/components/select/select.css +3 -3
  54. package/components/spinner/spinner.css +1 -1
  55. package/components/stat/stat.css +3 -3
  56. package/components/step-progress/step-progress.css +1 -1
  57. package/components/stepper/stepper.css +2 -2
  58. package/components/swatch/swatch.css +2 -2
  59. package/components/table/table.a2ui.json +0 -10
  60. package/components/table/table.class.js +4 -4
  61. package/components/table/table.css +6 -9
  62. package/components/table/table.d.ts +0 -2
  63. package/components/table/table.yaml +0 -9
  64. package/components/table-toolbar/table-toolbar.css +1 -1
  65. package/components/tabs/tabs.css +1 -1
  66. package/components/tag/tag.css +2 -2
  67. package/components/tags-input/tags-input.css +1 -1
  68. package/components/textarea/textarea.css +1 -1
  69. package/components/time-picker/time-picker.css +1 -1
  70. package/components/timeline/timeline.css +4 -4
  71. package/components/toc/toc.css +1 -1
  72. package/components/toggle-group/toggle-group.class.js +3 -11
  73. package/components/toggle-group/toggle-group.css +1 -3
  74. package/components/toggle-group/toggle-group.d.ts +1 -2
  75. package/components/toggle-group/toggle-group.yaml +1 -4
  76. package/components/toggle-group/toggle-option.a2ui.json +1 -1
  77. package/components/toggle-group/toggle-option.yaml +2 -6
  78. package/components/tooltip/tooltip.css +1 -1
  79. package/components/tour/tour.css +2 -2
  80. package/components/tree/tree.css +1 -1
  81. package/custom-elements.json +7 -15
  82. package/dist/host.min.css +1 -1
  83. package/dist/host.sheet.js +1 -1
  84. package/dist/theme-provider.min.js +1 -1
  85. package/dist/web-components.min.css +1 -1
  86. package/dist/web-components.min.js +89 -89
  87. package/dist/web-components.sheet.js +1 -1
  88. package/package.json +1 -1
  89. package/styles/type/scale.css +6 -7
@@ -149,7 +149,7 @@
149
149
  color: var(--combobox-fg);
150
150
  font: inherit;
151
151
  font-size: var(--combobox-font-size);
152
- line-height: 1.4;
152
+ line-height: var(--a-font-leading-normal);
153
153
  white-space: nowrap;
154
154
  overflow: hidden;
155
155
  /* Positioning context for the [data-empty]::before placeholder pseudo
@@ -322,7 +322,7 @@ combobox-ui [data-listbox] [role="group"] [data-group-label] {
322
322
  font-weight: var(--a-ui-weight);
323
323
  color: var(--a-ui-text-muted);
324
324
  text-transform: uppercase;
325
- letter-spacing: 0.05em;
325
+ letter-spacing: var(--a-font-tracking-wide);
326
326
  white-space: nowrap;
327
327
  }
328
328
 
@@ -111,7 +111,7 @@
111
111
  color: var(--command-fg);
112
112
  font-family: var(--command-font-family, var(--a-font-family-ui));
113
113
  font-size: var(--command-input-font-size);
114
- line-height: 1.4;
114
+ line-height: var(--a-font-leading-normal);
115
115
  padding: 0;
116
116
  white-space: nowrap;
117
117
  overflow: hidden;
@@ -216,7 +216,7 @@
216
216
  font-weight: var(--command-group-font-weight);
217
217
  color: var(--command-group-fg);
218
218
  text-transform: uppercase;
219
- letter-spacing: 0.05em;
219
+ letter-spacing: var(--a-font-tracking-wide);
220
220
  white-space: nowrap;
221
221
  }
222
222
 
@@ -255,7 +255,7 @@
255
255
  border-radius: var(--command-kbd-radius);
256
256
  font-family: inherit;
257
257
  font-size: inherit;
258
- line-height: 1.6;
258
+ line-height: var(--a-font-leading-loose);
259
259
  color: var(--command-kbd-fg);
260
260
  background: var(--command-kbd-bg);
261
261
  }
@@ -119,7 +119,7 @@
119
119
  slot triplet. button-ui's natural alignment is `center`; our
120
120
  leading+text+trailing layout reads better as space-between. */
121
121
  justify-content: space-between;
122
- line-height: 1;
122
+ line-height: var(--a-font-leading-none);
123
123
  transition:
124
124
  border-color var(--date-range-picker-duration) var(--date-range-picker-easing),
125
125
  background var(--date-range-picker-duration) var(--date-range-picker-easing);
@@ -77,7 +77,7 @@
77
77
  :scope [slot="trigger"] {
78
78
  min-width: var(--datetime-picker-trigger-min-width);
79
79
  justify-content: space-between;
80
- line-height: 1;
80
+ line-height: var(--a-font-leading-none);
81
81
  }
82
82
  /* A committed value bumps to --a-ui-text (bright), matching input-ui /
83
83
  select-ui / time-picker value color; the empty placeholder keeps
@@ -44,7 +44,7 @@
44
44
  font-size: var(--description-list-term-font-size);
45
45
  font-weight: var(--description-list-term-weight);
46
46
  color: var(--description-list-term-fg);
47
- line-height: 1.3;
47
+ line-height: var(--a-font-leading-normal);
48
48
  }
49
49
 
50
50
  [data-dl-desc],
@@ -53,7 +53,7 @@
53
53
  font-size: var(--description-list-desc-font-size);
54
54
  font-weight: var(--description-list-desc-weight);
55
55
  color: var(--description-list-desc-fg);
56
- line-height: 1.4;
56
+ line-height: var(--a-font-leading-relaxed);
57
57
  }
58
58
 
59
59
  /* Pair separator: extra margin under each non-last dd so DD→DT (between
@@ -50,7 +50,7 @@
50
50
  color: var(--display-field-label-color);
51
51
  font-size: var(--display-field-label-size);
52
52
  font-weight: var(--display-field-label-weight);
53
- line-height: 1.3;
53
+ line-height: var(--a-font-leading-normal);
54
54
  min-width: 0;
55
55
  }
56
56
 
@@ -67,7 +67,7 @@
67
67
  color: var(--display-field-value-color);
68
68
  font-size: var(--display-field-value-size);
69
69
  font-weight: var(--display-field-value-weight);
70
- line-height: 1.3;
70
+ line-height: var(--a-font-leading-normal);
71
71
  min-width: 0;
72
72
  }
73
73
 
@@ -75,7 +75,7 @@
75
75
  grid-area: hint;
76
76
  color: var(--display-field-hint-color);
77
77
  font-size: var(--display-field-hint-size);
78
- line-height: 1.3;
78
+ line-height: var(--a-font-leading-normal);
79
79
  min-width: 0;
80
80
  }
81
81
 
@@ -52,7 +52,7 @@
52
52
  font-size: var(--divider-label-font);
53
53
  color: var(--divider-label-fg);
54
54
  white-space: nowrap;
55
- line-height: 1;
55
+ line-height: var(--a-font-leading-none);
56
56
  }
57
57
 
58
58
  /* ── Vertical ── */
@@ -244,7 +244,7 @@ drawer-ui [slot="panel"] > [slot="header"]:has(> :is([slot="description"], p, sm
244
244
  drawer-ui [slot="panel"] > [slot="header"] > :is([slot="heading"], h1, h2, h3, h4, h5, h6),
245
245
  drawer-ui [slot="panel"] > [slot="header"] > [slot="heading"] :is(h1, h2, h3, h4, h5, h6) {
246
246
  grid-row: 1;
247
- line-height: 1.3;
247
+ line-height: var(--a-font-leading-normal);
248
248
  margin: 0;
249
249
  font-size: var(--drawer-heading-size);
250
250
  font-weight: var(--drawer-heading-weight);
@@ -266,7 +266,7 @@ drawer-ui [slot="panel"] > [slot="header"]:not(:has(> [slot="icon"])) > :is([slo
266
266
  drawer-ui [slot="panel"] > [slot="header"] > :is([slot="description"], p, small) {
267
267
  grid-row: 2;
268
268
  grid-column: 1 / -1;
269
- line-height: 1.4;
269
+ line-height: var(--a-font-leading-relaxed);
270
270
  margin: 0;
271
271
  font-size: var(--drawer-description-size);
272
272
  color: var(--drawer-description-fg);
@@ -230,7 +230,7 @@
230
230
  flex-direction: column;
231
231
  min-width: 0;
232
232
  flex: 1;
233
- line-height: 1.3;
233
+ line-height: var(--a-font-leading-normal);
234
234
  }
235
235
  [slot="label"] {
236
236
  overflow: hidden;
@@ -256,7 +256,7 @@
256
256
  border-radius: var(--drilldown-count-chip-radius);
257
257
  font-size: var(--drilldown-count-chip-font-size);
258
258
  font-variant-numeric: tabular-nums;
259
- line-height: 1;
259
+ line-height: var(--a-font-leading-none);
260
260
  background: var(--drilldown-count-chip-bg);
261
261
  color: var(--drilldown-count-chip-fg);
262
262
  white-space: nowrap;
@@ -44,14 +44,14 @@
44
44
  font-size: var(--empty-state-heading-size);
45
45
  font-weight: var(--empty-state-heading-weight);
46
46
  color: var(--empty-state-heading-fg);
47
- line-height: 1.3;
47
+ line-height: var(--a-font-leading-normal);
48
48
  }
49
49
 
50
50
  /* ── Description ── */
51
51
  [slot="description"] {
52
52
  font-size: var(--empty-state-desc-size);
53
53
  color: var(--empty-state-desc-fg);
54
- line-height: 1.5;
54
+ line-height: var(--a-font-leading-relaxed);
55
55
  max-width: 36ch;
56
56
  }
57
57
 
@@ -133,7 +133,7 @@
133
133
  :scope [slot="hint"],
134
134
  :scope [slot="error"] {
135
135
  grid-area: message;
136
- line-height: 1.3;
136
+ line-height: var(--a-font-leading-normal);
137
137
  }
138
138
  :scope [slot="hint"] {
139
139
  color: var(--field-hint-color);
@@ -53,7 +53,7 @@
53
53
 
54
54
  /* Title slot */
55
55
  :scope [slot="title"] {
56
- font-weight: 600;
56
+ font-weight: var(--a-weight-semibold);
57
57
  margin: 0;
58
58
  }
59
59
 
@@ -66,7 +66,7 @@
66
66
  }
67
67
 
68
68
  :scope [data-month-label] {
69
- line-height: 1;
69
+ line-height: var(--a-font-leading-none);
70
70
  }
71
71
 
72
72
  /* Grid of cells */
@@ -14,7 +14,7 @@
14
14
 
15
15
  /* ── Typography ── */
16
16
  --inline-message-font-size: var(--a-ui-sm);
17
- --inline-message-line-height: var(--a-leading-snug);
17
+ --inline-message-line-height: var(--a-font-leading-normal);
18
18
  }
19
19
 
20
20
  :scope {
@@ -106,13 +106,14 @@ input-ui:not([disabled]) [slot="field"]:hover [slot="suffix"] {
106
106
  /* font-family floor — see segment.css rationale. */
107
107
  font-family: var(--input-font-family);
108
108
  font-size: var(--input-font-size);
109
- /* line-height: 1.4 (not 1) so descender-bearing glyphs (g, j, p, q, y)
110
- have room inside [slot="text"]'s line box. With line-height: 1 the
109
+ /* line-height: normal (1.35, not 1) so descender-bearing glyphs
110
+ (g, j, p, q, y) have room inside [slot="text"]'s line box. With
111
+ line-height: 1 the
111
112
  line box equals the em-square and descenders extend below it; the
112
113
  overflow: hidden on [slot="text"] then clips them. The min-height
113
114
  still controls overall chrome height — align-items: center keeps the
114
115
  baseline centered regardless of line-height. */
115
- line-height: 1.4;
116
+ line-height: var(--a-font-leading-normal);
116
117
  cursor: text;
117
118
  /* Cover every property the hover / focus / invalid states change so
118
119
  the field doesn't half-snap (border slides, but bg/colour/ring snap). */
@@ -306,7 +307,7 @@ input-ui:not([disabled]) [slot="field"]:hover [slot="suffix"] {
306
307
  flex-shrink: 0;
307
308
  color: var(--input-affix-fg);
308
309
  font-size: var(--input-font-size);
309
- line-height: 1;
310
+ line-height: var(--a-font-leading-none);
310
311
  user-select: none;
311
312
  pointer-events: none;
312
313
  }
@@ -97,7 +97,7 @@
97
97
  color: var(--integration-card-heading-fg);
98
98
  font-size: var(--integration-card-heading-size);
99
99
  font-weight: var(--integration-card-heading-weight);
100
- line-height: 1.3;
100
+ line-height: var(--a-font-leading-normal);
101
101
  min-width: 0;
102
102
  overflow: hidden;
103
103
  text-overflow: ellipsis;
@@ -118,7 +118,7 @@
118
118
  margin: 0;
119
119
  color: var(--integration-card-description-fg);
120
120
  font-size: var(--integration-card-description-size);
121
- line-height: 1.4;
121
+ line-height: var(--a-font-leading-relaxed);
122
122
  }
123
123
  :scope > [data-integration-card-description][hidden] {
124
124
  display: none;
@@ -131,7 +131,7 @@
131
131
  margin: 0;
132
132
  color: var(--integration-card-description-fg);
133
133
  font-size: var(--integration-card-description-size);
134
- line-height: 1.4;
134
+ line-height: var(--a-font-leading-relaxed);
135
135
  }
136
136
 
137
137
  /* ── Error message ── */
@@ -139,7 +139,7 @@
139
139
  margin: 0;
140
140
  color: var(--integration-card-error-fg);
141
141
  font-size: var(--integration-card-error-size);
142
- line-height: 1.4;
142
+ line-height: var(--a-font-leading-relaxed);
143
143
  }
144
144
  :scope > [data-integration-card-error][hidden] {
145
145
  display: none;
@@ -43,7 +43,7 @@
43
43
  font-family: var(--kbd-font);
44
44
  font-size: var(--kbd-font-size);
45
45
  font-weight: var(--kbd-weight);
46
- line-height: 1;
46
+ line-height: var(--a-font-leading-none);
47
47
  color: var(--kbd-fg);
48
48
  background: var(--kbd-bg);
49
49
  border: 1px solid var(--kbd-border);
@@ -125,7 +125,7 @@
125
125
  row-gap: var(--list-item-gap-row);
126
126
  font-size: var(--list-item-font-size);
127
127
  color: var(--list-item-text-color);
128
- line-height: 1.4;
128
+ line-height: var(--a-font-leading-normal);
129
129
  /* Defensive floor: empty list-item-ui (no text/icon/children) collapses
130
130
  to 0 height and disappears. Keep a visible row instead. */
131
131
  min-height: var(--a-space-6);
@@ -175,7 +175,7 @@
175
175
  grid-row: 2;
176
176
  color: var(--list-item-desc-color);
177
177
  font-size: var(--list-item-desc-font-size);
178
- line-height: 1.3;
178
+ line-height: var(--a-font-leading-normal);
179
179
  }
180
180
 
181
181
  /* When a [slot="action"] child is present, the grid becomes 3-column:
@@ -80,7 +80,7 @@
80
80
  font-weight: var(--nav-label-weight);
81
81
  color: var(--nav-label-fg);
82
82
  text-transform: uppercase;
83
- letter-spacing: 0.06em;
83
+ letter-spacing: var(--a-font-tracking-wider);
84
84
  white-space: nowrap;
85
85
  overflow: hidden;
86
86
  }
@@ -134,7 +134,7 @@
134
134
  font-weight: var(--nav-label-weight);
135
135
  color: var(--nav-label-fg);
136
136
  text-transform: uppercase;
137
- letter-spacing: 0.06em;
137
+ letter-spacing: var(--a-font-tracking-wider);
138
138
  white-space: nowrap;
139
139
  overflow: hidden;
140
140
  }
@@ -169,7 +169,7 @@
169
169
  background: var(--nav-group-badge-bg);
170
170
  padding: 1px var(--nav-group-badge-px);
171
171
  border-radius: var(--nav-group-badge-radius);
172
- line-height: 1.4;
172
+ line-height: var(--a-font-leading-normal);
173
173
  }
174
174
 
175
175
  [slot="header"] [slot="caret"] {
@@ -313,7 +313,7 @@ nav-group-ui [slot="popover-label"] {
313
313
  color: var(--nav-group-fg-muted);
314
314
  font-size: var(--a-ui-tiny);
315
315
  text-transform: uppercase;
316
- letter-spacing: 0.06em;
316
+ letter-spacing: var(--a-font-tracking-wider);
317
317
  }
318
318
 
319
319
  nav-group-ui [slot="popover"] [role="option"] {
@@ -364,7 +364,7 @@ nav-ui[variant="section"] > nav-group-ui:not([variant]) > [slot="header"] {
364
364
  font-weight: var(--a-weight-medium);
365
365
  color: var(--nav-group-fg-muted);
366
366
  text-transform: uppercase;
367
- letter-spacing: 0.06em;
367
+ letter-spacing: var(--a-font-tracking-wider);
368
368
  cursor: default;
369
369
  border-radius: 0;
370
370
  }
@@ -136,7 +136,7 @@ nav-item-ui[selected] [slot="icon"]:empty::before {
136
136
  background: var(--nav-item-badge-bg);
137
137
  padding: 1px var(--nav-item-badge-px);
138
138
  border-radius: var(--nav-item-badge-radius);
139
- line-height: 1.4;
139
+ line-height: var(--a-font-leading-normal);
140
140
  margin-inline-start: auto;
141
141
  }
142
142
 
@@ -147,7 +147,7 @@ nav-item-ui[selected] [slot="icon"]:empty::before {
147
147
  border: 1px solid var(--nav-item-trailing-border);
148
148
  border-radius: var(--nav-item-trailing-radius);
149
149
  padding: 0 var(--nav-item-trailing-px);
150
- line-height: 1.6;
150
+ line-height: var(--a-font-leading-loose);
151
151
  flex-shrink: 0;
152
152
  }
153
153
 
@@ -77,7 +77,7 @@ option-card-ui[checked] [slot="icon"] {
77
77
  --option-card-heading-size: var(--a-ui-size);
78
78
  --option-card-desc-color: var(--a-fg-muted);
79
79
  --option-card-desc-size: var(--a-ui-sm);
80
- --option-card-desc-line-height: 1.4;
80
+ --option-card-desc-line-height: var(--a-font-leading-relaxed);
81
81
  --option-card-icon-color: var(--md-sys-color-neutral-on-surface-variant);
82
82
  --option-card-icon-color-checked: var(--a-fg-strong);
83
83
  --option-card-icon-size: 1.5rem;
@@ -56,7 +56,7 @@
56
56
  color: var(--otp-input-fg);
57
57
  font-family: var(--otp-input-font);
58
58
  font-size: var(--otp-input-font-size);
59
- line-height: 1;
59
+ line-height: var(--a-font-leading-none);
60
60
  outline: none;
61
61
  transition: border-color var(--otp-input-duration) var(--otp-input-easing);
62
62
  /* Hide number spinner */
@@ -183,7 +183,7 @@
183
183
  :scope > :where(header, header-ui) > :is(text-ui[variant="display"], text-ui[variant="title"], text-ui[variant="heading"], text-ui[variant="subsection"]):not([slot]),
184
184
  :scope > :where(header, header-ui) > [slot="heading"] :is(h1, h2, h3, h4, h5, h6) {
185
185
  grid-row: 1;
186
- line-height: 1.3;
186
+ line-height: var(--a-font-leading-normal);
187
187
  margin: 0;
188
188
  }
189
189
 
@@ -210,7 +210,7 @@
210
210
  :scope > :where(header, header-ui) > :is(text-ui[variant="body"], text-ui[variant="caption"]):not([slot]) {
211
211
  grid-row: 2;
212
212
  grid-column: 1 / -1;
213
- line-height: 1.4;
213
+ line-height: var(--a-font-leading-relaxed);
214
214
  margin: 0;
215
215
  }
216
216
  :scope > :where(header, header-ui):has(> [slot="icon"]) > :is([slot="description"], p:not([slot]), small:not([slot])) { grid-column: 2 / -1; }
@@ -58,7 +58,7 @@
58
58
  font-size: var(--pagination-ellipsis-font);
59
59
  pointer-events: none;
60
60
  user-select: none;
61
- line-height: 1;
61
+ line-height: var(--a-font-leading-none);
62
62
  }
63
63
 
64
64
  /* ── variant="button" — square 1:1 cells via outline button-ui ──
@@ -141,7 +141,7 @@
141
141
  color: var(--pane-section-header-fg);
142
142
  padding-bottom: var(--pane-col-gap);
143
143
  text-transform: uppercase;
144
- letter-spacing: 0.06em;
144
+ letter-spacing: var(--a-font-tracking-wider);
145
145
  font-weight: var(--pane-section-header-weight);
146
146
  }
147
147
 
@@ -31,7 +31,7 @@
31
31
  grid-area: label;
32
32
  font-size: var(--progress-row-label-size);
33
33
  color: var(--progress-row-label-fg);
34
- line-height: 1.4;
34
+ line-height: var(--a-font-leading-normal);
35
35
  min-width: 0;
36
36
  overflow: hidden;
37
37
  text-overflow: ellipsis;
@@ -44,7 +44,7 @@
44
44
  color: var(--progress-row-meta-fg);
45
45
  font-variant-numeric: tabular-nums;
46
46
  justify-self: end;
47
- line-height: 1.4;
47
+ line-height: var(--a-font-leading-normal);
48
48
  }
49
49
 
50
50
  progress-ui {
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://adiaui.dev/a2ui/v0_9/components/QRCode.json",
4
4
  "title": "QRCode",
5
- "description": "Inline QR code generator — renders a scannable code as inline SVG.\nTwo modes:\n\n**A. Auto-encode (default).** Set `[value]` to a string (URL, plain\ntext, share link, 2FA secret). The component encodes the data with\nthe built-in zero-deps QR encoder (byte mode, ECC level configurable,\nversions 1–10 up to ~150 byte chars) and renders an SVG.\n\n**B. Bring-your-own matrix.** Set `[matrix]` to a JSON string of a\n2-D 0/1 array (`[[1,0,1,...],[...],...]`). The component renders the\nsupplied matrix directly without invoking its own encoder. Use this\nwhen you need versions 11–40, kanji/alphanumeric mode, or any\nencoder feature beyond the built-in. When both `[value]` and\n`[matrix]` are set, the matrix wins (BYO override).\n\nOutput is a single `<svg>` with `viewBox=\"0 0 N N\"`. Crisp-edges\nrendering preserves the scannable cell boundaries at any size.\nSizing is controlled by the `[size]` prop (host CSS-pixel dimension);\ninternal cell size is computed from `size / (matrix-size + 2 ·\nmargin)`. ARIA: `role=\"img\"` with `aria-label` (default \"QR code\"\nor the `[label]` prop).\n",
5
+ "description": "Inline QR code generator — renders a scannable code as inline SVG.\nTwo modes:\n\n**A. Auto-encode (default).** Set `[value]` to a string (URL, plain\ntext, share link, 2FA secret). The component encodes the data with\nthe built-in zero-deps QR encoder (byte mode, ECC level configurable,\nversions 1–10 up to ~150 byte chars) and renders an SVG.\n\n**B. Bring-your-own matrix.** Set `[matrix]` to a JSON string of a\n2-D 0/1 array (`[[1,0,1,...],[...],...]`). The component renders the\nsupplied matrix directly without invoking its own encoder. Use this\nwhen you need versions 11–40, kanji/alphanumeric mode, or any\nencoder feature beyond the built-in. When both `[value]` and\n`[matrix]` are set, the matrix wins (BYO override).\n\nOutput is a single `<svg>` with `viewBox=\"0 0 N N\"`. Crisp-edges\nrendering preserves the scannable cell boundaries at any size.\nSizing is controlled by the `[size]` prop (host CSS-pixel dimension);\ninternal cell size is computed from `size / (matrix-size + 2 ·\nquiet-zone)`. ARIA: `role=\"img\"` with `aria-label` (default \"QR code\"\nor the `[label]` prop).\n",
6
6
  "type": "object",
7
7
  "allOf": [
8
8
  {
@@ -42,18 +42,18 @@
42
42
  "type": "string",
43
43
  "default": "QR code"
44
44
  },
45
- "margin": {
46
- "description": "Quiet zone in cells around the QR pattern. QR spec requires a\nminimum 4-cell margin for reliable scanning; smaller values may\nnot scan on some devices. Default `4`.\n",
47
- "type": "number",
48
- "default": 4
49
- },
50
45
  "matrix": {
51
46
  "description": "BYO precomputed bit matrix as JSON — a 2-D array of 0/1\n(`[[1,0,...],[0,1,...],...]`). When set, the built-in encoder is\nbypassed and this matrix renders directly. Useful for QR variants\nthe built-in doesn't support (versions 11–40, alphanumeric mode,\nkanji, etc.) — bring your own encoder, pass the matrix here.\n",
52
47
  "type": "string",
53
48
  "default": ""
54
49
  },
50
+ "quietZone": {
51
+ "description": "Quiet zone in cells around the QR pattern. QR spec requires a\nminimum 4-cell quiet zone for reliable scanning; smaller values\nmay not scan on some devices. Default `4`. (Renamed from\n`[margin]` — that name collided with the framework's global\n`[margin]` Scale attribute; `margin` on `qr-code-ui` now means\nthe global spacing attribute, per ADR-0053.)\n",
52
+ "type": "number",
53
+ "default": 4
54
+ },
55
55
  "size": {
56
- "description": "Host display size in CSS pixels (width and height; the SVG is\nalways square). Default 200. Internal cell size is computed from\nthis divided by `matrix-size + 2·margin`.\n",
56
+ "description": "Host display size in CSS pixels (width and height; the SVG is\nalways square). Default 200. Internal cell size is computed from\nthis divided by `matrix-size + 2·quiet-zone`.\n",
57
57
  "type": "number",
58
58
  "default": 200
59
59
  },
@@ -75,9 +75,9 @@
75
75
  "wrong": "<qr-code-ui value=\"https://very.long.url.that.exceeds.150.bytes.of.utf8.encoded.length...\"></qr-code-ui>\n"
76
76
  },
77
77
  {
78
- "fix": "<qr-code-ui value=\"...\" margin=\"4\"></qr-code-ui>\n",
79
- "why": "Zero margin breaks scanning. QR spec requires a 4-cell quiet\nzone for reliable detection.\n",
80
- "wrong": "<qr-code-ui value=\"...\" margin=\"0\"></qr-code-ui>\n"
78
+ "fix": "<qr-code-ui value=\"...\" quiet-zone=\"4\"></qr-code-ui>\n",
79
+ "why": "Zero quiet zone breaks scanning. QR spec requires a 4-cell quiet\nzone for reliable detection.\n",
80
+ "wrong": "<qr-code-ui value=\"...\" quiet-zone=\"0\"></qr-code-ui>\n"
81
81
  }
82
82
  ],
83
83
  "category": "display",
@@ -33,7 +33,7 @@ export class UIQRCode extends UIElement {
33
33
  matrix: { type: String, default: '', reflect: true },
34
34
  size: { type: Number, default: 200, reflect: true },
35
35
  errorCorrection: { type: String, default: 'M', reflect: true, attribute: 'error-correction' },
36
- margin: { type: Number, default: 4, reflect: true },
36
+ quietZone: { type: Number, default: 4, reflect: true, attribute: 'quiet-zone' },
37
37
  color: { type: String, default: '', reflect: true },
38
38
  background: { type: String, default: '', reflect: true },
39
39
  label: { type: String, default: 'QR code', reflect: true },
@@ -91,7 +91,7 @@ export class UIQRCode extends UIElement {
91
91
  // Cheap idempotence: compute a signature of inputs, skip re-render
92
92
  // if nothing changed (encoding is non-trivial — version selection +
93
93
  // RS ECC + 8 mask evaluations).
94
- const sig = `${this.value}|${this.matrix}|${this.size}|${this.errorCorrection}|${this.margin}|${this.color}|${this.background}`;
94
+ const sig = `${this.value}|${this.matrix}|${this.size}|${this.errorCorrection}|${this.quietZone}|${this.color}|${this.background}`;
95
95
  if (sig === this.#lastSig && this.querySelector('svg')) return;
96
96
  this.#lastSig = sig;
97
97
 
@@ -106,7 +106,7 @@ export class UIQRCode extends UIElement {
106
106
 
107
107
  const svg = matrixToSVG(matrix, {
108
108
  cellSize: 8, // arbitrary internal unit; host CSS controls actual size via [size]
109
- margin: Number.isFinite(this.margin) ? this.margin : 4,
109
+ margin: Number.isFinite(this.quietZone) ? this.quietZone : 4,
110
110
  // Hardcoded fallback to black-on-white — the scannable convention.
111
111
  // Theme-aware `currentColor` produces light-on-dark in dark mode,
112
112
  // which most phone cameras (iPhone Camera in particular) refuse to
@@ -18,7 +18,7 @@ Output is a single `<svg>` with `viewBox="0 0 N N"`. Crisp-edges
18
18
  rendering preserves the scannable cell boundaries at any size.
19
19
  Sizing is controlled by the `[size]` prop (host CSS-pixel dimension);
20
20
  internal cell size is computed from `size / (matrix-size + 2 ·
21
- margin)`. ARIA: `role="img"` with `aria-label` (default "QR code"
21
+ quiet-zone)`. ARIA: `role="img"` with `aria-label` (default "QR code"
22
22
  or the `[label]` prop).
23
23
 
24
24
  *
@@ -58,11 +58,6 @@ from more damage at the cost of QR-version size growth.
58
58
  better AT context (e.g. "Share link QR code", "2FA setup QR").
59
59
  */
60
60
  label: string;
61
- /** Quiet zone in cells around the QR pattern. QR spec requires a
62
- minimum 4-cell margin for reliable scanning; smaller values may
63
- not scan on some devices. Default `4`.
64
- */
65
- margin: number;
66
61
  /** BYO precomputed bit matrix as JSON — a 2-D array of 0/1
67
62
  (`[[1,0,...],[0,1,...],...]`). When set, the built-in encoder is
68
63
  bypassed and this matrix renders directly. Useful for QR variants
@@ -70,9 +65,17 @@ the built-in doesn't support (versions 11–40, alphanumeric mode,
70
65
  kanji, etc.) — bring your own encoder, pass the matrix here.
71
66
  */
72
67
  matrix: string;
68
+ /** Quiet zone in cells around the QR pattern. QR spec requires a
69
+ minimum 4-cell quiet zone for reliable scanning; smaller values
70
+ may not scan on some devices. Default `4`. (Renamed from
71
+ `[margin]` — that name collided with the framework's global
72
+ `[margin]` Scale attribute; `margin` on `qr-code-ui` now means
73
+ the global spacing attribute, per ADR-0053.)
74
+ */
75
+ quietZone: number;
73
76
  /** Host display size in CSS pixels (width and height; the SVG is
74
77
  always square). Default 200. Internal cell size is computed from
75
- this divided by `matrix-size + 2·margin`.
78
+ this divided by `matrix-size + 2·quiet-zone`.
76
79
  */
77
80
  size: number;
78
81
  /** The string to encode (URL / text / share link / 2FA seed). When
@@ -25,7 +25,7 @@ description: |
25
25
  rendering preserves the scannable cell boundaries at any size.
26
26
  Sizing is controlled by the `[size]` prop (host CSS-pixel dimension);
27
27
  internal cell size is computed from `size / (matrix-size + 2 ·
28
- margin)`. ARIA: `role="img"` with `aria-label` (default "QR code"
28
+ quiet-zone)`. ARIA: `role="img"` with `aria-label` (default "QR code"
29
29
  or the `[label]` prop).
30
30
  props:
31
31
  value:
@@ -50,7 +50,7 @@ props:
50
50
  description: |
51
51
  Host display size in CSS pixels (width and height; the SVG is
52
52
  always square). Default 200. Internal cell size is computed from
53
- this divided by `matrix-size + 2·margin`.
53
+ this divided by `matrix-size + 2·quiet-zone`.
54
54
  type: number
55
55
  default: 200
56
56
  reflect: true
@@ -64,14 +64,18 @@ props:
64
64
  enum: [L, M, Q, H]
65
65
  reflect: true
66
66
  attribute: error-correction
67
- margin:
67
+ quietZone:
68
68
  description: |
69
69
  Quiet zone in cells around the QR pattern. QR spec requires a
70
- minimum 4-cell margin for reliable scanning; smaller values may
71
- not scan on some devices. Default `4`.
70
+ minimum 4-cell quiet zone for reliable scanning; smaller values
71
+ may not scan on some devices. Default `4`. (Renamed from
72
+ `[margin]` — that name collided with the framework's global
73
+ `[margin]` Scale attribute; `margin` on `qr-code-ui` now means
74
+ the global spacing attribute, per ADR-0053.)
72
75
  type: number
73
76
  default: 4
74
77
  reflect: true
78
+ attribute: quiet-zone
75
79
  color:
76
80
  description: |
77
81
  Foreground (dark-cell) color. Any CSS color string (hex, rgb,
@@ -125,7 +129,7 @@ a2ui:
125
129
  reason: "Encoder capacity contract."
126
130
  - rule: "When QR sits over a non-white surface, set [background] to a solid color. White-on-image QR backgrounds are unreliable for scanners — quiet-zone contrast against the dark cells is the load-bearing visual."
127
131
  reason: "Scannability constraint."
128
- - rule: "The [margin] (quiet zone) defaults to 4 cells per QR spec. Smaller margins may scan on some devices but not others; do not go below 2."
132
+ - rule: "The [quiet-zone] defaults to 4 cells per QR spec. Smaller values may scan on some devices but not others; do not go below 2."
129
133
  reason: "Quiet-zone requirement."
130
134
  anti_patterns:
131
135
  - wrong: |
@@ -140,12 +144,12 @@ anti_patterns:
140
144
  with a BYO encoder library + pass the [matrix]:
141
145
  `<qr-code-ui matrix="[[1,0,1,...],...]"></qr-code-ui>`
142
146
  - wrong: |
143
- <qr-code-ui value="..." margin="0"></qr-code-ui>
147
+ <qr-code-ui value="..." quiet-zone="0"></qr-code-ui>
144
148
  why: |
145
- Zero margin breaks scanning. QR spec requires a 4-cell quiet
149
+ Zero quiet zone breaks scanning. QR spec requires a 4-cell quiet
146
150
  zone for reliable detection.
147
151
  fix: |
148
- <qr-code-ui value="..." margin="4"></qr-code-ui>
152
+ <qr-code-ui value="..." quiet-zone="4"></qr-code-ui>
149
153
  examples:
150
154
  - name: default
151
155
  description: Plain URL encoding at default size + ECC-M.
@@ -69,7 +69,7 @@ range-ui:not([disabled]) [slot="field"]:hover [data-layer="fill"] {
69
69
  /* font-family floor — see segment.css rationale. */
70
70
  font-family: var(--range-font-family);
71
71
  font-size: var(--range-font-size);
72
- line-height: 1;
72
+ line-height: var(--a-font-leading-none);
73
73
  transition:
74
74
  border-color var(--range-duration) var(--range-easing),
75
75
  background var(--range-duration) var(--range-easing);