@orange-halo/components 1.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 (138) hide show
  1. package/custom-elements.json +186 -0
  2. package/dist/base.d.ts +30 -0
  3. package/dist/base.d.ts.map +1 -0
  4. package/dist/base.js +78 -0
  5. package/dist/base.js.map +1 -0
  6. package/dist/index.d.ts +83 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +72 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/oh-accordion.d.ts +47 -0
  11. package/dist/oh-accordion.d.ts.map +1 -0
  12. package/dist/oh-accordion.js +387 -0
  13. package/dist/oh-accordion.js.map +1 -0
  14. package/dist/oh-alert.d.ts +48 -0
  15. package/dist/oh-alert.d.ts.map +1 -0
  16. package/dist/oh-alert.js +343 -0
  17. package/dist/oh-alert.js.map +1 -0
  18. package/dist/oh-badge.d.ts +38 -0
  19. package/dist/oh-badge.d.ts.map +1 -0
  20. package/dist/oh-badge.js +176 -0
  21. package/dist/oh-badge.js.map +1 -0
  22. package/dist/oh-breadcrumb.d.ts +39 -0
  23. package/dist/oh-breadcrumb.d.ts.map +1 -0
  24. package/dist/oh-breadcrumb.js +277 -0
  25. package/dist/oh-breadcrumb.js.map +1 -0
  26. package/dist/oh-button.d.ts +62 -0
  27. package/dist/oh-button.d.ts.map +1 -0
  28. package/dist/oh-button.figma.d.ts +2 -0
  29. package/dist/oh-button.figma.d.ts.map +1 -0
  30. package/dist/oh-button.figma.js +20 -0
  31. package/dist/oh-button.figma.js.map +1 -0
  32. package/dist/oh-button.js +490 -0
  33. package/dist/oh-button.js.map +1 -0
  34. package/dist/oh-card.d.ts +44 -0
  35. package/dist/oh-card.d.ts.map +1 -0
  36. package/dist/oh-card.js +340 -0
  37. package/dist/oh-card.js.map +1 -0
  38. package/dist/oh-checkbox-group.d.ts +39 -0
  39. package/dist/oh-checkbox-group.d.ts.map +1 -0
  40. package/dist/oh-checkbox-group.figma.d.ts +2 -0
  41. package/dist/oh-checkbox-group.figma.d.ts.map +1 -0
  42. package/dist/oh-checkbox-group.figma.js +24 -0
  43. package/dist/oh-checkbox-group.figma.js.map +1 -0
  44. package/dist/oh-checkbox-group.js +309 -0
  45. package/dist/oh-checkbox-group.js.map +1 -0
  46. package/dist/oh-checkbox.d.ts +50 -0
  47. package/dist/oh-checkbox.d.ts.map +1 -0
  48. package/dist/oh-checkbox.js +315 -0
  49. package/dist/oh-checkbox.js.map +1 -0
  50. package/dist/oh-cluster.d.ts +38 -0
  51. package/dist/oh-cluster.d.ts.map +1 -0
  52. package/dist/oh-cluster.js +141 -0
  53. package/dist/oh-cluster.js.map +1 -0
  54. package/dist/oh-container.d.ts +38 -0
  55. package/dist/oh-container.d.ts.map +1 -0
  56. package/dist/oh-container.js +116 -0
  57. package/dist/oh-container.js.map +1 -0
  58. package/dist/oh-drawer.d.ts +66 -0
  59. package/dist/oh-drawer.d.ts.map +1 -0
  60. package/dist/oh-drawer.js +284 -0
  61. package/dist/oh-drawer.js.map +1 -0
  62. package/dist/oh-footer.d.ts +40 -0
  63. package/dist/oh-footer.d.ts.map +1 -0
  64. package/dist/oh-footer.js +112 -0
  65. package/dist/oh-footer.js.map +1 -0
  66. package/dist/oh-grid.d.ts +40 -0
  67. package/dist/oh-grid.d.ts.map +1 -0
  68. package/dist/oh-grid.js +168 -0
  69. package/dist/oh-grid.js.map +1 -0
  70. package/dist/oh-hero.d.ts +28 -0
  71. package/dist/oh-hero.d.ts.map +1 -0
  72. package/dist/oh-hero.js +242 -0
  73. package/dist/oh-hero.js.map +1 -0
  74. package/dist/oh-icon.d.ts +44 -0
  75. package/dist/oh-icon.d.ts.map +1 -0
  76. package/dist/oh-icon.js +321 -0
  77. package/dist/oh-icon.js.map +1 -0
  78. package/dist/oh-input.d.ts +56 -0
  79. package/dist/oh-input.d.ts.map +1 -0
  80. package/dist/oh-input.figma.d.ts +2 -0
  81. package/dist/oh-input.figma.d.ts.map +1 -0
  82. package/dist/oh-input.figma.js +36 -0
  83. package/dist/oh-input.figma.js.map +1 -0
  84. package/dist/oh-input.js +320 -0
  85. package/dist/oh-input.js.map +1 -0
  86. package/dist/oh-link.d.ts +45 -0
  87. package/dist/oh-link.d.ts.map +1 -0
  88. package/dist/oh-link.js +392 -0
  89. package/dist/oh-link.js.map +1 -0
  90. package/dist/oh-modal.d.ts +54 -0
  91. package/dist/oh-modal.d.ts.map +1 -0
  92. package/dist/oh-modal.js +450 -0
  93. package/dist/oh-modal.js.map +1 -0
  94. package/dist/oh-navbar.d.ts +49 -0
  95. package/dist/oh-navbar.d.ts.map +1 -0
  96. package/dist/oh-navbar.js +185 -0
  97. package/dist/oh-navbar.js.map +1 -0
  98. package/dist/oh-progress.d.ts +56 -0
  99. package/dist/oh-progress.d.ts.map +1 -0
  100. package/dist/oh-progress.js +299 -0
  101. package/dist/oh-progress.js.map +1 -0
  102. package/dist/oh-radio-group.d.ts +43 -0
  103. package/dist/oh-radio-group.d.ts.map +1 -0
  104. package/dist/oh-radio-group.figma.d.ts +2 -0
  105. package/dist/oh-radio-group.figma.d.ts.map +1 -0
  106. package/dist/oh-radio-group.figma.js +22 -0
  107. package/dist/oh-radio-group.figma.js.map +1 -0
  108. package/dist/oh-radio-group.js +324 -0
  109. package/dist/oh-radio-group.js.map +1 -0
  110. package/dist/oh-radio.d.ts +50 -0
  111. package/dist/oh-radio.d.ts.map +1 -0
  112. package/dist/oh-radio.js +314 -0
  113. package/dist/oh-radio.js.map +1 -0
  114. package/dist/oh-select.d.ts +82 -0
  115. package/dist/oh-select.d.ts.map +1 -0
  116. package/dist/oh-select.js +638 -0
  117. package/dist/oh-select.js.map +1 -0
  118. package/dist/oh-skip-link.d.ts +37 -0
  119. package/dist/oh-skip-link.d.ts.map +1 -0
  120. package/dist/oh-skip-link.js +145 -0
  121. package/dist/oh-skip-link.js.map +1 -0
  122. package/dist/oh-stack.d.ts +36 -0
  123. package/dist/oh-stack.d.ts.map +1 -0
  124. package/dist/oh-stack.js +112 -0
  125. package/dist/oh-stack.js.map +1 -0
  126. package/dist/oh-tabs.d.ts +85 -0
  127. package/dist/oh-tabs.d.ts.map +1 -0
  128. package/dist/oh-tabs.js +417 -0
  129. package/dist/oh-tabs.js.map +1 -0
  130. package/dist/oh-toggle.d.ts +51 -0
  131. package/dist/oh-toggle.d.ts.map +1 -0
  132. package/dist/oh-toggle.js +219 -0
  133. package/dist/oh-toggle.js.map +1 -0
  134. package/dist/styles/typography.d.ts +15 -0
  135. package/dist/styles/typography.d.ts.map +1 -0
  136. package/dist/styles/typography.js +235 -0
  137. package/dist/styles/typography.js.map +1 -0
  138. package/package.json +140 -0
@@ -0,0 +1,417 @@
1
+ /**
2
+ * oh-tabs
3
+ *
4
+ * Accessible tabbed interface with full keyboard support.
5
+ *
6
+ * ACCESSIBILITY FEATURES:
7
+ * ───────────────────────
8
+ * - Full ARIA support (tablist, tab, tabpanel roles)
9
+ * - Roving tabindex for keyboard navigation
10
+ * - Manual activation (arrow keys move focus, Enter/Space activates)
11
+ * - Home/End jump to first/last tab
12
+ * - Focus moves to panel content after activation
13
+ * - Focus indicators meet WCAG requirements
14
+ * - Panels properly hidden from assistive tech when inactive
15
+ *
16
+ * KEYBOARD INTERACTIONS:
17
+ * ──────────────────────
18
+ * - Left Arrow: Move focus to previous tab (wraps to last)
19
+ * - Right Arrow: Move focus to next tab (wraps to first)
20
+ * - Home: Move focus to first tab
21
+ * - End: Move focus to last tab
22
+ * - Enter/Space: Activate focused tab and move focus to panel
23
+ * - Tab: Move focus out of tablist
24
+ *
25
+ * @element oh-tabs
26
+ */
27
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
28
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
29
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
30
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
31
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
32
+ };
33
+ import { html, css } from "lit";
34
+ import { customElement, property, state } from "lit/decorators.js";
35
+ import { OhElement, baseStyles } from "./base.js";
36
+ let OhTabs = class OhTabs extends OhElement {
37
+ constructor() {
38
+ super(...arguments);
39
+ /**
40
+ * Array of tab items with id, label, and optional content
41
+ */
42
+ this.tabs = [];
43
+ /**
44
+ * ID of the currently selected tab
45
+ */
46
+ this.selected = "";
47
+ /**
48
+ * Orientation of the tabs (affects arrow key behavior)
49
+ */
50
+ this.orientation = "horizontal";
51
+ /**
52
+ * Index of the currently focused tab (for roving tabindex)
53
+ */
54
+ this._focusedIndex = 0;
55
+ /**
56
+ * Unique ID prefix for ARIA relationships
57
+ */
58
+ this._idPrefix = `oh-tabs-${Math.random().toString(36).substr(2, 9)}`;
59
+ }
60
+ static { this.styles = [
61
+ baseStyles,
62
+ css `
63
+ /* ═══════════════════════════════════════════════════════════════
64
+ ORANGE HALO TABS
65
+ Chunky • Playful • Accessible
66
+ ═══════════════════════════════════════════════════════════════ */
67
+
68
+ :host {
69
+ display: block;
70
+ font-family: var(--oh-font-family-sans);
71
+ }
72
+
73
+ /* ═══════════════════════════════════════════════════════════════
74
+ TAB LIST CONTAINER
75
+ ═══════════════════════════════════════════════════════════════ */
76
+
77
+ .tablist {
78
+ display: flex;
79
+ gap: var(--oh-spacing-1);
80
+ padding-bottom: 0;
81
+ margin-bottom: 0;
82
+ }
83
+
84
+ /* ═══════════════════════════════════════════════════════════════
85
+ INDIVIDUAL TAB BUTTONS
86
+ Clean inactive state, chunky selected state
87
+ ═══════════════════════════════════════════════════════════════ */
88
+
89
+ .tab {
90
+ position: relative;
91
+ padding: var(--oh-spacing-3) var(--oh-spacing-5);
92
+ font-family: inherit;
93
+ font-size: var(--oh-font-size-base);
94
+ font-weight: var(--oh-font-weight-medium);
95
+ color: var(--oh-color-brand-primary);
96
+ background: transparent;
97
+ border: var(--oh-input-base-border-width) solid transparent;
98
+ border-bottom: none;
99
+ border-radius: var(--oh-radius-md) var(--oh-radius-md) 0 0;
100
+ cursor: pointer;
101
+
102
+ /* No shadow for inactive tabs */
103
+ box-shadow: none;
104
+
105
+ /* Position above the border line */
106
+ margin-bottom: -2.5px;
107
+
108
+ transition:
109
+ color var(--oh-motion-snappy) ease,
110
+ background-color var(--oh-motion-snappy) ease,
111
+ border-color var(--oh-motion-snappy) ease,
112
+ box-shadow var(--oh-motion-snappy) ease;
113
+ }
114
+
115
+ /* Dashed underline pseudo-element for animation */
116
+ .tab__label {
117
+ position: relative;
118
+ }
119
+
120
+ .tab:not([aria-selected="true"]) .tab__label::after {
121
+ content: '';
122
+ position: absolute;
123
+ left: 0;
124
+ right: 0;
125
+ bottom: -3px;
126
+ height: 2px;
127
+ background: repeating-linear-gradient(
128
+ to right,
129
+ var(--oh-color-brand-primary) 0,
130
+ var(--oh-color-brand-primary) 4px,
131
+ transparent 4px,
132
+ transparent 8px
133
+ );
134
+ transform-origin: left;
135
+ transform: scaleX(0);
136
+ transition: transform var(--oh-motion-relaxed) ease;
137
+ }
138
+
139
+ .tab:hover:not([aria-selected="true"]) .tab__label::after {
140
+ transform: scaleX(1);
141
+ }
142
+
143
+ .tab:active:not([aria-selected="true"]) .tab__label::after {
144
+ transform: scaleX(1);
145
+ }
146
+
147
+ /* ═══════════════════════════════════════════════════════════════
148
+ SELECTED TAB STATE
149
+ Uses grey for a softer look (4.3:1 contrast against cream bg)
150
+ ═══════════════════════════════════════════════════════════════ */
151
+
152
+ .tab[aria-selected="true"] {
153
+ color: var(--oh-color-text-primary);
154
+ background: var(--oh-color-surface-base);
155
+ border-color: var(--oh-color-border-emphasis);
156
+ border-bottom-color: transparent;
157
+ z-index: 1;
158
+ /* Extend down to overlap the content panel's top border */
159
+ margin-bottom: calc(-1 * var(--oh-input-base-border-width));
160
+ padding-bottom: calc(var(--oh-spacing-3) + var(--oh-input-base-border-width));
161
+ }
162
+
163
+ /* ═══════════════════════════════════════════════════════════════
164
+ FOCUS STATE
165
+ Accessible underline indicator
166
+ ═══════════════════════════════════════════════════════════════ */
167
+
168
+ .tab:focus {
169
+ outline: none;
170
+ }
171
+
172
+ .tab:focus-visible {
173
+ outline: none;
174
+ }
175
+
176
+ .tab:focus-visible .tab__label {
177
+ text-decoration: underline;
178
+ text-underline-offset: var(--oh-spacing-1);
179
+ text-decoration-thickness: 2px;
180
+ }
181
+
182
+ .tab__label {
183
+ position: relative;
184
+ }
185
+
186
+ /* ═══════════════════════════════════════════════════════════════
187
+ TAB PANEL
188
+ Content area with warm styling, rounded top-right corner
189
+ ═══════════════════════════════════════════════════════════════ */
190
+
191
+ .tabpanel {
192
+ padding: var(--oh-spacing-6);
193
+ background: var(--oh-color-surface-base);
194
+ border: var(--oh-input-base-border-width) solid var(--oh-color-border-emphasis);
195
+ border-radius: 0 var(--oh-radius-md) var(--oh-radius-md) var(--oh-radius-md);
196
+ color: var(--oh-color-text-primary);
197
+ }
198
+
199
+ /* When first tab is not selected, round all corners */
200
+ .tabpanel--rounded-top-left {
201
+ border-radius: var(--oh-radius-md);
202
+ }
203
+
204
+ .tabpanel:focus {
205
+ outline: none;
206
+ }
207
+
208
+ .tabpanel:focus-visible {
209
+ outline: 2px solid var(--oh-color-border-emphasis);
210
+ outline-offset: -2px;
211
+ }
212
+
213
+ /* Hidden panels - properly hidden from assistive tech */
214
+ .tabpanel[hidden] {
215
+ display: none;
216
+ }
217
+
218
+ /* ═══════════════════════════════════════════════════════════════
219
+ REDUCED MOTION
220
+ ═══════════════════════════════════════════════════════════════ */
221
+
222
+ @media (prefers-reduced-motion: reduce) {
223
+ .tab {
224
+ transition-duration: 0.01ms !important;
225
+ }
226
+ }
227
+ `,
228
+ ]; }
229
+ connectedCallback() {
230
+ super.connectedCallback();
231
+ // Set initial selected tab if not specified
232
+ if (!this.selected && this.tabs.length > 0) {
233
+ this.selected = this.tabs[0].id;
234
+ }
235
+ // Set initial focused index to match selected
236
+ this._focusedIndex = Math.max(0, this.tabs.findIndex(t => t.id === this.selected));
237
+ }
238
+ updated(changedProperties) {
239
+ if (changedProperties.has("tabs") && this.tabs.length > 0 && !this.selected) {
240
+ this.selected = this.tabs[0].id;
241
+ }
242
+ }
243
+ /**
244
+ * Handle keyboard navigation within the tablist
245
+ * Uses manual activation: arrows move focus, Enter/Space activates
246
+ */
247
+ async _handleKeyDown(e) {
248
+ const { key } = e;
249
+ const tabCount = this.tabs.length;
250
+ if (tabCount === 0)
251
+ return;
252
+ let newIndex = this._focusedIndex;
253
+ let handled = false;
254
+ let shouldActivate = false;
255
+ switch (key) {
256
+ case "ArrowLeft":
257
+ if (this.orientation === "horizontal") {
258
+ newIndex = this._focusedIndex === 0 ? tabCount - 1 : this._focusedIndex - 1;
259
+ handled = true;
260
+ }
261
+ break;
262
+ case "ArrowRight":
263
+ if (this.orientation === "horizontal") {
264
+ newIndex = this._focusedIndex === tabCount - 1 ? 0 : this._focusedIndex + 1;
265
+ handled = true;
266
+ }
267
+ break;
268
+ case "ArrowUp":
269
+ if (this.orientation === "vertical") {
270
+ newIndex = this._focusedIndex === 0 ? tabCount - 1 : this._focusedIndex - 1;
271
+ handled = true;
272
+ }
273
+ break;
274
+ case "ArrowDown":
275
+ if (this.orientation === "vertical") {
276
+ newIndex = this._focusedIndex === tabCount - 1 ? 0 : this._focusedIndex + 1;
277
+ handled = true;
278
+ }
279
+ break;
280
+ case "Home":
281
+ newIndex = 0;
282
+ handled = true;
283
+ break;
284
+ case "End":
285
+ newIndex = tabCount - 1;
286
+ handled = true;
287
+ break;
288
+ case "Enter":
289
+ case " ": // Space
290
+ shouldActivate = true;
291
+ handled = true;
292
+ break;
293
+ }
294
+ if (handled) {
295
+ e.preventDefault();
296
+ if (shouldActivate) {
297
+ // Activate the currently focused tab
298
+ this._selectTab(this.tabs[this._focusedIndex].id);
299
+ // Wait for render to complete, then move focus to panel
300
+ await this.updateComplete;
301
+ this._focusPanel(this.tabs[this._focusedIndex].id);
302
+ }
303
+ else if (newIndex !== this._focusedIndex) {
304
+ // Just move focus to the new tab (don't activate)
305
+ this._focusedIndex = newIndex;
306
+ this._focusTab(newIndex);
307
+ }
308
+ }
309
+ }
310
+ /**
311
+ * Focus the panel for a given tab
312
+ */
313
+ _focusPanel(tabId) {
314
+ const panelId = `${this._idPrefix}-panel-${tabId}`;
315
+ const panel = this.shadowRoot?.getElementById(panelId);
316
+ panel?.focus();
317
+ }
318
+ /**
319
+ * Focus a specific tab button
320
+ */
321
+ _focusTab(index) {
322
+ const tabButtons = this.shadowRoot?.querySelectorAll('.tab');
323
+ tabButtons?.[index]?.focus();
324
+ }
325
+ /**
326
+ * Select a tab and dispatch change event
327
+ */
328
+ _selectTab(tabId) {
329
+ if (this.selected !== tabId) {
330
+ this.selected = tabId;
331
+ this._focusedIndex = this.tabs.findIndex(t => t.id === tabId);
332
+ this.dispatchEvent(new CustomEvent("tab-change", {
333
+ detail: { tabId },
334
+ bubbles: true,
335
+ composed: true,
336
+ }));
337
+ }
338
+ }
339
+ /**
340
+ * Handle click on a tab
341
+ */
342
+ _handleTabClick(tabId, index) {
343
+ this._focusedIndex = index;
344
+ this._selectTab(tabId);
345
+ }
346
+ render() {
347
+ return html `
348
+ <div class="tabs-container">
349
+ <!-- Tab List -->
350
+ <div
351
+ class="tablist"
352
+ role="tablist"
353
+ aria-orientation=${this.orientation}
354
+ @keydown=${this._handleKeyDown}
355
+ >
356
+ ${this.tabs.map((tab, index) => {
357
+ const isSelected = tab.id === this.selected;
358
+ const tabId = `${this._idPrefix}-tab-${tab.id}`;
359
+ const panelId = `${this._idPrefix}-panel-${tab.id}`;
360
+ return html `
361
+ <button
362
+ class="tab"
363
+ role="tab"
364
+ id=${tabId}
365
+ aria-selected=${isSelected ? "true" : "false"}
366
+ aria-controls=${panelId}
367
+ tabindex=${index === this._focusedIndex ? "0" : "-1"}
368
+ @click=${() => this._handleTabClick(tab.id, index)}
369
+ >
370
+ <span class="tab__label">${tab.label}</span>
371
+ </button>
372
+ `;
373
+ })}
374
+ </div>
375
+
376
+ <!-- Tab Panels -->
377
+ ${this.tabs.map((tab) => {
378
+ const isSelected = tab.id === this.selected;
379
+ const tabId = `${this._idPrefix}-tab-${tab.id}`;
380
+ const panelId = `${this._idPrefix}-panel-${tab.id}`;
381
+ const isFirstTabSelected = this.tabs.length > 0 && this.selected === this.tabs[0].id;
382
+ return html `
383
+ <div
384
+ class="tabpanel ${!isFirstTabSelected ? 'tabpanel--rounded-top-left' : ''}"
385
+ role="tabpanel"
386
+ id=${panelId}
387
+ aria-labelledby=${tabId}
388
+ ?hidden=${!isSelected}
389
+ tabindex=${isSelected ? "0" : "-1"}
390
+ >
391
+ ${tab.content
392
+ ? html `${tab.content}`
393
+ : html `<slot name=${tab.id}></slot>`}
394
+ </div>
395
+ `;
396
+ })}
397
+ </div>
398
+ `;
399
+ }
400
+ };
401
+ __decorate([
402
+ property({ type: Array })
403
+ ], OhTabs.prototype, "tabs", void 0);
404
+ __decorate([
405
+ property({ type: String, reflect: true, attribute: "selected" })
406
+ ], OhTabs.prototype, "selected", void 0);
407
+ __decorate([
408
+ property({ type: String })
409
+ ], OhTabs.prototype, "orientation", void 0);
410
+ __decorate([
411
+ state()
412
+ ], OhTabs.prototype, "_focusedIndex", void 0);
413
+ OhTabs = __decorate([
414
+ customElement("oh-tabs")
415
+ ], OhTabs);
416
+ export { OhTabs };
417
+ //# sourceMappingURL=oh-tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oh-tabs.js","sourceRoot":"","sources":["../src/oh-tabs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * oh-toggle
3
+ *
4
+ * A toggle/switch component for binary on/off states.
5
+ *
6
+ * DESIGN DECISIONS:
7
+ * ─────────────────
8
+ * 1. CHUNKY 3D FEEL
9
+ * - Thumb offset up-left from center to appear "popping out"
10
+ * - Shadow flips horizontally when checked (light source stays consistent)
11
+ * - Smooth slide animation
12
+ *
13
+ * 2. VISUAL STATES
14
+ * - Off: Neutral track, thumb on left, shadow bottom-right
15
+ * - On: Brand primary track, thumb on right, shadow bottom-left (flipped)
16
+ *
17
+ * 3. ACCESSIBILITY
18
+ * - Uses role="switch" with aria-checked
19
+ * - Keyboard: Space/Enter to toggle
20
+ * - Focus ring matches design system
21
+ * - Label association via aria-labelledby
22
+ *
23
+ * @element oh-toggle
24
+ *
25
+ * @fires oh-change - Fired when the toggle state changes
26
+ */
27
+ import { OhElement } from "./base.js";
28
+ export declare class OhToggle extends OhElement {
29
+ static styles: import("lit").CSSResult[];
30
+ /** Whether the toggle is checked/on */
31
+ checked: boolean;
32
+ /** Label text displayed next to the toggle */
33
+ label?: string;
34
+ /** Accessible label when no visible label is provided */
35
+ ariaLabel: string | null;
36
+ /** Name for form submission */
37
+ name?: string;
38
+ /** Value for form submission */
39
+ value: string;
40
+ private _toggle;
41
+ private _handleKeydown;
42
+ private _handleClick;
43
+ private readonly _labelId;
44
+ render(): import("lit").TemplateResult<1>;
45
+ }
46
+ declare global {
47
+ interface HTMLElementTagNameMap {
48
+ "oh-toggle": OhToggle;
49
+ }
50
+ }
51
+ //# sourceMappingURL=oh-toggle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oh-toggle.d.ts","sourceRoot":"","sources":["../src/oh-toggle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAIH,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,qBACa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,4BAkHpB;IAEF,uCAAuC;IAEvC,OAAO,UAAS;IAEhB,8CAA8C;IAE9C,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,yDAAyD;IAEzD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEhC,+BAA+B;IAE/B,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,gCAAgC;IAEhC,KAAK,SAAQ;IAEb,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+D;IAExF,MAAM;CAqBP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}