@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,450 @@
1
+ /**
2
+ * oh-modal
3
+ *
4
+ * A chunky, accessible modal dialog with focus trapping.
5
+ *
6
+ * DESIGN DECISIONS:
7
+ * ─────────────────
8
+ * 1. CHUNKY & LIFTED
9
+ * - 2.5px border like other components
10
+ * - Offset shadow (4px 4px) — feels like a lifted surface
11
+ * - Warm backdrop, not pure black
12
+ *
13
+ * 2. ACCESSIBLE
14
+ * - Focus trap when open
15
+ * - Escape key closes (when dismissible)
16
+ * - Focus returns to trigger on close
17
+ * - role="dialog" + aria-modal="true"
18
+ *
19
+ * 3. FLEXIBLE STRUCTURE
20
+ * - Optional heading
21
+ * - Scrollable body content
22
+ * - Optional footer slot for actions
23
+ *
24
+ * @element oh-modal
25
+ */
26
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
27
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
28
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
29
+ 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;
30
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
31
+ };
32
+ import { html, css, nothing } from "lit";
33
+ import { customElement, property, query, state } from "lit/decorators.js";
34
+ import { OhElement, baseStyles } from "./base.js";
35
+ let OhModal = class OhModal extends OhElement {
36
+ constructor() {
37
+ super(...arguments);
38
+ this.open = false;
39
+ this.heading = "";
40
+ this.dismissible = true;
41
+ this.size = "md";
42
+ this._previousActiveElement = null;
43
+ }
44
+ static { this.styles = [
45
+ baseStyles,
46
+ css `
47
+ /* ═══════════════════════════════════════════════════════════════
48
+ ORANGE HALO MODAL
49
+ Chunky • Lifted • Accessible
50
+ ═══════════════════════════════════════════════════════════════ */
51
+
52
+ :host {
53
+ display: contents;
54
+ }
55
+
56
+ /* ═══════════════════════════════════════════════════════════════
57
+ BACKDROP
58
+ ═══════════════════════════════════════════════════════════════ */
59
+
60
+ .backdrop {
61
+ position: fixed;
62
+ inset: 0;
63
+ z-index: 1000;
64
+
65
+ /* Warm semi-transparent overlay */
66
+ background-color: rgba(61, 50, 41, 0.6);
67
+
68
+ /* Flexbox centering */
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: center;
72
+ padding: var(--oh-spacing-4);
73
+
74
+ /* Animation */
75
+ opacity: 0;
76
+ visibility: hidden;
77
+ transition:
78
+ opacity var(--oh-motion-gentle, 200ms) ease,
79
+ visibility var(--oh-motion-gentle, 200ms) ease;
80
+ }
81
+
82
+ .backdrop--open {
83
+ opacity: 1;
84
+ visibility: visible;
85
+ }
86
+
87
+ /* ═══════════════════════════════════════════════════════════════
88
+ DIALOG PANEL
89
+ ═══════════════════════════════════════════════════════════════ */
90
+
91
+ .modal {
92
+ position: relative;
93
+ display: flex;
94
+ flex-direction: column;
95
+ max-height: calc(100vh - var(--oh-spacing-8));
96
+ max-width: 100%;
97
+
98
+ /* Warm surface */
99
+ background-color: var(--oh-color-surface-base);
100
+
101
+ /* Chunky border */
102
+ border: var(--oh-input-base-border-width, 2.5px) solid var(--oh-color-border-emphasis);
103
+ border-radius: var(--oh-radius-md);
104
+
105
+ /* Offset shadow — lifted surface */
106
+ box-shadow: 6px 6px 0 0 rgba(107, 93, 77, 0.25);
107
+
108
+ /* Animation */
109
+ transform: scale(0.95) translateY(10px);
110
+ opacity: 0;
111
+ transition:
112
+ transform var(--oh-motion-gentle, 200ms) var(--oh-motion-ease-playful, cubic-bezier(0.34, 1.56, 0.64, 1)),
113
+ opacity var(--oh-motion-gentle, 200ms) ease;
114
+ }
115
+
116
+ .backdrop--open .modal {
117
+ transform: scale(1) translateY(0);
118
+ opacity: 1;
119
+ }
120
+
121
+ /* Size variants */
122
+ .modal--sm {
123
+ width: 400px;
124
+ }
125
+
126
+ .modal--md {
127
+ width: 560px;
128
+ }
129
+
130
+ .modal--lg {
131
+ width: 720px;
132
+ }
133
+
134
+ /* ═══════════════════════════════════════════════════════════════
135
+ HEADER
136
+ ═══════════════════════════════════════════════════════════════ */
137
+
138
+ .modal-header {
139
+ display: flex;
140
+ align-items: center;
141
+ justify-content: space-between;
142
+ gap: var(--oh-spacing-4);
143
+ padding: var(--oh-spacing-4) var(--oh-spacing-5);
144
+ border-bottom: var(--oh-input-base-border-width, 2.5px) solid var(--oh-color-border-subtle);
145
+ }
146
+
147
+ .modal-title {
148
+ margin: 0;
149
+ font-family: var(--oh-font-family-sans);
150
+ font-size: var(--oh-font-size-xl);
151
+ font-weight: var(--oh-font-weight-semibold);
152
+ color: var(--oh-color-text-primary);
153
+ line-height: var(--oh-font-line-height-tight, 1.25);
154
+ }
155
+
156
+ /* ═══════════════════════════════════════════════════════════════
157
+ CLOSE BUTTON
158
+ ═══════════════════════════════════════════════════════════════ */
159
+
160
+ .modal-close {
161
+ flex-shrink: 0;
162
+ display: flex;
163
+ align-items: center;
164
+ gap: var(--oh-spacing-1);
165
+
166
+ padding: var(--oh-spacing-1) var(--oh-spacing-2);
167
+
168
+ font-family: var(--oh-font-family-sans);
169
+ font-size: var(--oh-font-size-base);
170
+ font-weight: var(--oh-font-weight-medium);
171
+
172
+ background: transparent;
173
+ border: none;
174
+ border-radius: var(--oh-radius-sm);
175
+ cursor: pointer;
176
+ color: var(--oh-color-text-primary);
177
+
178
+ transition:
179
+ transform var(--oh-motion-snappy, 150ms) var(--oh-motion-ease-playful, cubic-bezier(0.34, 1.56, 0.64, 1)),
180
+ box-shadow var(--oh-motion-snappy, 150ms) var(--oh-motion-ease-playful, cubic-bezier(0.34, 1.56, 0.64, 1)),
181
+ background-color var(--oh-motion-quick, 120ms) ease;
182
+ }
183
+
184
+ .modal-close:hover {
185
+ background-color: rgba(0, 0, 0, 0.08);
186
+ transform: translate(-2px, -2px);
187
+ box-shadow: 4px 4px 0 0 rgba(0, 0, 0, 0.15);
188
+ }
189
+
190
+ .modal-close:active {
191
+ transform: translate(1px, 1px);
192
+ box-shadow: 1px 1px 0 0 rgba(0, 0, 0, 0.15);
193
+ }
194
+
195
+ .modal-close:focus-visible {
196
+ outline: none;
197
+ text-decoration: underline;
198
+ text-underline-offset: 3px;
199
+ }
200
+
201
+ .modal-close svg {
202
+ width: 1rem;
203
+ height: 1rem;
204
+ }
205
+
206
+ /* ═══════════════════════════════════════════════════════════════
207
+ BODY
208
+ ═══════════════════════════════════════════════════════════════ */
209
+
210
+ .modal-body {
211
+ flex: 1;
212
+ overflow-y: auto;
213
+ padding: var(--oh-spacing-5);
214
+
215
+ font-family: var(--oh-font-family-sans);
216
+ font-size: var(--oh-font-size-base);
217
+ line-height: var(--oh-font-line-height-normal);
218
+ color: var(--oh-color-text-primary);
219
+ }
220
+
221
+ /* ═══════════════════════════════════════════════════════════════
222
+ FOOTER
223
+ ═══════════════════════════════════════════════════════════════ */
224
+
225
+ .modal-footer {
226
+ display: flex;
227
+ align-items: center;
228
+ justify-content: flex-start;
229
+ gap: var(--oh-spacing-6);
230
+ padding: var(--oh-spacing-4) var(--oh-spacing-5);
231
+ border-top: var(--oh-input-base-border-width, 2.5px) solid var(--oh-color-border-subtle);
232
+ }
233
+
234
+ /* Hide footer if empty */
235
+ .modal-footer:empty {
236
+ display: none;
237
+ }
238
+
239
+ /* Style slotted footer content */
240
+ .modal-footer ::slotted(*) {
241
+ display: flex;
242
+ align-items: center;
243
+ gap: var(--oh-spacing-6);
244
+ }
245
+
246
+ /* ═══════════════════════════════════════════════════════════════
247
+ REDUCED MOTION
248
+ ═══════════════════════════════════════════════════════════════ */
249
+
250
+ @media (prefers-reduced-motion: reduce) {
251
+ .backdrop,
252
+ .modal,
253
+ .modal-close {
254
+ transition-duration: 0.01ms !important;
255
+ }
256
+
257
+ .modal {
258
+ transform: none !important;
259
+ }
260
+ }
261
+ `,
262
+ ]; }
263
+ connectedCallback() {
264
+ super.connectedCallback();
265
+ this._handleKeyDown = this._handleKeyDown.bind(this);
266
+ }
267
+ updated(changedProperties) {
268
+ if (changedProperties.has("open")) {
269
+ if (this.open) {
270
+ this._onOpen();
271
+ }
272
+ else {
273
+ this._onClose();
274
+ }
275
+ }
276
+ }
277
+ _onOpen() {
278
+ // Store the currently focused element
279
+ this._previousActiveElement = document.activeElement;
280
+ // Prevent body scroll
281
+ document.body.style.overflow = "hidden";
282
+ // Add keyboard listener
283
+ document.addEventListener("keydown", this._handleKeyDown);
284
+ // Focus the close button or first focusable element
285
+ requestAnimationFrame(() => {
286
+ if (this._closeButton) {
287
+ this._closeButton.focus();
288
+ }
289
+ else {
290
+ this._focusFirstElement();
291
+ }
292
+ });
293
+ }
294
+ _onClose() {
295
+ // Restore body scroll
296
+ document.body.style.overflow = "";
297
+ // Remove keyboard listener
298
+ document.removeEventListener("keydown", this._handleKeyDown);
299
+ // Return focus to previous element
300
+ if (this._previousActiveElement) {
301
+ this._previousActiveElement.focus();
302
+ this._previousActiveElement = null;
303
+ }
304
+ }
305
+ _handleKeyDown(event) {
306
+ if (event.key === "Escape" && this.dismissible) {
307
+ this._requestClose();
308
+ return;
309
+ }
310
+ if (event.key === "Tab") {
311
+ this._trapFocus(event);
312
+ }
313
+ }
314
+ _trapFocus(event) {
315
+ const focusableElements = this._getFocusableElements();
316
+ if (focusableElements.length === 0)
317
+ return;
318
+ const firstElement = focusableElements[0];
319
+ const lastElement = focusableElements[focusableElements.length - 1];
320
+ if (event.shiftKey) {
321
+ // Shift + Tab
322
+ if (document.activeElement === firstElement) {
323
+ event.preventDefault();
324
+ lastElement.focus();
325
+ }
326
+ }
327
+ else {
328
+ // Tab
329
+ if (document.activeElement === lastElement) {
330
+ event.preventDefault();
331
+ firstElement.focus();
332
+ }
333
+ }
334
+ }
335
+ _getFocusableElements() {
336
+ const selector = [
337
+ 'button:not([disabled])',
338
+ 'a[href]',
339
+ 'input:not([disabled])',
340
+ 'select:not([disabled])',
341
+ 'textarea:not([disabled])',
342
+ '[tabindex]:not([tabindex="-1"])',
343
+ ].join(', ');
344
+ const shadowElements = Array.from(this.shadowRoot?.querySelectorAll(selector) || []);
345
+ const slottedElements = Array.from(this.querySelectorAll(selector));
346
+ return [...shadowElements, ...slottedElements];
347
+ }
348
+ _focusFirstElement() {
349
+ const focusableElements = this._getFocusableElements();
350
+ if (focusableElements.length > 0) {
351
+ focusableElements[0].focus();
352
+ }
353
+ }
354
+ _handleBackdropClick(event) {
355
+ if (event.target === event.currentTarget && this.dismissible) {
356
+ this._requestClose();
357
+ }
358
+ }
359
+ _requestClose() {
360
+ this.emit("oh-close");
361
+ this.open = false;
362
+ }
363
+ disconnectedCallback() {
364
+ super.disconnectedCallback();
365
+ document.removeEventListener("keydown", this._handleKeyDown);
366
+ document.body.style.overflow = "";
367
+ }
368
+ render() {
369
+ const backdropClasses = this.classMap({
370
+ backdrop: true,
371
+ "backdrop--open": this.open,
372
+ });
373
+ const modalClasses = this.classMap({
374
+ modal: true,
375
+ [`modal--${this.size}`]: true,
376
+ });
377
+ const labelId = this.heading ? "modal-title" : undefined;
378
+ return html `
379
+ <div
380
+ class=${backdropClasses}
381
+ @click=${this._handleBackdropClick}
382
+ aria-hidden=${!this.open}
383
+ >
384
+ <div
385
+ class=${modalClasses}
386
+ role="dialog"
387
+ aria-modal="true"
388
+ aria-labelledby=${labelId || nothing}
389
+ part="modal"
390
+ >
391
+ ${this.heading || this.dismissible
392
+ ? html `
393
+ <header class="modal-header" part="header">
394
+ ${this.heading
395
+ ? html `<h2 id="modal-title" class="modal-title">${this.heading}</h2>`
396
+ : html `<span></span>`}
397
+ ${this.dismissible
398
+ ? html `
399
+ <button
400
+ class="modal-close"
401
+ type="button"
402
+ @click=${this._requestClose}
403
+ part="close"
404
+ >
405
+ <span>Close</span>
406
+ <svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
407
+ <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
408
+ </svg>
409
+ </button>
410
+ `
411
+ : nothing}
412
+ </header>
413
+ `
414
+ : nothing}
415
+
416
+ <div class="modal-body" part="body">
417
+ <slot></slot>
418
+ </div>
419
+
420
+ <footer class="modal-footer" part="footer">
421
+ <slot name="footer"></slot>
422
+ </footer>
423
+ </div>
424
+ </div>
425
+ `;
426
+ }
427
+ };
428
+ __decorate([
429
+ property({ type: Boolean, reflect: true })
430
+ ], OhModal.prototype, "open", void 0);
431
+ __decorate([
432
+ property({ type: String })
433
+ ], OhModal.prototype, "heading", void 0);
434
+ __decorate([
435
+ property({ type: Boolean, reflect: true })
436
+ ], OhModal.prototype, "dismissible", void 0);
437
+ __decorate([
438
+ property({ type: String, reflect: true })
439
+ ], OhModal.prototype, "size", void 0);
440
+ __decorate([
441
+ state()
442
+ ], OhModal.prototype, "_previousActiveElement", void 0);
443
+ __decorate([
444
+ query(".modal-close")
445
+ ], OhModal.prototype, "_closeButton", void 0);
446
+ OhModal = __decorate([
447
+ customElement("oh-modal")
448
+ ], OhModal);
449
+ export { OhModal };
450
+ //# sourceMappingURL=oh-modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oh-modal.js","sourceRoot":"","sources":["../src/oh-modal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * oh-navbar
3
+ *
4
+ * A responsive navigation bar component with logo, links, and mobile drawer.
5
+ *
6
+ * DESIGN DECISIONS:
7
+ * ─────────────────
8
+ * 1. LAYOUT
9
+ * - Logo on the left
10
+ * - Navigation links on the right (desktop)
11
+ * - Hamburger menu on mobile triggers drawer
12
+ *
13
+ * 2. STYLING
14
+ * - Surface base background
15
+ * - Chunky bottom border
16
+ * - Links use oh-link styling
17
+ *
18
+ * 3. RESPONSIVE
19
+ * - Desktop: horizontal links
20
+ * - Mobile (< 768px): hamburger + drawer
21
+ *
22
+ * @element oh-navbar
23
+ *
24
+ * @slot logo - Slot for logo/brand element
25
+ * @slot - Default slot for navigation links
26
+ *
27
+ * @cssprop --oh-navbar-breakpoint - Mobile breakpoint (default: 768px)
28
+ */
29
+ import { OhElement } from "./base.js";
30
+ import "./oh-container.js";
31
+ import "./oh-cluster.js";
32
+ import "./oh-drawer.js";
33
+ import "./oh-button.js";
34
+ import "./oh-icon.js";
35
+ export declare class OhNavbar extends OhElement {
36
+ static styles: import("lit").CSSResult[];
37
+ /** Heading shown in the mobile drawer */
38
+ drawerHeading: string;
39
+ private _drawerOpen;
40
+ private _openDrawer;
41
+ private _closeDrawer;
42
+ render(): import("lit").TemplateResult<1>;
43
+ }
44
+ declare global {
45
+ interface HTMLElementTagNameMap {
46
+ "oh-navbar": OhNavbar;
47
+ }
48
+ }
49
+ //# sourceMappingURL=oh-navbar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oh-navbar.d.ts","sourceRoot":"","sources":["../src/oh-navbar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,OAAO,mBAAmB,CAAC;AAC3B,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AACxB,OAAO,gBAAgB,CAAC;AACxB,OAAO,cAAc,CAAC;AAEtB,qBACa,QAAS,SAAQ,SAAS;IACrC,OAAgB,MAAM,4BA2EpB;IAEF,yCAAyC;IAEzC,aAAa,SAAU;IAGvB,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,YAAY;IAIpB,MAAM;CA0CP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * oh-navbar
3
+ *
4
+ * A responsive navigation bar component with logo, links, and mobile drawer.
5
+ *
6
+ * DESIGN DECISIONS:
7
+ * ─────────────────
8
+ * 1. LAYOUT
9
+ * - Logo on the left
10
+ * - Navigation links on the right (desktop)
11
+ * - Hamburger menu on mobile triggers drawer
12
+ *
13
+ * 2. STYLING
14
+ * - Surface base background
15
+ * - Chunky bottom border
16
+ * - Links use oh-link styling
17
+ *
18
+ * 3. RESPONSIVE
19
+ * - Desktop: horizontal links
20
+ * - Mobile (< 768px): hamburger + drawer
21
+ *
22
+ * @element oh-navbar
23
+ *
24
+ * @slot logo - Slot for logo/brand element
25
+ * @slot - Default slot for navigation links
26
+ *
27
+ * @cssprop --oh-navbar-breakpoint - Mobile breakpoint (default: 768px)
28
+ */
29
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
30
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
31
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
32
+ 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;
33
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
34
+ };
35
+ import { html, css } from "lit";
36
+ import { customElement, property, state } from "lit/decorators.js";
37
+ import { OhElement, baseStyles } from "./base.js";
38
+ import "./oh-container.js";
39
+ import "./oh-cluster.js";
40
+ import "./oh-drawer.js";
41
+ import "./oh-button.js";
42
+ import "./oh-icon.js";
43
+ let OhNavbar = class OhNavbar extends OhElement {
44
+ constructor() {
45
+ super(...arguments);
46
+ /** Heading shown in the mobile drawer */
47
+ this.drawerHeading = "Menu";
48
+ this._drawerOpen = false;
49
+ }
50
+ static { this.styles = [
51
+ baseStyles,
52
+ css `
53
+ :host {
54
+ display: block;
55
+ background-color: var(--oh-color-surface-base);
56
+ border-bottom: var(--oh-border-width-md) solid var(--oh-color-border-default);
57
+ box-shadow: 0 2px 8px var(--oh-focus-glow-color);
58
+ font-family: var(--oh-font-family-sans);
59
+ font-size: var(--oh-font-size-base);
60
+ }
61
+
62
+ .navbar {
63
+ display: flex;
64
+ align-items: center;
65
+ justify-content: space-between;
66
+ padding: var(--oh-spacing-4) 0;
67
+ }
68
+
69
+ /* Logo slot */
70
+ .navbar__logo {
71
+ display: flex;
72
+ align-items: center;
73
+ }
74
+
75
+ .navbar__logo ::slotted(a) {
76
+ display: flex;
77
+ align-items: center;
78
+ text-decoration: none;
79
+ height: var(--oh-navbar-logo-height, 40px);
80
+ }
81
+
82
+ .navbar__logo ::slotted(img) {
83
+ height: var(--oh-navbar-logo-height, 40px);
84
+ width: auto;
85
+ }
86
+
87
+ /* Desktop links - pushed to the right */
88
+ .navbar__links {
89
+ margin-left: auto;
90
+ width: auto; /* Override oh-cluster's width: 100% */
91
+ }
92
+
93
+ /* Mobile toggle - hidden on desktop */
94
+ .navbar__mobile-toggle {
95
+ display: none;
96
+ }
97
+
98
+ /* Drawer nav styling */
99
+ .drawer-nav {
100
+ display: flex;
101
+ flex-direction: column;
102
+ gap: var(--oh-spacing-2);
103
+ }
104
+
105
+ .drawer-nav ::slotted(oh-link) {
106
+ padding: var(--oh-spacing-3) 0;
107
+ border-bottom: 1px solid var(--oh-color-border-subtle);
108
+ }
109
+
110
+ .drawer-nav ::slotted(oh-link:last-child) {
111
+ border-bottom: none;
112
+ }
113
+
114
+ /* Mobile styles */
115
+ @media (max-width: 768px) {
116
+ .navbar__links {
117
+ display: none;
118
+ }
119
+
120
+ .navbar__mobile-toggle {
121
+ display: block;
122
+ }
123
+ }
124
+ `,
125
+ ]; }
126
+ _openDrawer() {
127
+ this._drawerOpen = true;
128
+ }
129
+ _closeDrawer() {
130
+ this._drawerOpen = false;
131
+ }
132
+ render() {
133
+ return html `
134
+ <oh-container size="lg">
135
+ <nav class="navbar">
136
+ <!-- Logo -->
137
+ <div class="navbar__logo">
138
+ <slot name="logo"></slot>
139
+ </div>
140
+
141
+ <!-- Desktop Navigation Links -->
142
+ <oh-cluster gap="lg" align="center" class="navbar__links">
143
+ <slot></slot>
144
+ </oh-cluster>
145
+
146
+ <!-- Mobile Menu Toggle -->
147
+ <div class="navbar__mobile-toggle">
148
+ <oh-button
149
+ variant="primary"
150
+ size="sm"
151
+ icon-only
152
+ aria-label="Open navigation menu"
153
+ @click=${this._openDrawer}
154
+ >
155
+ <oh-icon name="menu"></oh-icon>
156
+ </oh-button>
157
+ </div>
158
+ </nav>
159
+ </oh-container>
160
+
161
+ <!-- Mobile Navigation Drawer -->
162
+ <oh-drawer
163
+ position="left"
164
+ heading=${this.drawerHeading}
165
+ ?open=${this._drawerOpen}
166
+ @oh-close=${this._closeDrawer}
167
+ >
168
+ <nav class="drawer-nav">
169
+ <slot name="mobile"></slot>
170
+ </nav>
171
+ </oh-drawer>
172
+ `;
173
+ }
174
+ };
175
+ __decorate([
176
+ property({ type: String, attribute: "drawer-heading" })
177
+ ], OhNavbar.prototype, "drawerHeading", void 0);
178
+ __decorate([
179
+ state()
180
+ ], OhNavbar.prototype, "_drawerOpen", void 0);
181
+ OhNavbar = __decorate([
182
+ customElement("oh-navbar")
183
+ ], OhNavbar);
184
+ export { OhNavbar };
185
+ //# sourceMappingURL=oh-navbar.js.map