@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
package/dist/oh-radio.js CHANGED
@@ -1,28 +1,24 @@
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
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
28
24
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -33,6 +29,44 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
33
29
  import { html, css, nothing } from "lit";
34
30
  import { customElement, property, state } from "lit/decorators.js";
35
31
  import { OhElement, baseStyles } from "./base.js";
32
+ /**
33
+ * A single radio button with its label.
34
+ *
35
+ * **Use it for** a one-off radio you manage yourself. **For a set of
36
+ * choices, use `oh-radio-group`.** Each `oh-radio` keeps its native radio
37
+ * inside its own shadow root, so two of them with the same `name` don't form
38
+ * a group: checking one doesn't uncheck the other, and arrow keys don't move
39
+ * between them. `oh-radio-group` renders the whole set in one place, with
40
+ * arrow-key navigation and one label for the group. For an independent
41
+ * on/off choice use `oh-checkbox`.
42
+ *
43
+ * **States:** unchecked, checked, hover, active, focus, error (set `error-text`).
44
+ *
45
+ * **Behaviour:** clicking the circle or label checks it. Checking sets
46
+ * `checked` and fires `oh-change`. The native radio sits in the shadow
47
+ * root, so it doesn't submit with a native form.
48
+ *
49
+ * **Accessibility:** a real native radio, visually hidden, carries the role
50
+ * and state; the drawn circle is decoration. Always set `label`: it's the
51
+ * radio's name. Focus underlines the label. The error message shows under
52
+ * the radio with an icon, sets `aria-invalid` and is linked with
53
+ * `aria-describedby`; it's announced (`role="alert"`) only when it appears
54
+ * after first render.
55
+ *
56
+ * **Look:** set by tokens — `stroke.control` in `color.border.emphasis`
57
+ * (border), `shape.pill` (circle), `typography.control.*` (label),
58
+ * `elevation.offset.*` and `elevation.color.secondary` (shadow), `lift.hoverSm` /
59
+ * `lift.pressSm` (movement on hover and press), `color.border.hover`
60
+ * (hover), `color.brand.primary` (and its hover and active tokens),
61
+ * `color.text.onBrand` and `elevation.color.primary` (checked),
62
+ * `color.feedback.error` and `elevation.color.error` (error).
63
+ *
64
+ * @element oh-radio
65
+ * @fires oh-change - The radio was checked. detail: { checked, value }
66
+ * @csspart circle - The drawn radio circle
67
+ * @csspart label - The label text
68
+ * @csspart error - The error message
69
+ */
36
70
  let OhRadio = class OhRadio extends OhElement {
37
71
  constructor() {
38
72
  super(...arguments);
@@ -40,8 +74,11 @@ let OhRadio = class OhRadio extends OhElement {
40
74
  this.label = "";
41
75
  this.name = "";
42
76
  this.value = "";
43
- this.error = false;
44
- this.errorMessage = "";
77
+ /**
78
+ * Error shown with the control and linked to it. Setting it puts the
79
+ * control in its error state; clear it to leave that state.
80
+ */
81
+ this.errorText = "";
45
82
  /**
46
83
  * Force a visual state (for documentation/Figma sync only)
47
84
  * Values: 'hover' | 'focus'
@@ -58,11 +95,6 @@ let OhRadio = class OhRadio extends OhElement {
58
95
  static { this.styles = [
59
96
  baseStyles,
60
97
  css `
61
- /* ═══════════════════════════════════════════════════════════════
62
- ORANGE HALO RADIO
63
- Chunky • Tactile • Playful
64
- ═══════════════════════════════════════════════════════════════ */
65
-
66
98
  :host {
67
99
  display: inline-block;
68
100
  }
@@ -96,25 +128,26 @@ let OhRadio = class OhRadio extends OhElement {
96
128
  width: 24px;
97
129
  height: 24px;
98
130
  flex-shrink: 0;
99
-
100
- /* Chunky border, fully circular */
131
+
132
+ /* Border: stroke.control in color.border.emphasis; circular (shape.pill) */
101
133
  border: var(--oh-stroke-control) solid var(--oh-color-border-emphasis);
102
134
  border-radius: var(--oh-shape-pill);
103
-
104
- /* Offset shadow like primary button */
135
+
136
+ /* Offset shadow: elevation.offset.md in elevation.color.secondary */
105
137
  background-color: var(--oh-color-surface-base);
106
- box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md) 0 0 var(--oh-shadow-secondary);
107
-
108
- transition:
109
- transform var(--oh-motion-snappy) var(--oh-motion-ease-playful),
110
- box-shadow var(--oh-motion-snappy) var(--oh-motion-ease-playful),
138
+ box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md)
139
+ 0 0 var(--oh-elevation-color-secondary);
140
+
141
+ transition:
142
+ transform var(--oh-motion-snappy) var(--oh-motion-ease-emphasized),
143
+ box-shadow var(--oh-motion-snappy) var(--oh-motion-ease-emphasized),
111
144
  background-color var(--oh-motion-quick) ease,
112
145
  border-color var(--oh-motion-quick) ease;
113
146
  }
114
147
 
115
148
  /* Inner dot (hidden by default) */
116
149
  .radio-circle::after {
117
- content: '';
150
+ content: "";
118
151
  position: absolute;
119
152
  top: 50%;
120
153
  left: 50%;
@@ -123,31 +156,35 @@ let OhRadio = class OhRadio extends OhElement {
123
156
  background-color: var(--oh-color-text-on-brand);
124
157
  border-radius: var(--oh-shape-pill);
125
158
  transform: translate(-50%, -50%) scale(0);
126
- transition: transform var(--oh-motion-snappy) var(--oh-motion-ease-playful);
159
+ transition: transform var(--oh-motion-snappy)
160
+ var(--oh-motion-ease-emphasized);
127
161
  }
128
162
 
129
163
  /* ═══════════════════════════════════════════════════════════════
130
164
  STATES
131
165
  ═══════════════════════════════════════════════════════════════ */
132
166
 
133
- /* Hover: lift up-left, shadow grows */
167
+ /* Hover: moves by lift.hoverSm; shadow offset elevation.offset.lg */
134
168
  .radio-wrapper:hover .radio-circle {
135
169
  border-color: var(--oh-color-border-hover);
136
170
  transform: translate(var(--oh-lift-hover-sm), var(--oh-lift-hover-sm));
137
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-secondary);
171
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
172
+ 0 0 var(--oh-elevation-color-secondary);
138
173
  }
139
174
 
140
- /* Active: press down-right, shadow shrinks */
175
+ /* Active: moves by lift.pressSm; shadow offset elevation.offset.xs */
141
176
  .radio-wrapper:active .radio-circle {
142
177
  transform: translate(var(--oh-lift-press-sm), var(--oh-lift-press-sm));
143
- box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs) 0 0 var(--oh-shadow-secondary);
178
+ box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs)
179
+ 0 0 var(--oh-elevation-color-secondary);
144
180
  }
145
181
 
146
- /* Checked: primary color with warm shadow */
182
+ /* Checked: color.brand.primary fill, elevation.color.primary shadow */
147
183
  .native-radio:checked + .radio-circle {
148
184
  background-color: var(--oh-color-brand-primary);
149
185
  border-color: var(--oh-color-brand-primary);
150
- box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md) 0 0 var(--oh-shadow-primary);
186
+ box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md)
187
+ 0 0 var(--oh-elevation-color-primary);
151
188
  }
152
189
 
153
190
  .native-radio:checked + .radio-circle::after {
@@ -159,14 +196,16 @@ let OhRadio = class OhRadio extends OhElement {
159
196
  background-color: var(--oh-color-brand-primary-hover);
160
197
  border-color: var(--oh-color-brand-primary-hover);
161
198
  transform: translate(var(--oh-lift-hover-sm), var(--oh-lift-hover-sm));
162
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-primary);
199
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
200
+ 0 0 var(--oh-elevation-color-primary);
163
201
  }
164
202
 
165
203
  /* Checked + Active */
166
204
  .radio-wrapper:active .native-radio:checked + .radio-circle {
167
205
  background-color: var(--oh-color-brand-primary-active);
168
206
  transform: translate(var(--oh-lift-press-sm), var(--oh-lift-press-sm));
169
- box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs) 0 0 var(--oh-shadow-primary);
207
+ box-shadow: var(--oh-elevation-offset-xs) var(--oh-elevation-offset-xs)
208
+ 0 0 var(--oh-elevation-color-primary);
170
209
  }
171
210
 
172
211
  /* Focus: underline the label (accessible indicator) */
@@ -192,14 +231,16 @@ let OhRadio = class OhRadio extends OhElement {
192
231
  ERROR STATE
193
232
  ═══════════════════════════════════════════════════════════════ */
194
233
 
195
- :host([error]) .radio-circle {
234
+ :host([data-invalid]) .radio-circle {
196
235
  border-color: var(--oh-color-feedback-error);
197
- box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md) 0 0 var(--oh-shadow-error);
236
+ box-shadow: var(--oh-elevation-offset-md) var(--oh-elevation-offset-md)
237
+ 0 0 var(--oh-elevation-color-error);
198
238
  }
199
239
 
200
- :host([error]) .radio-wrapper:hover .radio-circle {
240
+ :host([data-invalid]) .radio-wrapper:hover .radio-circle {
201
241
  border-color: var(--oh-color-feedback-error-hover);
202
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-error);
242
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
243
+ 0 0 var(--oh-elevation-color-error);
203
244
  }
204
245
 
205
246
  .error-message {
@@ -238,7 +279,8 @@ let OhRadio = class OhRadio extends OhElement {
238
279
  :host([force-state="hover"]) .radio-circle {
239
280
  border-color: var(--oh-color-border-hover);
240
281
  transform: translate(var(--oh-lift-hover-sm), var(--oh-lift-hover-sm));
241
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-secondary);
282
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
283
+ 0 0 var(--oh-elevation-color-secondary);
242
284
  }
243
285
 
244
286
  /* Forced Focus - Unchecked */
@@ -252,7 +294,8 @@ let OhRadio = class OhRadio extends OhElement {
252
294
  background-color: var(--oh-color-brand-primary-hover);
253
295
  border-color: var(--oh-color-brand-primary-hover);
254
296
  transform: translate(var(--oh-lift-hover-sm), var(--oh-lift-hover-sm));
255
- box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg) 0 0 var(--oh-shadow-primary);
297
+ box-shadow: var(--oh-elevation-offset-lg) var(--oh-elevation-offset-lg)
298
+ 0 0 var(--oh-elevation-color-primary);
256
299
  }
257
300
  `,
258
301
  ]; }
@@ -261,9 +304,14 @@ let OhRadio = class OhRadio extends OhElement {
261
304
  this.checked = target.checked;
262
305
  this.emit("oh-change", { checked: this.checked, value: this.value });
263
306
  }
307
+ updated(changed) {
308
+ // Styling hook for the error state (data-invalid on the host)
309
+ if (changed.has("errorText"))
310
+ this.toggleAttribute("data-invalid", !!this.errorText);
311
+ }
264
312
  willUpdate(changed) {
265
- if (this.hasUpdated && (changed.has("error") || changed.has("errorMessage"))) {
266
- this._announceError = !!(this.error && this.errorMessage);
313
+ if (this.hasUpdated && changed.has("errorText")) {
314
+ this._announceError = !!this.errorText;
267
315
  }
268
316
  }
269
317
  render() {
@@ -278,20 +326,34 @@ let OhRadio = class OhRadio extends OhElement {
278
326
  name=${this.name}
279
327
  .value=${this.value}
280
328
  .checked=${this.checked}
281
- aria-invalid=${this.error ? "true" : "false"}
282
- aria-describedby=${this.error && this.errorMessage ? this._errorId : nothing}
329
+ aria-invalid=${this.errorText ? "true" : "false"}
330
+ aria-describedby=${this.errorText ? this._errorId : nothing}
283
331
  @change=${this._handleChange}
284
332
  />
285
333
  <span class="radio-circle" part="circle"></span>
286
334
  <span class="label" part="label">${this.label}</span>
287
335
  </label>
288
- ${this.error && this.errorMessage
336
+ ${this.errorText
289
337
  ? html `
290
- <div id=${this._errorId} class="error-message" part="error" role=${this._announceError ? "alert" : nothing}>
291
- <svg class="error-icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
292
- <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" />
338
+ <div
339
+ id=${this._errorId}
340
+ class="error-message"
341
+ part="error"
342
+ role=${this._announceError ? "alert" : nothing}
343
+ >
344
+ <svg
345
+ class="error-icon"
346
+ viewBox="0 0 20 20"
347
+ fill="currentColor"
348
+ aria-hidden="true"
349
+ >
350
+ <path
351
+ fill-rule="evenodd"
352
+ 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"
353
+ clip-rule="evenodd"
354
+ />
293
355
  </svg>
294
- ${this.errorMessage}
356
+ ${this.errorText}
295
357
  </div>
296
358
  `
297
359
  : ""}
@@ -312,11 +374,8 @@ __decorate([
312
374
  property({ type: String })
313
375
  ], OhRadio.prototype, "value", void 0);
314
376
  __decorate([
315
- property({ type: Boolean, reflect: true })
316
- ], OhRadio.prototype, "error", void 0);
317
- __decorate([
318
- property({ type: String })
319
- ], OhRadio.prototype, "errorMessage", void 0);
377
+ property({ type: String, attribute: "error-text" })
378
+ ], OhRadio.prototype, "errorText", void 0);
320
379
  __decorate([
321
380
  property({ type: String, reflect: true, attribute: "force-state" })
322
381
  ], OhRadio.prototype, "forceState", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"oh-radio.js","sourceRoot":"","sources":["../src/oh-radio.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oh-radio.js","sourceRoot":"","sources":["../src/oh-radio.ts"],"names":[],"mappings":"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"}
@@ -1,31 +1,31 @@
1
1
  /**
2
2
  * oh-select
3
3
  *
4
- * A chunky, playful dropdown select with hand-crafted feel.
5
- * Custom-styled dropdown (not native) for full visual control.
4
+ * A custom dropdown select (not a native <select>), so the trigger and the
5
+ * list can be styled with tokens.
6
6
  *
7
7
  * DESIGN DECISIONS:
8
8
  * ─────────────────
9
- * 1. CHUNKY & TACTILE
10
- * - Thick border (stroke.control)
11
- * - Offset shadow (sticker effect like button)
12
- * - shape.control corners
13
- * - Solid warm fills
9
+ * 1. TRIGGER
10
+ * - A <button role="combobox">, with the same tokens as the other
11
+ * controls: stroke.control border in color.border.emphasis,
12
+ * shape.control corners, an outset shadow offset by
13
+ * elevation.offset.lg in elevation.color.secondary
14
+ * - Hover and press move it by lift.hoverMd / lift.pressSm, like oh-button
14
15
  *
15
16
  * 2. DROPDOWN PANEL
16
- * - Appears below trigger with shadow
17
- * - Options have hover/focus states
18
- * - Selected option highlighted
19
- * - Smooth open/close animation
17
+ * - A listbox below the trigger, on color.surface.highlight with
18
+ * shape.container corners
19
+ * - The highlighted option is underlined; the selected option is marked
20
+ * in color.brand.primary and set in typography.emphasis.fontWeight
21
+ * - Opens and closes with a transition (none under reduced motion)
20
22
  *
21
23
  * 3. ACCESSIBILITY
22
- * - role="combobox" with proper ARIA
23
- * - Keyboard navigation (arrows, enter, escape, home, end)
24
+ * - role="combobox" with aria-expanded, aria-controls and
25
+ * aria-activedescendant; focus stays on the trigger
26
+ * - Keyboard navigation (arrows, Enter, Space, Escape, Home, End, Tab)
24
27
  * - Type-ahead search
25
- * - Focus management
26
28
  * - Label always required
27
- *
28
- * @element oh-select
29
29
  */
30
30
  import { type PropertyValues } from "lit";
31
31
  import { OhElement } from "./base.js";
@@ -33,6 +33,48 @@ export interface SelectOption {
33
33
  label: string;
34
34
  value: string;
35
35
  }
36
+ /**
37
+ * A dropdown for choosing one option from a list.
38
+ *
39
+ * **Use it for** one choice from a list too long to show every option.
40
+ * **Don't use it for** a few options (use `oh-radio-group`, which shows them
41
+ * all), several choices (use `oh-checkbox-group`) or free text (use
42
+ * `oh-input` with `suggestions`).
43
+ *
44
+ * **Parts:** a trigger showing the selected option's label (or
45
+ * `placeholder`), and a list of `options` (`{ label, value }`). One size.
46
+ * **States:** rest, hover, active, focus, open, error (set `error-text`),
47
+ * required.
48
+ *
49
+ * **Behaviour:** click the trigger, or press Enter, Space or an arrow key,
50
+ * to open the list. Arrow keys, Home and End move the highlight, Enter or
51
+ * Space selects, Escape and Tab close, and clicking outside closes. Typing
52
+ * letters jumps to a matching option (and selects it while the list is
53
+ * closed). Selecting sets `value`, returns focus to the trigger and fires
54
+ * `oh-change`. It isn't form-associated: it doesn't submit with a native
55
+ * form, so read `value` or listen for `oh-change`. It has no `disabled`
56
+ * property.
57
+ *
58
+ * **Accessibility:** the trigger is a `combobox` controlling a `listbox`,
59
+ * with `aria-activedescendant` for the highlighted option, so focus stays
60
+ * on the trigger. Always set `label`: it names the trigger and the list.
61
+ * The error shows after the label and before the trigger, with an icon, sets
62
+ * `aria-invalid` and is linked with `aria-describedby`; it's announced
63
+ * (`role="alert"`) only when it appears after first render. Focus is a
64
+ * solid underline on the trigger text.
65
+ *
66
+ * **Look:** set by tokens — `stroke.control` in `color.border.emphasis`
67
+ * (border), `shape.control` (trigger corners), `shape.container` (list
68
+ * corners), `typography.control.*` (type), `elevation.offset.*` and
69
+ * `elevation.color.secondary` (shadow), `lift.hoverMd` / `lift.pressSm` (movement
70
+ * on hover and press), `color.border.hover` (hover), `focus.ringColor` and
71
+ * `color.surface.highlight` (open), `color.surface.hover` and
72
+ * `color.brand.primary` (selected option), `color.feedback.error` and
73
+ * `elevation.color.error` (error).
74
+ *
75
+ * @element oh-select
76
+ * @fires oh-change - An option was selected. detail: { value }
77
+ */
36
78
  export declare class OhSelect extends OhElement {
37
79
  static styles: import("lit").CSSResult[];
38
80
  label: string;
@@ -51,6 +93,7 @@ export declare class OhSelect extends OhElement {
51
93
  private _labelId;
52
94
  private _listboxId;
53
95
  private _errorId;
96
+ private _helperId;
54
97
  private _typeaheadBuffer;
55
98
  private _typeaheadTimeout;
56
99
  private get _selectedOption();
@@ -1 +1 @@
1
- {"version":3,"file":"oh-select.d.ts","sourceRoot":"","sources":["../src/oh-select.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBACa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,4BAoQpB;IAGF,KAAK,SAAM;IAGX,WAAW,SAAsB;IAGjC,IAAI,SAAM;IAGV,OAAO,EAAE,YAAY,EAAE,CAAM;IAG7B,KAAK,SAAM;IAGX,QAAQ,UAAS;IAGjB,UAAU,SAAM;IAGhB,SAAS,SAAM;IAGf,OAAO,CAAC,KAAK,CAAS;IAGtB,OAAO,CAAC,iBAAiB,CAAM;IAG/B,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,QAAQ,CAAqB;IAGrC,OAAO,CAAC,QAAQ,CAAoB;IAEpC,OAAO,CAAC,QAAQ,CAAgE;IAChF,OAAO,CAAC,UAAU,CAAkE;IACpF,OAAO,CAAC,QAAQ,CAAgE;IAChF,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAuB;IAEhD,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,qBAAqB;IAqE7B,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,mBAAmB,CAIzB;IAEO,iBAAiB;IAKjB,oBAAoB;IAK7B;;;;OAIG;IAEH,OAAO,CAAC,cAAc,CAAS;IAE/B,UAAU,CAAC,OAAO,EAAE,cAAc;IAMlC,MAAM;CAyGP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
1
+ {"version":3,"file":"oh-select.d.ts","sourceRoot":"","sources":["../src/oh-select.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBACa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,4BAqQpB;IAGF,KAAK,SAAM;IAGX,WAAW,SAAsB;IAGjC,IAAI,SAAM;IAGV,OAAO,EAAE,YAAY,EAAE,CAAM;IAG7B,KAAK,SAAM;IAGX,QAAQ,UAAS;IAGjB,UAAU,SAAM;IAGhB,SAAS,SAAM;IAGf,OAAO,CAAC,KAAK,CAAS;IAGtB,OAAO,CAAC,iBAAiB,CAAM;IAG/B,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,QAAQ,CAAqB;IAGrC,OAAO,CAAC,QAAQ,CAAoB;IAEpC,OAAO,CAAC,QAAQ,CAAgE;IAChF,OAAO,CAAC,UAAU,CAAkE;IACpF,OAAO,CAAC,QAAQ,CAAgE;IAChF,OAAO,CAAC,SAAS,CAAiE;IAClF,OAAO,CAAC,gBAAgB,CAAM;IAC9B,OAAO,CAAC,iBAAiB,CAAuB;IAEhD,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,qBAAqB;IAqE7B,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,mBAAmB,CAIzB;IAEO,iBAAiB;IAKjB,oBAAoB;IAK7B;;;;OAIG;IAEH,OAAO,CAAC,cAAc,CAAS;IAE/B,UAAU,CAAC,OAAO,EAAE,cAAc;IAMlC,MAAM;CAoIP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}