@orange-halo/components 2.1.0 → 3.0.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.
Files changed (130) hide show
  1. package/custom-elements.json +968 -362
  2. package/dist/base.d.ts.map +1 -1
  3. package/dist/base.js +1 -2
  4. package/dist/base.js.map +1 -1
  5. package/dist/index.d.ts +4 -8
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -4
  8. package/dist/index.js.map +1 -1
  9. package/dist/oh-accordion.d.ts +53 -8
  10. package/dist/oh-accordion.d.ts.map +1 -1
  11. package/dist/oh-accordion.js +99 -29
  12. package/dist/oh-accordion.js.map +1 -1
  13. package/dist/oh-alert.d.ts +26 -8
  14. package/dist/oh-alert.d.ts.map +1 -1
  15. package/dist/oh-alert.js +96 -36
  16. package/dist/oh-alert.js.map +1 -1
  17. package/dist/oh-badge.d.ts +32 -13
  18. package/dist/oh-badge.d.ts.map +1 -1
  19. package/dist/oh-badge.js +38 -19
  20. package/dist/oh-badge.js.map +1 -1
  21. package/dist/oh-breadcrumb.d.ts +39 -12
  22. package/dist/oh-breadcrumb.d.ts.map +1 -1
  23. package/dist/oh-breadcrumb.js +66 -25
  24. package/dist/oh-breadcrumb.js.map +1 -1
  25. package/dist/oh-button.d.ts +49 -23
  26. package/dist/oh-button.d.ts.map +1 -1
  27. package/dist/oh-button.figma.js +1 -3
  28. package/dist/oh-button.figma.js.map +1 -1
  29. package/dist/oh-button.js +133 -82
  30. package/dist/oh-button.js.map +1 -1
  31. package/dist/oh-card.d.ts +47 -19
  32. package/dist/oh-card.d.ts.map +1 -1
  33. package/dist/oh-card.js +143 -96
  34. package/dist/oh-card.js.map +1 -1
  35. package/dist/oh-checkbox-group.d.ts +56 -12
  36. package/dist/oh-checkbox-group.d.ts.map +1 -1
  37. package/dist/oh-checkbox-group.figma.js +4 -6
  38. package/dist/oh-checkbox-group.figma.js.map +1 -1
  39. package/dist/oh-checkbox-group.js +114 -49
  40. package/dist/oh-checkbox-group.js.map +1 -1
  41. package/dist/oh-checkbox.d.ts +54 -17
  42. package/dist/oh-checkbox.d.ts.map +1 -1
  43. package/dist/oh-checkbox.js +117 -60
  44. package/dist/oh-checkbox.js.map +1 -1
  45. package/dist/oh-cluster.d.ts +19 -14
  46. package/dist/oh-cluster.d.ts.map +1 -1
  47. package/dist/oh-cluster.js +19 -19
  48. package/dist/oh-cluster.js.map +1 -1
  49. package/dist/oh-container.d.ts +19 -16
  50. package/dist/oh-container.d.ts.map +1 -1
  51. package/dist/oh-container.js +21 -23
  52. package/dist/oh-container.js.map +1 -1
  53. package/dist/oh-drawer.d.ts +28 -11
  54. package/dist/oh-drawer.d.ts.map +1 -1
  55. package/dist/oh-drawer.js +52 -24
  56. package/dist/oh-drawer.js.map +1 -1
  57. package/dist/oh-footer.d.ts +37 -18
  58. package/dist/oh-footer.d.ts.map +1 -1
  59. package/dist/oh-footer.js +38 -19
  60. package/dist/oh-footer.js.map +1 -1
  61. package/dist/oh-grid.d.ts +27 -14
  62. package/dist/oh-grid.d.ts.map +1 -1
  63. package/dist/oh-grid.js +28 -21
  64. package/dist/oh-grid.js.map +1 -1
  65. package/dist/oh-icon.d.ts +21 -5
  66. package/dist/oh-icon.d.ts.map +1 -1
  67. package/dist/oh-icon.js +27 -9
  68. package/dist/oh-icon.js.map +1 -1
  69. package/dist/oh-input.d.ts +110 -21
  70. package/dist/oh-input.d.ts.map +1 -1
  71. package/dist/oh-input.figma.js +2 -2
  72. package/dist/oh-input.figma.js.map +1 -1
  73. package/dist/oh-input.js +227 -71
  74. package/dist/oh-input.js.map +1 -1
  75. package/dist/oh-link.d.ts +42 -19
  76. package/dist/oh-link.d.ts.map +1 -1
  77. package/dist/oh-link.js +83 -38
  78. package/dist/oh-link.js.map +1 -1
  79. package/dist/oh-modal.d.ts +35 -6
  80. package/dist/oh-modal.d.ts.map +1 -1
  81. package/dist/oh-modal.js +90 -39
  82. package/dist/oh-modal.js.map +1 -1
  83. package/dist/oh-navbar.d.ts +42 -19
  84. package/dist/oh-navbar.d.ts.map +1 -1
  85. package/dist/oh-navbar.js +44 -20
  86. package/dist/oh-navbar.js.map +1 -1
  87. package/dist/oh-progress.d.ts +26 -7
  88. package/dist/oh-progress.d.ts.map +1 -1
  89. package/dist/oh-progress.js +35 -14
  90. package/dist/oh-progress.js.map +1 -1
  91. package/dist/oh-radio-group.d.ts +55 -13
  92. package/dist/oh-radio-group.d.ts.map +1 -1
  93. package/dist/oh-radio-group.figma.js +2 -2
  94. package/dist/oh-radio-group.figma.js.map +1 -1
  95. package/dist/oh-radio-group.js +122 -51
  96. package/dist/oh-radio-group.js.map +1 -1
  97. package/dist/oh-radio.d.ts +55 -17
  98. package/dist/oh-radio.d.ts.map +1 -1
  99. package/dist/oh-radio.js +120 -61
  100. package/dist/oh-radio.js.map +1 -1
  101. package/dist/oh-select.d.ts +59 -16
  102. package/dist/oh-select.d.ts.map +1 -1
  103. package/dist/oh-select.js +141 -69
  104. package/dist/oh-select.js.map +1 -1
  105. package/dist/oh-skip-link.d.ts +33 -15
  106. package/dist/oh-skip-link.d.ts.map +1 -1
  107. package/dist/oh-skip-link.js +43 -32
  108. package/dist/oh-skip-link.js.map +1 -1
  109. package/dist/oh-stack.d.ts +17 -14
  110. package/dist/oh-stack.d.ts.map +1 -1
  111. package/dist/oh-stack.js +18 -20
  112. package/dist/oh-stack.js.map +1 -1
  113. package/dist/oh-tabs.d.ts +55 -30
  114. package/dist/oh-tabs.d.ts.map +1 -1
  115. package/dist/oh-tabs.js +100 -76
  116. package/dist/oh-tabs.js.map +1 -1
  117. package/dist/oh-textarea.d.ts +129 -0
  118. package/dist/oh-textarea.d.ts.map +1 -0
  119. package/dist/oh-textarea.js +401 -0
  120. package/dist/oh-textarea.js.map +1 -0
  121. package/dist/oh-toggle.d.ts +45 -12
  122. package/dist/oh-toggle.d.ts.map +1 -1
  123. package/dist/oh-toggle.js +84 -34
  124. package/dist/oh-toggle.js.map +1 -1
  125. package/dist/styles/typography.js +1 -1
  126. package/package.json +7 -7
  127. package/dist/oh-hero.d.ts +0 -33
  128. package/dist/oh-hero.d.ts.map +0 -1
  129. package/dist/oh-hero.js +0 -246
  130. package/dist/oh-hero.js.map +0 -1
@@ -1,18 +1,18 @@
1
1
  /**
2
2
  * oh-radio-group
3
3
  *
4
- * A radio group with proper ARIA semantics and group-level error handling.
5
- * Individual radios cannot be used standalone.
4
+ * A radio group with ARIA group semantics and group-level error handling.
5
+ * Use it for every set of radios: separate oh-radio elements can't form a
6
+ * group, because each native radio is in its own shadow root.
6
7
  *
7
- * ACCESSIBILITY:
8
- * ─────────────
9
- * - role="radiogroup" with aria-labelledby
10
- * - Arrow key navigation between options
11
- * - Group-level error messaging
12
- * - Visible focus ring (outline, not inset)
13
- * - aria-required and aria-invalid
14
- *
15
- * @element oh-radio-group
8
+ * DESIGN DECISIONS:
9
+ * ─────────────────
10
+ * - role="radiogroup" with aria-labelledby, aria-required and aria-invalid
11
+ * - Native radios sharing one name in one shadow root, so the browser
12
+ * handles arrow-key navigation between options
13
+ * - One error for the group, after the label and before the options
14
+ * - Focus underlines the option's label (a solid indicator)
15
+ * - The drawn circles use the same tokens as oh-radio
16
16
  */
17
17
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18
18
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -23,6 +23,44 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
23
23
  import { html, css, nothing } from "lit";
24
24
  import { customElement, property, state } from "lit/decorators.js";
25
25
  import { OhElement, baseStyles } from "./base.js";
26
+ /**
27
+ * A set of radio buttons under one label, where exactly one can be chosen.
28
+ *
29
+ * **Use it for** one choice from a few options that should all be visible,
30
+ * such as a plan or a delivery speed. **Don't use it for** a long list (use
31
+ * `oh-select`), several choices (use `oh-checkbox-group`) or an on/off
32
+ * setting (use `oh-toggle` or `oh-checkbox`). Use it rather than separate
33
+ * `oh-radio` elements, which can't form a group.
34
+ *
35
+ * **Parts:** a `label` for the group and a list of `options`
36
+ * (`{ label, value }`). `value` is the chosen option's value. **States:**
37
+ * each option unchecked, checked, hover, active and focus; the group can be
38
+ * `required` and in error (set `error-text`).
39
+ *
40
+ * **Behaviour:** Tab moves into and out of the group; arrow keys move
41
+ * between options and choose them (the browser's native radio behaviour).
42
+ * Each change sets `value` and fires `oh-change`. The native radios sit in
43
+ * the shadow root, so they don't submit with a native form: read `value` or
44
+ * listen for `oh-change`. `required` sets `aria-required` and a marker on
45
+ * the label but doesn't validate; set the error yourself.
46
+ *
47
+ * **Accessibility:** `role="radiogroup"` labelled by `label`, so always set
48
+ * one. The error shows after the label and before the options, with an
49
+ * icon; the group gets `aria-invalid` and `aria-describedby`, and the error
50
+ * is announced (`role="alert"`) only when it appears after first render.
51
+ * Focus underlines the option's label.
52
+ *
53
+ * **Look:** set by tokens — the same as `oh-radio`: `stroke.control` in
54
+ * `color.border.emphasis` (border), `shape.pill` (circle),
55
+ * `elevation.offset.*` with `elevation.color.secondary` / `elevation.color.primary` (shadow),
56
+ * `lift.hoverSm` / `lift.pressSm` (movement on hover and press),
57
+ * `color.brand.primary` and `color.text.onBrand` (checked),
58
+ * `color.feedback.error` and `elevation.color.error` (error); `typography.control.*`
59
+ * for the group label and option labels.
60
+ *
61
+ * @element oh-radio-group
62
+ * @fires oh-change - An option was chosen. detail: { value }
63
+ */
26
64
  let OhRadioGroup = class OhRadioGroup extends OhElement {
27
65
  constructor() {
28
66
  super(...arguments);
@@ -31,8 +69,11 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
31
69
  this.options = [];
32
70
  this.value = "";
33
71
  this.required = false;
34
- this.error = false;
35
- this.errorMessage = "";
72
+ /**
73
+ * Error shown with the control and linked to it. Setting it puts the
74
+ * control in its error state; clear it to leave that state.
75
+ */
76
+ this.errorText = "";
36
77
  this._labelId = `radio-group-label-${Math.random().toString(36).substr(2, 9)}`;
37
78
  this._focusedValue = null;
38
79
  /**
@@ -105,16 +146,17 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
105
146
  border: var(--oh-stroke-control) solid var(--oh-color-border-emphasis);
106
147
  border-radius: var(--oh-shape-pill);
107
148
  background-color: var(--oh-color-surface-base);
108
- box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md) 0 0 var(--oh-shadow-secondary);
109
- transition:
110
- transform var(--oh-motion-snappy) var(--oh-motion-ease-playful),
111
- box-shadow var(--oh-motion-snappy) var(--oh-motion-ease-playful),
149
+ box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md)
150
+ 0 0 var(--oh-elevation-color-secondary);
151
+ transition:
152
+ transform var(--oh-motion-snappy) var(--oh-motion-ease-emphasized),
153
+ box-shadow var(--oh-motion-snappy) var(--oh-motion-ease-emphasized),
112
154
  background-color var(--oh-motion-quick) ease,
113
155
  border-color var(--oh-motion-quick) ease;
114
156
  }
115
157
 
116
158
  .radio-circle::after {
117
- content: '';
159
+ content: "";
118
160
  position: absolute;
119
161
  top: 50%;
120
162
  left: 50%;
@@ -123,7 +165,8 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
123
165
  background-color: var(--oh-color-text-on-brand);
124
166
  border-radius: var(--oh-shape-pill);
125
167
  transform: translate(-50%, -50%) scale(0);
126
- transition: transform var(--oh-motion-snappy) var(--oh-motion-ease-playful);
168
+ transition: transform var(--oh-motion-snappy)
169
+ var(--oh-motion-ease-emphasized);
127
170
  }
128
171
 
129
172
  .option-label {
@@ -138,24 +181,27 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
138
181
  STATES
139
182
  ═══════════════════════════════════════════════════════════════ */
140
183
 
141
- /* Hover: lift up-left, shadow grows */
184
+ /* Hover: moves by lift.hoverSm; shadow offset elevation.offset.lg */
142
185
  .radio-option:hover .radio-circle {
143
186
  border-color: var(--oh-color-border-hover);
144
187
  transform: translate(var(--oh-lift-hover-sm), var(--oh-lift-hover-sm));
145
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-secondary);
188
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
189
+ 0 0 var(--oh-elevation-color-secondary);
146
190
  }
147
191
 
148
- /* Active: press down-right, shadow shrinks */
192
+ /* Active: moves by lift.pressSm; shadow offset elevation.offset.xs */
149
193
  .radio-option:active .radio-circle {
150
194
  transform: translate(var(--oh-lift-press-sm), var(--oh-lift-press-sm));
151
- box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs) 0 0 var(--oh-shadow-secondary);
195
+ box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs)
196
+ 0 0 var(--oh-elevation-color-secondary);
152
197
  }
153
198
 
154
- /* Checked: primary color with warm shadow */
199
+ /* Checked: color.brand.primary fill, elevation.color.primary shadow */
155
200
  .native-radio:checked + .radio-circle {
156
201
  background-color: var(--oh-color-brand-primary);
157
202
  border-color: var(--oh-color-brand-primary);
158
- box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md) 0 0 var(--oh-shadow-primary);
203
+ box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md)
204
+ 0 0 var(--oh-elevation-color-primary);
159
205
  }
160
206
 
161
207
  .native-radio:checked + .radio-circle::after {
@@ -167,14 +213,16 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
167
213
  background-color: var(--oh-color-brand-primary-hover);
168
214
  border-color: var(--oh-color-brand-primary-hover);
169
215
  transform: translate(var(--oh-lift-hover-sm), var(--oh-lift-hover-sm));
170
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-primary);
216
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
217
+ 0 0 var(--oh-elevation-color-primary);
171
218
  }
172
219
 
173
220
  /* Checked + Active */
174
221
  .radio-option:active .native-radio:checked + .radio-circle {
175
222
  background-color: var(--oh-color-brand-primary-active);
176
223
  transform: translate(var(--oh-lift-press-sm), var(--oh-lift-press-sm));
177
- box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs) 0 0 var(--oh-shadow-primary);
224
+ box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs)
225
+ 0 0 var(--oh-elevation-color-primary);
178
226
  }
179
227
 
180
228
  /* Focus: underline the label (accessible indicator) */
@@ -193,14 +241,16 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
193
241
  ERROR STATE
194
242
  ═══════════════════════════════════════════════════════════════ */
195
243
 
196
- :host([error]) .radio-circle {
244
+ :host([data-invalid]) .radio-circle {
197
245
  border-color: var(--oh-color-feedback-error);
198
- box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md) 0 0 var(--oh-shadow-error);
246
+ box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md)
247
+ 0 0 var(--oh-elevation-color-error);
199
248
  }
200
249
 
201
- :host([error]) .radio-option:hover .radio-circle {
250
+ :host([data-invalid]) .radio-option:hover .radio-circle {
202
251
  border-color: var(--oh-color-feedback-error-hover);
203
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-error);
252
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
253
+ 0 0 var(--oh-elevation-color-error);
204
254
  }
205
255
 
206
256
  .error-message {
@@ -242,9 +292,14 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
242
292
  _handleBlur() {
243
293
  this._focusedValue = null;
244
294
  }
295
+ updated(changed) {
296
+ // Styling hook for the error state (data-invalid on the host)
297
+ if (changed.has("errorText"))
298
+ this.toggleAttribute("data-invalid", !!this.errorText);
299
+ }
245
300
  willUpdate(changed) {
246
- if (this.hasUpdated && (changed.has("error") || changed.has("errorMessage"))) {
247
- this._announceError = !!(this.error && this.errorMessage);
301
+ if (this.hasUpdated && changed.has("errorText")) {
302
+ this._announceError = !!this.errorText;
248
303
  }
249
304
  }
250
305
  render() {
@@ -252,33 +307,47 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
252
307
  <div>
253
308
  ${this.label
254
309
  ? html `
255
- <span
256
- id=${this._labelId}
257
- class="group-label ${this.required ? "group-label--required" : ""}"
310
+ <span
311
+ id=${this._labelId}
312
+ class="group-label ${this.required
313
+ ? "group-label--required"
314
+ : ""}"
258
315
  >
259
316
  ${this.label}
260
317
  </span>
261
318
  `
262
319
  : nothing}
263
-
264
- ${this.error && this.errorMessage
320
+ ${this.errorText
265
321
  ? html `
266
- <div id="error-msg" class="error-message" role=${this._announceError ? "alert" : nothing}>
267
- <svg class="error-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
268
- <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
322
+ <div
323
+ id="error-msg"
324
+ class="error-message"
325
+ role=${this._announceError ? "alert" : nothing}
326
+ >
327
+ <svg
328
+ class="error-icon"
329
+ viewBox="0 0 20 20"
330
+ fill="currentColor"
331
+ aria-hidden="true"
332
+ >
333
+ <path
334
+ fill-rule="evenodd"
335
+ d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z"
336
+ clip-rule="evenodd"
337
+ />
269
338
  </svg>
270
- ${this.errorMessage}
339
+ ${this.errorText}
271
340
  </div>
272
341
  `
273
342
  : nothing}
274
-
343
+
275
344
  <div
276
345
  class="radio-group"
277
346
  role="radiogroup"
278
347
  aria-labelledby=${this.label ? this._labelId : nothing}
279
348
  aria-required=${this.required ? "true" : nothing}
280
- aria-invalid=${this.error ? "true" : nothing}
281
- aria-describedby=${this.error && this.errorMessage ? "error-msg" : nothing}
349
+ aria-invalid=${this.errorText ? "true" : nothing}
350
+ aria-describedby=${this.errorText ? "error-msg" : nothing}
282
351
  >
283
352
  ${this.options.map((option) => html `
284
353
  <label class="radio-option">
@@ -293,7 +362,12 @@ let OhRadioGroup = class OhRadioGroup extends OhElement {
293
362
  @blur=${this._handleBlur}
294
363
  />
295
364
  <span class="radio-circle"></span>
296
- <span class="option-label ${this._focusedValue === option.value ? 'option-label--focused' : ''}">${option.label}</span>
365
+ <span
366
+ class="option-label ${this._focusedValue === option.value
367
+ ? "option-label--focused"
368
+ : ""}"
369
+ >${option.label}</span
370
+ >
297
371
  </label>
298
372
  `)}
299
373
  </div>
@@ -317,11 +391,8 @@ __decorate([
317
391
  property({ type: Boolean, reflect: true })
318
392
  ], OhRadioGroup.prototype, "required", void 0);
319
393
  __decorate([
320
- property({ type: Boolean, reflect: true })
321
- ], OhRadioGroup.prototype, "error", void 0);
322
- __decorate([
323
- property({ type: String })
324
- ], OhRadioGroup.prototype, "errorMessage", void 0);
394
+ property({ type: String, attribute: "error-text" })
395
+ ], OhRadioGroup.prototype, "errorText", void 0);
325
396
  __decorate([
326
397
  state()
327
398
  ], OhRadioGroup.prototype, "_labelId", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"oh-radio-group.js","sourceRoot":"","sources":["../src/oh-radio-group.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oh-radio-group.js","sourceRoot":"","sources":["../src/oh-radio-group.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;;;;;;;AAEH,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAuB,MAAM,KAAK,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAOlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,SAAS;IAApC;;QAyML,UAAK,GAAG,EAAE,CAAC;QAGX,SAAI,GAAG,EAAE,CAAC;QAGV,YAAO,GAAkB,EAAE,CAAC;QAG5B,UAAK,GAAG,EAAE,CAAC;QAGX,aAAQ,GAAG,KAAK,CAAC;QAEjB;;;WAGG;QAEH,cAAS,GAAG,EAAE,CAAC;QAGP,aAAQ,GACd,qBAAqB,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAGzD,kBAAa,GAAkB,IAAI,CAAC;QAgB5C;;;;WAIG;QAEK,mBAAc,GAAG,KAAK,CAAC;IAwFjC,CAAC;aAhViB,WAAM,GAAG;QACvB,UAAU;QACV,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkMF;KACF,AArMqB,CAqMpB;IA+BM,aAAa,CAAC,KAAY;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAA0B,CAAC;QAChD,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAChD,CAAC;IAEO,YAAY,CAAC,KAAa;QAChC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IAC7B,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;IAUD,OAAO,CAAC,OAAuB;QAC7B,8DAA8D;QAC9D,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;YAC1B,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3D,CAAC;IAED,UAAU,CAAC,OAAuB;QAChC,IAAI,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;QACzC,CAAC;IACH,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAA;;UAEL,IAAI,CAAC,KAAK;YACV,CAAC,CAAC,IAAI,CAAA;;qBAEK,IAAI,CAAC,QAAQ;qCACG,IAAI,CAAC,QAAQ;gBAChC,CAAC,CAAC,uBAAuB;gBACzB,CAAC,CAAC,EAAE;;kBAEJ,IAAI,CAAC,KAAK;;aAEf;YACH,CAAC,CAAC,OAAO;UACT,IAAI,CAAC,SAAS;YACd,CAAC,CAAC,IAAI,CAAA;;;;uBAIO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;;;;;;;;;;;;;;kBAc5C,IAAI,CAAC,SAAS;;aAEnB;YACH,CAAC,CAAC,OAAO;;;;;4BAKS,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;0BACtC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;yBACjC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;6BAC7B,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO;;YAEvD,IAAI,CAAC,OAAO,CAAC,GAAG,CAChB,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAA;;;;;yBAKH,IAAI,CAAC,IAAI;2BACP,MAAM,CAAC,KAAK;6BACV,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;4BAC5B,IAAI,CAAC,aAAa;2BACnB,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC;0BACtC,IAAI,CAAC,WAAW;;;;wCAIF,IAAI,CAAC,aAAa,KAAK,MAAM,CAAC,KAAK;YACvD,CAAC,CAAC,uBAAuB;YACzB,CAAC,CAAC,EAAE;qBACH,MAAM,CAAC,KAAK;;;aAGpB,CACF;;;KAGN,CAAC;IACJ,CAAC;;AAvID;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CAChB;AAGX;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CACjB;AAGV;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;6CACE;AAG5B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CAChB;AAGX;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAC1B;AAOjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;+CACrC;AAGP;IADP,KAAK,EAAE;8CAEyD;AAGzD;IADP,KAAK,EAAE;mDACoC;AAsBpC;IADP,KAAK,EAAE;oDACuB;AAzPpB,YAAY;IADxB,aAAa,CAAC,gBAAgB,CAAC;GACnB,YAAY,CAiVxB"}
@@ -1,40 +1,77 @@
1
1
  /**
2
2
  * oh-radio
3
3
  *
4
- * A chunky, playful radio button with hand-crafted feel.
5
- * Matches the inset/pressed aesthetic of oh-input.
6
- *
7
4
  * DESIGN DECISIONS:
8
5
  * ─────────────────
9
- * 1. CHUNKY & TACTILE
10
- * - Thick border (stroke.control)
11
- * - Inset shadow when unchecked (pressed into page)
12
- * - Fully circular (radio = circle)
6
+ * 1. LOOK FROM TOKENS
7
+ * - Border: stroke.control in color.border.emphasis
8
+ * - Circular: shape.pill
9
+ * - Shadow: offset by elevation.offset.* in elevation.color.secondary; hover and
10
+ * press move the circle by lift.hoverSm / lift.pressSm
13
11
  *
14
12
  * 2. CHECKED STATE
15
- * - Filled dot in center
16
- * - Primary color ring
17
- * - Shadow shifts to feel "activated"
13
+ * - Filled with color.brand.primary, a centre dot in color.text.onBrand,
14
+ * and the shadow in elevation.color.primary
18
15
  *
19
16
  * 3. ACCESSIBILITY
20
- * - Native radio hidden but accessible
17
+ * - A native radio, visually hidden but focusable and announced
21
18
  * - Label always required
22
- * - Focus ring matches input
23
- * - Works in radio groups via name attribute
24
- *
25
- * @element oh-radio
19
+ * - Focus underlines the label (a solid indicator)
20
+ * - Two oh-radios with the same name don't form a group (each native
21
+ * radio is in its own shadow root): use oh-radio-group for a set
26
22
  */
27
23
  import { type PropertyValues } from "lit";
28
24
  import { OhElement } from "./base.js";
29
25
  export type RadioState = "default" | "hover" | "focus";
26
+ /**
27
+ * A single radio button with its label.
28
+ *
29
+ * **Use it for** a one-off radio you manage yourself. **For a set of
30
+ * choices, use `oh-radio-group`.** Each `oh-radio` keeps its native radio
31
+ * inside its own shadow root, so two of them with the same `name` don't form
32
+ * a group: checking one doesn't uncheck the other, and arrow keys don't move
33
+ * between them. `oh-radio-group` renders the whole set in one place, with
34
+ * arrow-key navigation and one label for the group. For an independent
35
+ * on/off choice use `oh-checkbox`.
36
+ *
37
+ * **States:** unchecked, checked, hover, active, focus, error (set `error-text`).
38
+ *
39
+ * **Behaviour:** clicking the circle or label checks it. Checking sets
40
+ * `checked` and fires `oh-change`. The native radio sits in the shadow
41
+ * root, so it doesn't submit with a native form.
42
+ *
43
+ * **Accessibility:** a real native radio, visually hidden, carries the role
44
+ * and state; the drawn circle is decoration. Always set `label`: it's the
45
+ * radio's name. Focus underlines the label. The error message shows under
46
+ * the radio with an icon, sets `aria-invalid` and is linked with
47
+ * `aria-describedby`; it's announced (`role="alert"`) only when it appears
48
+ * after first render.
49
+ *
50
+ * **Look:** set by tokens — `stroke.control` in `color.border.emphasis`
51
+ * (border), `shape.pill` (circle), `typography.control.*` (label),
52
+ * `elevation.offset.*` and `elevation.color.secondary` (shadow), `lift.hoverSm` /
53
+ * `lift.pressSm` (movement on hover and press), `color.border.hover`
54
+ * (hover), `color.brand.primary` (and its hover and active tokens),
55
+ * `color.text.onBrand` and `elevation.color.primary` (checked),
56
+ * `color.feedback.error` and `elevation.color.error` (error).
57
+ *
58
+ * @element oh-radio
59
+ * @fires oh-change - The radio was checked. detail: { checked, value }
60
+ * @csspart circle - The drawn radio circle
61
+ * @csspart label - The label text
62
+ * @csspart error - The error message
63
+ */
30
64
  export declare class OhRadio extends OhElement {
31
65
  static styles: import("lit").CSSResult[];
32
66
  checked: boolean;
33
67
  label: string;
34
68
  name: string;
35
69
  value: string;
36
- error: boolean;
37
- errorMessage: string;
70
+ /**
71
+ * Error shown with the control and linked to it. Setting it puts the
72
+ * control in its error state; clear it to leave that state.
73
+ */
74
+ errorText: string;
38
75
  /**
39
76
  * Force a visual state (for documentation/Figma sync only)
40
77
  * Values: 'hover' | 'focus'
@@ -48,6 +85,7 @@ export declare class OhRadio extends OhElement {
48
85
  */
49
86
  private _announceError;
50
87
  private _errorId;
88
+ updated(changed: PropertyValues): void;
51
89
  willUpdate(changed: PropertyValues): void;
52
90
  render(): import("lit").TemplateResult<1>;
53
91
  }
@@ -1 +1 @@
1
- {"version":3,"file":"oh-radio.d.ts","sourceRoot":"","sources":["../src/oh-radio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEvD,qBACa,OAAQ,SAAQ,SAAS;IACpC,OAAgB,MAAM,4BAwMpB;IAGF,OAAO,UAAS;IAGhB,KAAK,SAAM;IAGX,IAAI,SAAM;IAGV,KAAK,SAAM;IAGX,KAAK,UAAS;IAGd,YAAY,SAAM;IAElB;;;OAGG;IAEH,UAAU,EAAE,UAAU,CAAa;IAEnC,OAAO,CAAC,aAAa;IAMrB;;;;OAIG;IAEH,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,QAAQ,CAA+D;IAE/E,UAAU,CAAC,OAAO,EAAE,cAAc;IAMlC,MAAM;CAiCP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,OAAO,CAAC;KACrB;CACF"}
1
+ {"version":3,"file":"oh-radio.d.ts","sourceRoot":"","sources":["../src/oh-radio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBACa,OAAQ,SAAQ,SAAS;IACpC,OAAgB,MAAM,4BA8MpB;IAGF,OAAO,UAAS;IAGhB,KAAK,SAAM;IAGX,IAAI,SAAM;IAGV,KAAK,SAAM;IAEX;;;OAGG;IAEH,SAAS,SAAM;IAEf;;;OAGG;IAEH,UAAU,EAAE,UAAU,CAAa;IAEnC,OAAO,CAAC,aAAa;IAMrB;;;;OAIG;IAEH,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,QAAQ,CAA+D;IAE/E,OAAO,CAAC,OAAO,EAAE,cAAc;IAM/B,UAAU,CAAC,OAAO,EAAE,cAAc;IAMlC,MAAM;CA+CP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,UAAU,EAAE,OAAO,CAAC;KACrB;CACF"}