@hypoth-ui/wc 0.1.1

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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/button-MKQKTC5Q.js +10 -0
  4. package/dist/button-MKQKTC5Q.js.map +1 -0
  5. package/dist/chunk-4HLM6DBG.js +910 -0
  6. package/dist/chunk-4HLM6DBG.js.map +1 -0
  7. package/dist/chunk-55ID7LJL.js +3602 -0
  8. package/dist/chunk-55ID7LJL.js.map +1 -0
  9. package/dist/chunk-66HFYJD7.js +86 -0
  10. package/dist/chunk-66HFYJD7.js.map +1 -0
  11. package/dist/chunk-CZOXIJVS.js +70 -0
  12. package/dist/chunk-CZOXIJVS.js.map +1 -0
  13. package/dist/chunk-DHUM4Q5Y.js +495 -0
  14. package/dist/chunk-DHUM4Q5Y.js.map +1 -0
  15. package/dist/chunk-DNNI5BDE.js +1842 -0
  16. package/dist/chunk-DNNI5BDE.js.map +1 -0
  17. package/dist/chunk-GXKZ6E6K.js +99 -0
  18. package/dist/chunk-GXKZ6E6K.js.map +1 -0
  19. package/dist/chunk-H4GJJZ3N.js +51 -0
  20. package/dist/chunk-H4GJJZ3N.js.map +1 -0
  21. package/dist/chunk-JMPTFALJ.js +175 -0
  22. package/dist/chunk-JMPTFALJ.js.map +1 -0
  23. package/dist/chunk-MYQWCLUJ.js +45 -0
  24. package/dist/chunk-MYQWCLUJ.js.map +1 -0
  25. package/dist/chunk-QZSPWT7L.js +183 -0
  26. package/dist/chunk-QZSPWT7L.js.map +1 -0
  27. package/dist/chunk-TSKBQCTR.js +5137 -0
  28. package/dist/chunk-TSKBQCTR.js.map +1 -0
  29. package/dist/chunk-TXIIUVL3.js +130 -0
  30. package/dist/chunk-TXIIUVL3.js.map +1 -0
  31. package/dist/chunk-UM7WRO7W.js +237 -0
  32. package/dist/chunk-UM7WRO7W.js.map +1 -0
  33. package/dist/chunk-VPXL4RB3.js +202 -0
  34. package/dist/chunk-VPXL4RB3.js.map +1 -0
  35. package/dist/chunk-VX5CKSMN.js +39 -0
  36. package/dist/chunk-VX5CKSMN.js.map +1 -0
  37. package/dist/chunk-WQ5BEP3E.js +2845 -0
  38. package/dist/chunk-WQ5BEP3E.js.map +1 -0
  39. package/dist/chunk-YDQ434UH.js +60 -0
  40. package/dist/chunk-YDQ434UH.js.map +1 -0
  41. package/dist/chunk-ZWV4VI6D.js +153 -0
  42. package/dist/chunk-ZWV4VI6D.js.map +1 -0
  43. package/dist/core.d.ts +127 -0
  44. package/dist/core.js +38 -0
  45. package/dist/core.js.map +1 -0
  46. package/dist/data-display.d.ts +872 -0
  47. package/dist/data-display.js +57 -0
  48. package/dist/data-display.js.map +1 -0
  49. package/dist/ds-element-Db0LMfxI.d.ts +43 -0
  50. package/dist/feedback.d.ts +292 -0
  51. package/dist/feedback.js +31 -0
  52. package/dist/feedback.js.map +1 -0
  53. package/dist/form-controls.d.ts +1713 -0
  54. package/dist/form-controls.js +63 -0
  55. package/dist/form-controls.js.map +1 -0
  56. package/dist/icon-7IZTJ5WT.js +8 -0
  57. package/dist/icon-7IZTJ5WT.js.map +1 -0
  58. package/dist/index.d.ts +15 -0
  59. package/dist/index.js +423 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/input-LB6UR37A.js +10 -0
  62. package/dist/input-LB6UR37A.js.map +1 -0
  63. package/dist/layout.d.ts +504 -0
  64. package/dist/layout.js +34 -0
  65. package/dist/layout.js.map +1 -0
  66. package/dist/link-NHDJ6SFY.js +9 -0
  67. package/dist/link-NHDJ6SFY.js.map +1 -0
  68. package/dist/navigation.d.ts +255 -0
  69. package/dist/navigation.js +111 -0
  70. package/dist/navigation.js.map +1 -0
  71. package/dist/overlays.d.ts +1291 -0
  72. package/dist/overlays.js +106 -0
  73. package/dist/overlays.js.map +1 -0
  74. package/dist/primitives.d.ts +230 -0
  75. package/dist/primitives.js +26 -0
  76. package/dist/primitives.js.map +1 -0
  77. package/dist/registry-Bns0t11H.d.ts +233 -0
  78. package/dist/skeleton-MUdd2029.d.ts +109 -0
  79. package/dist/spinner-BWaNlc-Y.d.ts +45 -0
  80. package/dist/spinner-UIYDUVBZ.js +8 -0
  81. package/dist/spinner-UIYDUVBZ.js.map +1 -0
  82. package/dist/stepper-CCRwcQOe.d.ts +851 -0
  83. package/dist/text-MT3S3EMU.js +8 -0
  84. package/dist/text-MT3S3EMU.js.map +1 -0
  85. package/dist/visually-hidden-MW2XY4CS.js +8 -0
  86. package/dist/visually-hidden-MW2XY4CS.js.map +1 -0
  87. package/package.json +92 -0
@@ -0,0 +1,3602 @@
1
+ import {
2
+ Warnings,
3
+ devWarn,
4
+ hasRequiredChild
5
+ } from "./chunk-JMPTFALJ.js";
6
+ import {
7
+ StandardEvents,
8
+ emitEvent
9
+ } from "./chunk-YDQ434UH.js";
10
+ import {
11
+ DSElement,
12
+ __decorateClass,
13
+ define
14
+ } from "./chunk-H4GJJZ3N.js";
15
+
16
+ // src/components/dialog/dialog-content.ts
17
+ import { html } from "lit";
18
+ import { property } from "lit/decorators.js";
19
+ var DsDialogContent = class extends DSElement {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.size = "md";
23
+ this.dataState = "open";
24
+ }
25
+ render() {
26
+ return html`
27
+ <div class="ds-dialog-content" part="container" data-size=${this.size}>
28
+ <slot></slot>
29
+ </div>
30
+ `;
31
+ }
32
+ };
33
+ __decorateClass([
34
+ property({ type: String, reflect: true })
35
+ ], DsDialogContent.prototype, "size", 2);
36
+ __decorateClass([
37
+ property({ type: String, reflect: true, attribute: "data-state" })
38
+ ], DsDialogContent.prototype, "dataState", 2);
39
+ define("ds-dialog-content", DsDialogContent);
40
+
41
+ // src/components/dialog/dialog-title.ts
42
+ import { html as html2, nothing } from "lit";
43
+ import { state } from "lit/decorators.js";
44
+ var DsDialogTitle = class extends DSElement {
45
+ constructor() {
46
+ super(...arguments);
47
+ this.titleText = "";
48
+ }
49
+ connectedCallback() {
50
+ this.titleText = this.textContent?.trim() ?? "";
51
+ super.connectedCallback();
52
+ if (!this.id) {
53
+ this.id = `dialog-title-${crypto.randomUUID().slice(0, 8)}`;
54
+ }
55
+ }
56
+ render() {
57
+ if (!this.titleText) {
58
+ return nothing;
59
+ }
60
+ return html2`
61
+ <h2 class="ds-dialog-title" part="title">${this.titleText}</h2>
62
+ `;
63
+ }
64
+ };
65
+ __decorateClass([
66
+ state()
67
+ ], DsDialogTitle.prototype, "titleText", 2);
68
+ define("ds-dialog-title", DsDialogTitle);
69
+
70
+ // src/components/dialog/dialog-description.ts
71
+ import { html as html3, nothing as nothing2 } from "lit";
72
+ import { state as state2 } from "lit/decorators.js";
73
+ var DsDialogDescription = class extends DSElement {
74
+ constructor() {
75
+ super(...arguments);
76
+ this.descriptionText = "";
77
+ }
78
+ connectedCallback() {
79
+ this.descriptionText = this.textContent?.trim() ?? "";
80
+ super.connectedCallback();
81
+ if (!this.id) {
82
+ this.id = `dialog-desc-${crypto.randomUUID().slice(0, 8)}`;
83
+ }
84
+ }
85
+ render() {
86
+ if (!this.descriptionText) {
87
+ return nothing2;
88
+ }
89
+ return html3`
90
+ <p class="ds-dialog-description" part="description">${this.descriptionText}</p>
91
+ `;
92
+ }
93
+ };
94
+ __decorateClass([
95
+ state2()
96
+ ], DsDialogDescription.prototype, "descriptionText", 2);
97
+ define("ds-dialog-description", DsDialogDescription);
98
+
99
+ // src/components/dialog/dialog.ts
100
+ import {
101
+ createDialogBehavior,
102
+ createPresence,
103
+ prefersReducedMotion
104
+ } from "@hypoth-ui/primitives-dom";
105
+ import { html as html4 } from "lit";
106
+ import { property as property2, state as state3 } from "lit/decorators.js";
107
+ var DsDialog = class extends DSElement {
108
+ constructor() {
109
+ super(...arguments);
110
+ this.open = false;
111
+ this.closeOnEscape = true;
112
+ this.closeOnBackdrop = true;
113
+ this.animated = true;
114
+ this.dialogRole = "dialog";
115
+ this.isClosing = false;
116
+ this.dialogBehavior = null;
117
+ this.presence = null;
118
+ this.attributeObserver = null;
119
+ this.backdropElement = null;
120
+ /** Tracks the reason for closing (for animation completion) */
121
+ this._closeReason = "programmatic";
122
+ this.handleTriggerClick = (event) => {
123
+ const target = event.target;
124
+ const trigger = target.closest('[slot="trigger"]');
125
+ if (trigger && this.contains(trigger)) {
126
+ this.dialogBehavior?.setTriggerElement(trigger);
127
+ this.show();
128
+ }
129
+ };
130
+ this.handleBackdropClick = (event) => {
131
+ const content = this.querySelector("ds-dialog-content");
132
+ const target = event.target;
133
+ if (content?.contains(target)) {
134
+ return;
135
+ }
136
+ if (this.closeOnBackdrop) {
137
+ this.close("outside-click");
138
+ }
139
+ };
140
+ }
141
+ connectedCallback() {
142
+ super.connectedCallback();
143
+ this.addEventListener("click", this.handleTriggerClick);
144
+ this.attributeObserver = new MutationObserver(() => {
145
+ const roleAttr = this.getAttribute("role");
146
+ if (roleAttr === "alertdialog" || roleAttr === "dialog") {
147
+ this.dialogRole = roleAttr;
148
+ }
149
+ if (roleAttr) {
150
+ this.removeAttribute("role");
151
+ }
152
+ });
153
+ this.attributeObserver.observe(this, {
154
+ attributes: true,
155
+ attributeFilter: ["role"]
156
+ });
157
+ const initialRole = this.getAttribute("role");
158
+ if (initialRole === "alertdialog" || initialRole === "dialog") {
159
+ this.dialogRole = initialRole;
160
+ this.removeAttribute("role");
161
+ }
162
+ this.initDialogBehavior();
163
+ }
164
+ disconnectedCallback() {
165
+ super.disconnectedCallback();
166
+ this.removeEventListener("click", this.handleTriggerClick);
167
+ this.attributeObserver?.disconnect();
168
+ this.attributeObserver = null;
169
+ this.cleanup();
170
+ }
171
+ /**
172
+ * Initializes the dialog behavior primitive.
173
+ */
174
+ initDialogBehavior() {
175
+ this.dialogBehavior = createDialogBehavior({
176
+ defaultOpen: this.open,
177
+ role: this.dialogRole,
178
+ closeOnEscape: this.closeOnEscape,
179
+ closeOnOutsideClick: this.closeOnBackdrop,
180
+ onOpenChange: (open) => {
181
+ if (!open && this.open) {
182
+ this.handleBehaviorClose();
183
+ }
184
+ }
185
+ });
186
+ const trigger = this.querySelector('[slot="trigger"]');
187
+ if (trigger) {
188
+ this.dialogBehavior.setTriggerElement(trigger);
189
+ }
190
+ }
191
+ /**
192
+ * Handles close triggered by the behavior (escape/outside click).
193
+ */
194
+ handleBehaviorClose(reason = "escape") {
195
+ const openChangeEvent = emitEvent(this, StandardEvents.OPEN_CHANGE, {
196
+ detail: { open: false, reason },
197
+ cancelable: true
198
+ });
199
+ if (openChangeEvent.defaultPrevented) {
200
+ this.dialogBehavior?.open();
201
+ return;
202
+ }
203
+ const content = this.querySelector("ds-dialog-content");
204
+ if (this.animated && content && !prefersReducedMotion()) {
205
+ this.isClosing = true;
206
+ this._closeReason = reason;
207
+ this.presence = createPresence({
208
+ onExitComplete: () => {
209
+ this.completeClose();
210
+ }
211
+ });
212
+ this.presence.hide(content);
213
+ } else {
214
+ this.open = false;
215
+ this.isClosing = false;
216
+ }
217
+ }
218
+ /**
219
+ * Opens the dialog.
220
+ */
221
+ show() {
222
+ if (this.open) return;
223
+ const trigger = this.querySelector('[slot="trigger"]');
224
+ if (trigger) {
225
+ this.dialogBehavior?.setTriggerElement(trigger);
226
+ } else if (document.activeElement instanceof HTMLElement) {
227
+ this.dialogBehavior?.setTriggerElement(document.activeElement);
228
+ }
229
+ this.open = true;
230
+ this.dialogBehavior?.open();
231
+ emitEvent(this, StandardEvents.OPEN_CHANGE, {
232
+ detail: { open: true, reason: "trigger" }
233
+ });
234
+ }
235
+ /**
236
+ * Closes the dialog.
237
+ * @param reason - The reason for closing (default: "programmatic")
238
+ */
239
+ close(reason = "programmatic") {
240
+ if (!this.open) return;
241
+ const openChangeEvent = emitEvent(this, StandardEvents.OPEN_CHANGE, {
242
+ detail: { open: false, reason },
243
+ cancelable: true
244
+ });
245
+ if (openChangeEvent.defaultPrevented) {
246
+ return;
247
+ }
248
+ const content = this.querySelector("ds-dialog-content");
249
+ this.dialogBehavior?.close();
250
+ if (this.animated && content && !prefersReducedMotion()) {
251
+ this.isClosing = true;
252
+ this._closeReason = reason;
253
+ this.presence = createPresence({
254
+ onExitComplete: () => {
255
+ this.completeClose();
256
+ }
257
+ });
258
+ this.presence.hide(content);
259
+ } else {
260
+ this.open = false;
261
+ this.isClosing = false;
262
+ }
263
+ }
264
+ /**
265
+ * Completes the close after exit animation.
266
+ * Note: The open-change event was already emitted before animation started.
267
+ */
268
+ completeClose() {
269
+ this.presence?.destroy();
270
+ this.presence = null;
271
+ this.open = false;
272
+ this.isClosing = false;
273
+ }
274
+ cleanup() {
275
+ this.dialogBehavior?.destroy();
276
+ this.dialogBehavior = null;
277
+ this.presence?.destroy();
278
+ this.presence = null;
279
+ }
280
+ async updated(changedProperties) {
281
+ super.updated(changedProperties);
282
+ if (changedProperties.has("open")) {
283
+ const content = this.querySelector("ds-dialog-content");
284
+ if (this.open) {
285
+ await this.updateComplete;
286
+ if (content) {
287
+ content.dataState = "open";
288
+ }
289
+ this.dialogBehavior?.setContentElement(content);
290
+ this.updateContentAccessibility();
291
+ this.backdropElement = this.querySelector(".ds-dialog__backdrop");
292
+ this.backdropElement?.addEventListener("click", this.handleBackdropClick);
293
+ } else {
294
+ this.backdropElement?.removeEventListener("click", this.handleBackdropClick);
295
+ this.backdropElement = null;
296
+ this.dialogBehavior?.setContentElement(null);
297
+ }
298
+ }
299
+ if (changedProperties.has("dialogRole") && this.open) {
300
+ this.updateContentAccessibility();
301
+ }
302
+ if (changedProperties.has("closeOnEscape") || changedProperties.has("closeOnBackdrop")) {
303
+ const wasOpen = this.dialogBehavior?.state.open;
304
+ this.dialogBehavior?.destroy();
305
+ this.initDialogBehavior();
306
+ if (wasOpen) {
307
+ this.dialogBehavior?.open();
308
+ const content = this.querySelector("ds-dialog-content");
309
+ this.dialogBehavior?.setContentElement(content);
310
+ }
311
+ }
312
+ }
313
+ /**
314
+ * Updates accessibility attributes on dialog content.
315
+ */
316
+ updateContentAccessibility() {
317
+ const content = this.querySelector("ds-dialog-content");
318
+ if (!content || !this.dialogBehavior) return;
319
+ const contentProps = this.dialogBehavior.getContentProps();
320
+ content.setAttribute("role", this.dialogRole);
321
+ content.setAttribute("aria-modal", contentProps["aria-modal"]);
322
+ if (!hasRequiredChild(this, "ds-dialog-title") && !this.getAttribute("aria-label")) {
323
+ devWarn(Warnings.dialogMissingTitle("ds-dialog"));
324
+ }
325
+ const title = this.querySelector("ds-dialog-title");
326
+ if (title) {
327
+ const titleProps = this.dialogBehavior.getTitleProps();
328
+ if (!title.id) {
329
+ title.id = titleProps.id;
330
+ }
331
+ content.setAttribute("aria-labelledby", title.id);
332
+ }
333
+ const description = this.querySelector("ds-dialog-description");
334
+ if (description) {
335
+ const descProps = this.dialogBehavior.getDescriptionProps();
336
+ if (!description.id) {
337
+ description.id = descProps.id;
338
+ }
339
+ content.setAttribute("aria-describedby", description.id);
340
+ this.dialogBehavior.setHasDescription(true);
341
+ } else {
342
+ if (title) {
343
+ devWarn(Warnings.dialogMissingDescription("ds-dialog"));
344
+ }
345
+ this.dialogBehavior.setHasDescription(false);
346
+ }
347
+ }
348
+ render() {
349
+ return html4`
350
+ <slot name="trigger"></slot>
351
+ <div
352
+ class="ds-dialog__backdrop"
353
+ ?hidden=${!this.open}
354
+ ?data-closing=${this.isClosing}
355
+ >
356
+ <slot></slot>
357
+ </div>
358
+ `;
359
+ }
360
+ };
361
+ __decorateClass([
362
+ property2({ type: Boolean, reflect: true })
363
+ ], DsDialog.prototype, "open", 2);
364
+ __decorateClass([
365
+ property2({ type: Boolean, attribute: "close-on-escape" })
366
+ ], DsDialog.prototype, "closeOnEscape", 2);
367
+ __decorateClass([
368
+ property2({ type: Boolean, attribute: "close-on-backdrop" })
369
+ ], DsDialog.prototype, "closeOnBackdrop", 2);
370
+ __decorateClass([
371
+ property2({ type: Boolean })
372
+ ], DsDialog.prototype, "animated", 2);
373
+ __decorateClass([
374
+ state3()
375
+ ], DsDialog.prototype, "dialogRole", 2);
376
+ __decorateClass([
377
+ state3()
378
+ ], DsDialog.prototype, "isClosing", 2);
379
+ define("ds-dialog", DsDialog);
380
+
381
+ // src/components/popover/popover-content.ts
382
+ import { html as html5 } from "lit";
383
+ import { property as property3 } from "lit/decorators.js";
384
+ var DsPopoverContent = class extends DSElement {
385
+ constructor() {
386
+ super(...arguments);
387
+ this.id = "";
388
+ this.dataState = "closed";
389
+ }
390
+ connectedCallback() {
391
+ super.connectedCallback();
392
+ if (!this.id) {
393
+ this.id = `popover-content-${crypto.randomUUID().slice(0, 8)}`;
394
+ }
395
+ this.setAttribute("hidden", "");
396
+ }
397
+ render() {
398
+ return html5`
399
+ <div class="ds-popover-content" part="container">
400
+ <slot></slot>
401
+ </div>
402
+ `;
403
+ }
404
+ };
405
+ __decorateClass([
406
+ property3({ type: String, reflect: true })
407
+ ], DsPopoverContent.prototype, "id", 2);
408
+ __decorateClass([
409
+ property3({ type: String, reflect: true, attribute: "data-state" })
410
+ ], DsPopoverContent.prototype, "dataState", 2);
411
+ define("ds-popover-content", DsPopoverContent);
412
+
413
+ // src/components/popover/popover.ts
414
+ import {
415
+ createAnchorPosition,
416
+ createDismissableLayer,
417
+ createPresence as createPresence2,
418
+ prefersReducedMotion as prefersReducedMotion2
419
+ } from "@hypoth-ui/primitives-dom";
420
+ import { html as html6 } from "lit";
421
+ import { property as property4 } from "lit/decorators.js";
422
+ var DsPopover = class extends DSElement {
423
+ constructor() {
424
+ super(...arguments);
425
+ this.open = false;
426
+ this.placement = "bottom";
427
+ this.offset = 8;
428
+ this.flip = true;
429
+ this.closeOnEscape = true;
430
+ this.closeOnOutsideClick = true;
431
+ this.animated = true;
432
+ this.anchorPosition = null;
433
+ this.dismissLayer = null;
434
+ this.presence = null;
435
+ this.triggerElement = null;
436
+ this.resizeObserver = null;
437
+ this.scrollHandler = null;
438
+ this.handleTriggerClick = (event) => {
439
+ const target = event.target;
440
+ const trigger = target.closest('[slot="trigger"]');
441
+ if (trigger && this.contains(trigger)) {
442
+ event.preventDefault();
443
+ this.triggerElement = trigger;
444
+ this.toggle();
445
+ }
446
+ };
447
+ this.handleDismiss = (reason) => {
448
+ if (reason === "escape" && this.closeOnEscape) {
449
+ this.close();
450
+ } else if (reason === "outside-click" && this.closeOnOutsideClick) {
451
+ this.close();
452
+ }
453
+ };
454
+ }
455
+ connectedCallback() {
456
+ super.connectedCallback();
457
+ this.addEventListener("click", this.handleTriggerClick);
458
+ this.updateComplete.then(() => {
459
+ this.setupTriggerAccessibility();
460
+ });
461
+ }
462
+ disconnectedCallback() {
463
+ super.disconnectedCallback();
464
+ this.removeEventListener("click", this.handleTriggerClick);
465
+ this.cleanup();
466
+ }
467
+ /**
468
+ * Opens the popover.
469
+ */
470
+ show() {
471
+ if (this.open) return;
472
+ this.open = true;
473
+ emitEvent(this, StandardEvents.OPEN);
474
+ }
475
+ /**
476
+ * Closes the popover.
477
+ */
478
+ close() {
479
+ if (!this.open) return;
480
+ const content = this.querySelector("ds-popover-content");
481
+ if (this.animated && content && !prefersReducedMotion2()) {
482
+ this.dismissLayer?.deactivate();
483
+ this.dismissLayer = null;
484
+ this.presence = createPresence2({
485
+ onExitComplete: () => {
486
+ this.completeClose();
487
+ }
488
+ });
489
+ this.presence.hide(content);
490
+ } else {
491
+ this.cleanup();
492
+ this.open = false;
493
+ emitEvent(this, StandardEvents.CLOSE);
494
+ this.triggerElement?.focus();
495
+ }
496
+ }
497
+ /**
498
+ * Completes the close after exit animation.
499
+ */
500
+ completeClose() {
501
+ this.cleanup();
502
+ this.open = false;
503
+ emitEvent(this, StandardEvents.CLOSE);
504
+ this.triggerElement?.focus();
505
+ }
506
+ /**
507
+ * Toggles the popover open/closed state.
508
+ */
509
+ toggle() {
510
+ if (this.open) {
511
+ this.close();
512
+ } else {
513
+ this.show();
514
+ }
515
+ }
516
+ setupTriggerAccessibility() {
517
+ const trigger = this.querySelector('[slot="trigger"]');
518
+ const content = this.querySelector("ds-popover-content");
519
+ if (trigger && content) {
520
+ this.triggerElement = trigger;
521
+ trigger.setAttribute("aria-haspopup", "true");
522
+ trigger.setAttribute("aria-expanded", String(this.open));
523
+ trigger.setAttribute("aria-controls", content.id);
524
+ }
525
+ }
526
+ updateTriggerAria() {
527
+ const trigger = this.querySelector('[slot="trigger"]');
528
+ if (trigger) {
529
+ trigger.setAttribute("aria-expanded", String(this.open));
530
+ }
531
+ }
532
+ setupPositioning() {
533
+ const trigger = this.querySelector('[slot="trigger"]');
534
+ const content = this.querySelector("ds-popover-content");
535
+ if (!trigger || !content) return;
536
+ this.anchorPosition = createAnchorPosition({
537
+ anchor: trigger,
538
+ floating: content,
539
+ placement: this.placement,
540
+ offset: this.offset,
541
+ flip: this.flip,
542
+ onPositionChange: (pos) => {
543
+ content.setAttribute("data-placement", pos.placement);
544
+ }
545
+ });
546
+ this.resizeObserver = new ResizeObserver(() => {
547
+ this.anchorPosition?.update();
548
+ });
549
+ this.resizeObserver.observe(trigger);
550
+ this.resizeObserver.observe(content);
551
+ this.scrollHandler = () => {
552
+ this.anchorPosition?.update();
553
+ };
554
+ window.addEventListener("scroll", this.scrollHandler, { passive: true });
555
+ window.addEventListener("resize", this.scrollHandler, { passive: true });
556
+ }
557
+ setupDismissLayer() {
558
+ const content = this.querySelector("ds-popover-content");
559
+ const trigger = this.querySelector('[slot="trigger"]');
560
+ if (!content) return;
561
+ this.dismissLayer = createDismissableLayer({
562
+ container: content,
563
+ excludeElements: trigger ? [trigger] : [],
564
+ onDismiss: this.handleDismiss,
565
+ closeOnEscape: this.closeOnEscape,
566
+ closeOnOutsideClick: this.closeOnOutsideClick
567
+ });
568
+ this.dismissLayer.activate();
569
+ }
570
+ cleanup() {
571
+ this.anchorPosition?.destroy();
572
+ this.anchorPosition = null;
573
+ this.dismissLayer?.deactivate();
574
+ this.dismissLayer = null;
575
+ this.presence?.destroy();
576
+ this.presence = null;
577
+ this.resizeObserver?.disconnect();
578
+ this.resizeObserver = null;
579
+ if (this.scrollHandler) {
580
+ window.removeEventListener("scroll", this.scrollHandler);
581
+ window.removeEventListener("resize", this.scrollHandler);
582
+ this.scrollHandler = null;
583
+ }
584
+ }
585
+ async updated(changedProperties) {
586
+ super.updated(changedProperties);
587
+ if (changedProperties.has("open")) {
588
+ this.updateTriggerAria();
589
+ const content = this.querySelector("ds-popover-content");
590
+ if (this.open) {
591
+ content?.removeAttribute("hidden");
592
+ if (content) {
593
+ content.dataState = "open";
594
+ }
595
+ await this.updateComplete;
596
+ this.setupPositioning();
597
+ this.setupDismissLayer();
598
+ } else {
599
+ content?.setAttribute("hidden", "");
600
+ }
601
+ }
602
+ if (this.open && (changedProperties.has("placement") || changedProperties.has("offset"))) {
603
+ this.cleanup();
604
+ this.setupPositioning();
605
+ this.setupDismissLayer();
606
+ }
607
+ }
608
+ render() {
609
+ return html6`
610
+ <slot name="trigger"></slot>
611
+ <slot></slot>
612
+ `;
613
+ }
614
+ };
615
+ __decorateClass([
616
+ property4({ type: Boolean, reflect: true })
617
+ ], DsPopover.prototype, "open", 2);
618
+ __decorateClass([
619
+ property4({ type: String, reflect: true })
620
+ ], DsPopover.prototype, "placement", 2);
621
+ __decorateClass([
622
+ property4({ type: Number })
623
+ ], DsPopover.prototype, "offset", 2);
624
+ __decorateClass([
625
+ property4({ type: Boolean })
626
+ ], DsPopover.prototype, "flip", 2);
627
+ __decorateClass([
628
+ property4({
629
+ attribute: "close-on-escape",
630
+ converter: {
631
+ fromAttribute: (value) => value !== "false",
632
+ toAttribute: (value) => value ? "" : "false"
633
+ }
634
+ })
635
+ ], DsPopover.prototype, "closeOnEscape", 2);
636
+ __decorateClass([
637
+ property4({
638
+ attribute: "close-on-outside-click",
639
+ converter: {
640
+ fromAttribute: (value) => value !== "false",
641
+ toAttribute: (value) => value ? "" : "false"
642
+ }
643
+ })
644
+ ], DsPopover.prototype, "closeOnOutsideClick", 2);
645
+ __decorateClass([
646
+ property4({ type: Boolean })
647
+ ], DsPopover.prototype, "animated", 2);
648
+ define("ds-popover", DsPopover);
649
+
650
+ // src/components/tooltip/tooltip-content.ts
651
+ import { html as html7 } from "lit";
652
+ import { property as property5 } from "lit/decorators.js";
653
+ var DsTooltipContent = class extends DSElement {
654
+ constructor() {
655
+ super(...arguments);
656
+ this.id = "";
657
+ this.dataState = "closed";
658
+ }
659
+ connectedCallback() {
660
+ super.connectedCallback();
661
+ if (!this.id) {
662
+ this.id = `tooltip-content-${crypto.randomUUID().slice(0, 8)}`;
663
+ }
664
+ this.setAttribute("role", "tooltip");
665
+ this.setAttribute("hidden", "");
666
+ }
667
+ render() {
668
+ return html7`
669
+ <div class="ds-tooltip-content" part="container">
670
+ <slot></slot>
671
+ </div>
672
+ `;
673
+ }
674
+ };
675
+ __decorateClass([
676
+ property5({ type: String, reflect: true })
677
+ ], DsTooltipContent.prototype, "id", 2);
678
+ __decorateClass([
679
+ property5({ type: String, reflect: true, attribute: "data-state" })
680
+ ], DsTooltipContent.prototype, "dataState", 2);
681
+ define("ds-tooltip-content", DsTooltipContent);
682
+
683
+ // src/components/tooltip/tooltip.ts
684
+ import {
685
+ createAnchorPosition as createAnchorPosition2,
686
+ createPresence as createPresence3,
687
+ prefersReducedMotion as prefersReducedMotion3
688
+ } from "@hypoth-ui/primitives-dom";
689
+ import { html as html8 } from "lit";
690
+ import { property as property6 } from "lit/decorators.js";
691
+ var DsTooltip = class extends DSElement {
692
+ constructor() {
693
+ super(...arguments);
694
+ this.open = false;
695
+ this.placement = "top";
696
+ this.offset = 8;
697
+ this.showDelay = 400;
698
+ this.hideDelay = 100;
699
+ this.animated = true;
700
+ this.anchorPosition = null;
701
+ this.presence = null;
702
+ this.showTimeout = null;
703
+ this.hideTimeout = null;
704
+ this.escapeHandler = null;
705
+ this.handleTriggerMouseEnter = () => {
706
+ this.scheduleShow();
707
+ };
708
+ this.handleTriggerMouseLeave = () => {
709
+ this.scheduleHide();
710
+ };
711
+ this.handleTriggerFocusIn = () => {
712
+ this.scheduleShow();
713
+ };
714
+ this.handleTriggerFocusOut = () => {
715
+ this.scheduleHide();
716
+ };
717
+ this.handleContentMouseEnter = () => {
718
+ this.clearTimeouts();
719
+ };
720
+ this.handleContentMouseLeave = () => {
721
+ this.scheduleHide();
722
+ };
723
+ }
724
+ connectedCallback() {
725
+ super.connectedCallback();
726
+ this.updateComplete.then(() => {
727
+ this.setupTriggerListeners();
728
+ this.setupContentListeners();
729
+ this.setupTriggerAccessibility();
730
+ this.setupEscapeHandler();
731
+ });
732
+ }
733
+ disconnectedCallback() {
734
+ super.disconnectedCallback();
735
+ this.cleanup();
736
+ this.removeEscapeHandler();
737
+ }
738
+ /**
739
+ * Shows the tooltip immediately.
740
+ */
741
+ show() {
742
+ this.clearTimeouts();
743
+ if (this.open) return;
744
+ this.open = true;
745
+ }
746
+ /**
747
+ * Hides the tooltip immediately.
748
+ */
749
+ hide() {
750
+ this.clearTimeouts();
751
+ if (!this.open) return;
752
+ this.cleanup();
753
+ this.open = false;
754
+ }
755
+ clearTimeouts() {
756
+ if (this.showTimeout) {
757
+ clearTimeout(this.showTimeout);
758
+ this.showTimeout = null;
759
+ }
760
+ if (this.hideTimeout) {
761
+ clearTimeout(this.hideTimeout);
762
+ this.hideTimeout = null;
763
+ }
764
+ }
765
+ scheduleShow() {
766
+ this.clearTimeouts();
767
+ if (this.open) return;
768
+ this.showTimeout = setTimeout(() => {
769
+ this.open = true;
770
+ this.showTimeout = null;
771
+ }, this.showDelay);
772
+ }
773
+ scheduleHide() {
774
+ this.clearTimeouts();
775
+ if (!this.open) return;
776
+ this.hideTimeout = setTimeout(() => {
777
+ const content = this.querySelector("ds-tooltip-content");
778
+ if (this.animated && content && !prefersReducedMotion3()) {
779
+ this.presence = createPresence3({
780
+ onExitComplete: () => {
781
+ this.cleanup();
782
+ this.open = false;
783
+ }
784
+ });
785
+ this.presence.hide(content);
786
+ } else {
787
+ this.cleanup();
788
+ this.open = false;
789
+ }
790
+ this.hideTimeout = null;
791
+ }, this.hideDelay);
792
+ }
793
+ setupTriggerListeners() {
794
+ const trigger = this.querySelector('[slot="trigger"]');
795
+ if (!trigger) return;
796
+ trigger.addEventListener("mouseenter", this.handleTriggerMouseEnter);
797
+ trigger.addEventListener("mouseleave", this.handleTriggerMouseLeave);
798
+ trigger.addEventListener("focusin", this.handleTriggerFocusIn);
799
+ trigger.addEventListener("focusout", this.handleTriggerFocusOut);
800
+ }
801
+ setupContentListeners() {
802
+ const content = this.querySelector("ds-tooltip-content");
803
+ if (!content) return;
804
+ content.addEventListener("mouseenter", this.handleContentMouseEnter);
805
+ content.addEventListener("mouseleave", this.handleContentMouseLeave);
806
+ }
807
+ setupTriggerAccessibility() {
808
+ const trigger = this.querySelector('[slot="trigger"]');
809
+ const content = this.querySelector("ds-tooltip-content");
810
+ if (trigger && content) {
811
+ trigger.setAttribute("aria-describedby", content.id);
812
+ }
813
+ }
814
+ setupEscapeHandler() {
815
+ this.escapeHandler = (event) => {
816
+ if (event.key === "Escape" && this.open) {
817
+ event.preventDefault();
818
+ this.hide();
819
+ }
820
+ };
821
+ document.addEventListener("keydown", this.escapeHandler);
822
+ }
823
+ removeEscapeHandler() {
824
+ if (this.escapeHandler) {
825
+ document.removeEventListener("keydown", this.escapeHandler);
826
+ this.escapeHandler = null;
827
+ }
828
+ }
829
+ setupPositioning() {
830
+ const trigger = this.querySelector('[slot="trigger"]');
831
+ const content = this.querySelector("ds-tooltip-content");
832
+ if (!trigger || !content) return;
833
+ this.anchorPosition = createAnchorPosition2({
834
+ anchor: trigger,
835
+ floating: content,
836
+ placement: this.placement,
837
+ offset: this.offset,
838
+ flip: true,
839
+ onPositionChange: (pos) => {
840
+ content.setAttribute("data-placement", pos.placement);
841
+ }
842
+ });
843
+ }
844
+ cleanup() {
845
+ this.clearTimeouts();
846
+ this.anchorPosition?.destroy();
847
+ this.anchorPosition = null;
848
+ this.presence?.destroy();
849
+ this.presence = null;
850
+ }
851
+ async updated(changedProperties) {
852
+ super.updated(changedProperties);
853
+ if (changedProperties.has("open")) {
854
+ const content = this.querySelector("ds-tooltip-content");
855
+ if (this.open) {
856
+ content?.removeAttribute("hidden");
857
+ if (content) {
858
+ content.dataState = "open";
859
+ }
860
+ await this.updateComplete;
861
+ this.setupPositioning();
862
+ } else {
863
+ content?.setAttribute("hidden", "");
864
+ }
865
+ }
866
+ }
867
+ render() {
868
+ return html8`
869
+ <slot name="trigger"></slot>
870
+ <slot></slot>
871
+ `;
872
+ }
873
+ };
874
+ __decorateClass([
875
+ property6({ type: Boolean, reflect: true })
876
+ ], DsTooltip.prototype, "open", 2);
877
+ __decorateClass([
878
+ property6({ type: String, reflect: true })
879
+ ], DsTooltip.prototype, "placement", 2);
880
+ __decorateClass([
881
+ property6({ type: Number })
882
+ ], DsTooltip.prototype, "offset", 2);
883
+ __decorateClass([
884
+ property6({ type: Number, attribute: "show-delay" })
885
+ ], DsTooltip.prototype, "showDelay", 2);
886
+ __decorateClass([
887
+ property6({ type: Number, attribute: "hide-delay" })
888
+ ], DsTooltip.prototype, "hideDelay", 2);
889
+ __decorateClass([
890
+ property6({ type: Boolean })
891
+ ], DsTooltip.prototype, "animated", 2);
892
+ define("ds-tooltip", DsTooltip);
893
+
894
+ // src/components/menu/menu-content.ts
895
+ import { html as html9 } from "lit";
896
+ import { property as property7 } from "lit/decorators.js";
897
+ var DsMenuContent = class extends DSElement {
898
+ constructor() {
899
+ super(...arguments);
900
+ this.id = "";
901
+ this.dataState = "closed";
902
+ }
903
+ connectedCallback() {
904
+ super.connectedCallback();
905
+ if (!this.id) {
906
+ this.id = `menu-content-${crypto.randomUUID().slice(0, 8)}`;
907
+ }
908
+ this.setAttribute("role", "menu");
909
+ this.setAttribute("hidden", "");
910
+ }
911
+ render() {
912
+ return html9`
913
+ <div class="ds-menu-content" part="container">
914
+ <slot></slot>
915
+ </div>
916
+ `;
917
+ }
918
+ };
919
+ __decorateClass([
920
+ property7({ type: String, reflect: true })
921
+ ], DsMenuContent.prototype, "id", 2);
922
+ __decorateClass([
923
+ property7({ type: String, reflect: true, attribute: "data-state" })
924
+ ], DsMenuContent.prototype, "dataState", 2);
925
+ define("ds-menu-content", DsMenuContent);
926
+
927
+ // src/components/menu/menu-item.ts
928
+ import { html as html10 } from "lit";
929
+ import { property as property8 } from "lit/decorators.js";
930
+ var DsMenuItem = class extends DSElement {
931
+ constructor() {
932
+ super(...arguments);
933
+ this.disabled = false;
934
+ this.value = "";
935
+ this.handleClick = () => {
936
+ this.select();
937
+ };
938
+ this.handleKeyDown = (event) => {
939
+ if (event.key === "Enter" || event.key === " ") {
940
+ event.preventDefault();
941
+ this.select();
942
+ }
943
+ };
944
+ }
945
+ connectedCallback() {
946
+ super.connectedCallback();
947
+ this.setAttribute("role", "menuitem");
948
+ this.tabIndex = -1;
949
+ this.updateAriaDisabled();
950
+ this.addEventListener("click", this.handleClick);
951
+ this.addEventListener("keydown", this.handleKeyDown);
952
+ }
953
+ disconnectedCallback() {
954
+ super.disconnectedCallback();
955
+ this.removeEventListener("click", this.handleClick);
956
+ this.removeEventListener("keydown", this.handleKeyDown);
957
+ }
958
+ updateAriaDisabled() {
959
+ if (this.disabled) {
960
+ this.setAttribute("aria-disabled", "true");
961
+ } else {
962
+ this.removeAttribute("aria-disabled");
963
+ }
964
+ }
965
+ /**
966
+ * Triggers selection of this item.
967
+ * Emits ds:select event and notifies parent menu to close.
968
+ */
969
+ select() {
970
+ if (this.disabled) return;
971
+ const value = this.value || this.textContent?.trim() || "";
972
+ emitEvent(this, "select", { detail: { value } });
973
+ }
974
+ updated(changedProperties) {
975
+ super.updated(changedProperties);
976
+ if (changedProperties.has("disabled")) {
977
+ this.updateAriaDisabled();
978
+ }
979
+ }
980
+ render() {
981
+ return html10`
982
+ <div class="ds-menu-item" part="container">
983
+ <slot></slot>
984
+ </div>
985
+ `;
986
+ }
987
+ };
988
+ __decorateClass([
989
+ property8({ type: Boolean, reflect: true })
990
+ ], DsMenuItem.prototype, "disabled", 2);
991
+ __decorateClass([
992
+ property8({ type: String })
993
+ ], DsMenuItem.prototype, "value", 2);
994
+ define("ds-menu-item", DsMenuItem);
995
+
996
+ // src/components/menu/menu.ts
997
+ import {
998
+ createAnchorPosition as createAnchorPosition3,
999
+ createDismissableLayer as createDismissableLayer2,
1000
+ createPresence as createPresence4,
1001
+ createRovingFocus,
1002
+ createTypeAhead,
1003
+ prefersReducedMotion as prefersReducedMotion4
1004
+ } from "@hypoth-ui/primitives-dom";
1005
+ import { html as html11 } from "lit";
1006
+ import { property as property9 } from "lit/decorators.js";
1007
+ var DsMenu = class extends DSElement {
1008
+ constructor() {
1009
+ super(...arguments);
1010
+ this.open = false;
1011
+ this.placement = "bottom-start";
1012
+ this.offset = 8;
1013
+ this.flip = true;
1014
+ this.animated = true;
1015
+ this.anchorPosition = null;
1016
+ this.dismissLayer = null;
1017
+ this.presence = null;
1018
+ this.rovingFocus = null;
1019
+ this.typeAhead = null;
1020
+ this.triggerElement = null;
1021
+ this.resizeObserver = null;
1022
+ this.scrollHandler = null;
1023
+ this.focusFirstOnOpen = null;
1024
+ this.handleTriggerClick = (event) => {
1025
+ const target = event.target;
1026
+ const trigger = target.closest('[slot="trigger"]');
1027
+ if (trigger && this.contains(trigger)) {
1028
+ event.preventDefault();
1029
+ this.triggerElement = trigger;
1030
+ this.focusFirstOnOpen = "first";
1031
+ this.toggle();
1032
+ }
1033
+ };
1034
+ this.handleTriggerKeyDown = (event) => {
1035
+ const target = event.target;
1036
+ const trigger = target.closest('[slot="trigger"]');
1037
+ if (!trigger || !this.contains(trigger)) return;
1038
+ this.triggerElement = trigger;
1039
+ switch (event.key) {
1040
+ case "Enter":
1041
+ case " ":
1042
+ event.preventDefault();
1043
+ this.focusFirstOnOpen = "first";
1044
+ this.toggle();
1045
+ break;
1046
+ case "ArrowDown":
1047
+ event.preventDefault();
1048
+ this.focusFirstOnOpen = "first";
1049
+ if (!this.open) this.show();
1050
+ break;
1051
+ case "ArrowUp":
1052
+ event.preventDefault();
1053
+ this.focusFirstOnOpen = "last";
1054
+ if (!this.open) this.show();
1055
+ break;
1056
+ }
1057
+ };
1058
+ this.handleItemSelect = (_event) => {
1059
+ this.close();
1060
+ };
1061
+ this.handleDismiss = () => {
1062
+ this.close();
1063
+ };
1064
+ this.handleTypeAheadKeyDown = (event) => {
1065
+ this.typeAhead?.handleKeyDown(event);
1066
+ };
1067
+ }
1068
+ connectedCallback() {
1069
+ super.connectedCallback();
1070
+ this.addEventListener("click", this.handleTriggerClick);
1071
+ this.addEventListener("keydown", this.handleTriggerKeyDown);
1072
+ this.addEventListener("ds:select", this.handleItemSelect);
1073
+ this.updateComplete.then(() => {
1074
+ this.setupTriggerAccessibility();
1075
+ });
1076
+ }
1077
+ disconnectedCallback() {
1078
+ super.disconnectedCallback();
1079
+ this.removeEventListener("click", this.handleTriggerClick);
1080
+ this.removeEventListener("keydown", this.handleTriggerKeyDown);
1081
+ this.removeEventListener("ds:select", this.handleItemSelect);
1082
+ this.cleanup();
1083
+ }
1084
+ /**
1085
+ * Opens the menu.
1086
+ */
1087
+ show() {
1088
+ if (this.open) return;
1089
+ this.open = true;
1090
+ emitEvent(this, StandardEvents.OPEN);
1091
+ }
1092
+ /**
1093
+ * Closes the menu.
1094
+ */
1095
+ close() {
1096
+ if (!this.open) return;
1097
+ const content = this.querySelector("ds-menu-content");
1098
+ if (this.animated && content && !prefersReducedMotion4()) {
1099
+ this.dismissLayer?.deactivate();
1100
+ this.dismissLayer = null;
1101
+ this.presence = createPresence4({
1102
+ onExitComplete: () => {
1103
+ this.completeClose();
1104
+ }
1105
+ });
1106
+ this.presence.hide(content);
1107
+ } else {
1108
+ this.cleanup();
1109
+ this.open = false;
1110
+ emitEvent(this, StandardEvents.CLOSE);
1111
+ this.triggerElement?.focus();
1112
+ }
1113
+ }
1114
+ /**
1115
+ * Completes the close after exit animation.
1116
+ */
1117
+ completeClose() {
1118
+ this.cleanup();
1119
+ this.open = false;
1120
+ emitEvent(this, StandardEvents.CLOSE);
1121
+ this.triggerElement?.focus();
1122
+ }
1123
+ /**
1124
+ * Toggles the menu open/closed state.
1125
+ */
1126
+ toggle() {
1127
+ if (this.open) {
1128
+ this.close();
1129
+ } else {
1130
+ this.show();
1131
+ }
1132
+ }
1133
+ setupTriggerAccessibility() {
1134
+ const trigger = this.querySelector('[slot="trigger"]');
1135
+ const content = this.querySelector("ds-menu-content");
1136
+ if (trigger && content) {
1137
+ this.triggerElement = trigger;
1138
+ trigger.setAttribute("aria-haspopup", "menu");
1139
+ trigger.setAttribute("aria-expanded", String(this.open));
1140
+ trigger.setAttribute("aria-controls", content.id);
1141
+ }
1142
+ }
1143
+ updateTriggerAria() {
1144
+ const trigger = this.querySelector('[slot="trigger"]');
1145
+ if (trigger) {
1146
+ trigger.setAttribute("aria-expanded", String(this.open));
1147
+ }
1148
+ }
1149
+ setupPositioning() {
1150
+ const trigger = this.querySelector('[slot="trigger"]');
1151
+ const content = this.querySelector("ds-menu-content");
1152
+ if (!trigger || !content) return;
1153
+ this.anchorPosition = createAnchorPosition3({
1154
+ anchor: trigger,
1155
+ floating: content,
1156
+ placement: this.placement,
1157
+ offset: this.offset,
1158
+ flip: this.flip,
1159
+ onPositionChange: (pos) => {
1160
+ content.setAttribute("data-placement", pos.placement);
1161
+ }
1162
+ });
1163
+ this.resizeObserver = new ResizeObserver(() => {
1164
+ this.anchorPosition?.update();
1165
+ });
1166
+ this.resizeObserver.observe(trigger);
1167
+ this.resizeObserver.observe(content);
1168
+ this.scrollHandler = () => {
1169
+ this.anchorPosition?.update();
1170
+ };
1171
+ window.addEventListener("scroll", this.scrollHandler, { passive: true });
1172
+ window.addEventListener("resize", this.scrollHandler, { passive: true });
1173
+ }
1174
+ setupDismissLayer() {
1175
+ const content = this.querySelector("ds-menu-content");
1176
+ const trigger = this.querySelector('[slot="trigger"]');
1177
+ if (!content) return;
1178
+ this.dismissLayer = createDismissableLayer2({
1179
+ container: content,
1180
+ excludeElements: trigger ? [trigger] : [],
1181
+ onDismiss: this.handleDismiss,
1182
+ closeOnEscape: true,
1183
+ closeOnOutsideClick: true
1184
+ });
1185
+ this.dismissLayer.activate();
1186
+ }
1187
+ setupRovingFocus() {
1188
+ const content = this.querySelector("ds-menu-content");
1189
+ if (!content) return;
1190
+ this.rovingFocus = createRovingFocus({
1191
+ container: content,
1192
+ selector: "ds-menu-item:not([disabled])",
1193
+ direction: "vertical",
1194
+ loop: true,
1195
+ skipDisabled: true
1196
+ });
1197
+ }
1198
+ setupTypeAhead() {
1199
+ const content = this.querySelector("ds-menu-content");
1200
+ if (!content) return;
1201
+ this.typeAhead = createTypeAhead({
1202
+ items: () => Array.from(content.querySelectorAll("ds-menu-item:not([disabled])")),
1203
+ getText: (item) => item.textContent?.trim() || "",
1204
+ onMatch: (_item, index) => {
1205
+ this.rovingFocus?.setFocusedIndex(index);
1206
+ }
1207
+ });
1208
+ content.addEventListener("keydown", this.handleTypeAheadKeyDown);
1209
+ }
1210
+ focusInitialItem() {
1211
+ const content = this.querySelector("ds-menu-content");
1212
+ if (!content) return;
1213
+ const items = content.querySelectorAll("ds-menu-item:not([disabled])");
1214
+ if (items.length === 0) return;
1215
+ if (this.focusFirstOnOpen === "last") {
1216
+ const lastIndex = items.length - 1;
1217
+ this.rovingFocus?.setFocusedIndex(lastIndex);
1218
+ } else {
1219
+ this.rovingFocus?.setFocusedIndex(0);
1220
+ }
1221
+ this.focusFirstOnOpen = null;
1222
+ }
1223
+ cleanup() {
1224
+ const content = this.querySelector("ds-menu-content");
1225
+ if (content) {
1226
+ content.removeEventListener("keydown", this.handleTypeAheadKeyDown);
1227
+ }
1228
+ this.anchorPosition?.destroy();
1229
+ this.anchorPosition = null;
1230
+ this.dismissLayer?.deactivate();
1231
+ this.dismissLayer = null;
1232
+ this.presence?.destroy();
1233
+ this.presence = null;
1234
+ this.rovingFocus?.destroy();
1235
+ this.rovingFocus = null;
1236
+ this.typeAhead?.reset();
1237
+ this.typeAhead = null;
1238
+ this.resizeObserver?.disconnect();
1239
+ this.resizeObserver = null;
1240
+ if (this.scrollHandler) {
1241
+ window.removeEventListener("scroll", this.scrollHandler);
1242
+ window.removeEventListener("resize", this.scrollHandler);
1243
+ this.scrollHandler = null;
1244
+ }
1245
+ }
1246
+ async updated(changedProperties) {
1247
+ super.updated(changedProperties);
1248
+ if (changedProperties.has("open")) {
1249
+ this.updateTriggerAria();
1250
+ const content = this.querySelector("ds-menu-content");
1251
+ if (this.open) {
1252
+ content?.removeAttribute("hidden");
1253
+ if (content) {
1254
+ content.dataState = "open";
1255
+ }
1256
+ await this.updateComplete;
1257
+ this.setupPositioning();
1258
+ this.setupDismissLayer();
1259
+ this.setupRovingFocus();
1260
+ this.setupTypeAhead();
1261
+ this.focusInitialItem();
1262
+ } else {
1263
+ content?.setAttribute("hidden", "");
1264
+ }
1265
+ }
1266
+ if (this.open && (changedProperties.has("placement") || changedProperties.has("offset"))) {
1267
+ this.cleanup();
1268
+ this.setupPositioning();
1269
+ this.setupDismissLayer();
1270
+ this.setupRovingFocus();
1271
+ this.setupTypeAhead();
1272
+ }
1273
+ }
1274
+ render() {
1275
+ return html11`
1276
+ <slot name="trigger"></slot>
1277
+ <slot></slot>
1278
+ `;
1279
+ }
1280
+ };
1281
+ __decorateClass([
1282
+ property9({ type: Boolean, reflect: true })
1283
+ ], DsMenu.prototype, "open", 2);
1284
+ __decorateClass([
1285
+ property9({ type: String, reflect: true })
1286
+ ], DsMenu.prototype, "placement", 2);
1287
+ __decorateClass([
1288
+ property9({ type: Number })
1289
+ ], DsMenu.prototype, "offset", 2);
1290
+ __decorateClass([
1291
+ property9({ type: Boolean })
1292
+ ], DsMenu.prototype, "flip", 2);
1293
+ __decorateClass([
1294
+ property9({ type: Boolean })
1295
+ ], DsMenu.prototype, "animated", 2);
1296
+ define("ds-menu", DsMenu);
1297
+
1298
+ // src/components/alert-dialog/alert-dialog-content.ts
1299
+ import { html as html12 } from "lit";
1300
+ import { property as property10 } from "lit/decorators.js";
1301
+ var DsAlertDialogContent = class extends DSElement {
1302
+ constructor() {
1303
+ super(...arguments);
1304
+ this.size = "md";
1305
+ this.dataState = "closed";
1306
+ }
1307
+ connectedCallback() {
1308
+ super.connectedCallback();
1309
+ }
1310
+ render() {
1311
+ return html12`<slot></slot>`;
1312
+ }
1313
+ };
1314
+ __decorateClass([
1315
+ property10({ reflect: true })
1316
+ ], DsAlertDialogContent.prototype, "size", 2);
1317
+ __decorateClass([
1318
+ property10({ attribute: "data-state", reflect: true })
1319
+ ], DsAlertDialogContent.prototype, "dataState", 2);
1320
+ define("ds-alert-dialog-content", DsAlertDialogContent);
1321
+
1322
+ // src/components/alert-dialog/alert-dialog-header.ts
1323
+ import { html as html13 } from "lit";
1324
+ var DsAlertDialogHeader = class extends DSElement {
1325
+ render() {
1326
+ return html13`<slot></slot>`;
1327
+ }
1328
+ };
1329
+ define("ds-alert-dialog-header", DsAlertDialogHeader);
1330
+
1331
+ // src/components/alert-dialog/alert-dialog-footer.ts
1332
+ import { html as html14 } from "lit";
1333
+ var DsAlertDialogFooter = class extends DSElement {
1334
+ render() {
1335
+ return html14`<slot></slot>`;
1336
+ }
1337
+ };
1338
+ define("ds-alert-dialog-footer", DsAlertDialogFooter);
1339
+
1340
+ // src/components/alert-dialog/alert-dialog-title.ts
1341
+ import { html as html15 } from "lit";
1342
+ var DsAlertDialogTitle = class extends DSElement {
1343
+ connectedCallback() {
1344
+ super.connectedCallback();
1345
+ if (!this.id) {
1346
+ this.id = `alert-dialog-title-${crypto.randomUUID().slice(0, 8)}`;
1347
+ }
1348
+ }
1349
+ render() {
1350
+ return html15`<slot></slot>`;
1351
+ }
1352
+ };
1353
+ define("ds-alert-dialog-title", DsAlertDialogTitle);
1354
+
1355
+ // src/components/alert-dialog/alert-dialog-description.ts
1356
+ import { html as html16 } from "lit";
1357
+ var DsAlertDialogDescription = class extends DSElement {
1358
+ connectedCallback() {
1359
+ super.connectedCallback();
1360
+ if (!this.id) {
1361
+ this.id = `alert-dialog-desc-${crypto.randomUUID().slice(0, 8)}`;
1362
+ }
1363
+ }
1364
+ render() {
1365
+ return html16`<slot></slot>`;
1366
+ }
1367
+ };
1368
+ define("ds-alert-dialog-description", DsAlertDialogDescription);
1369
+
1370
+ // src/components/alert-dialog/alert-dialog-action.ts
1371
+ import { html as html17 } from "lit";
1372
+ var DsAlertDialogAction = class extends DSElement {
1373
+ constructor() {
1374
+ super(...arguments);
1375
+ this.handleClick = () => {
1376
+ emitEvent(this, "ds:alert-dialog-action", { bubbles: true });
1377
+ };
1378
+ }
1379
+ connectedCallback() {
1380
+ super.connectedCallback();
1381
+ this.addEventListener("click", this.handleClick);
1382
+ }
1383
+ disconnectedCallback() {
1384
+ super.disconnectedCallback();
1385
+ this.removeEventListener("click", this.handleClick);
1386
+ }
1387
+ render() {
1388
+ return html17`<slot></slot>`;
1389
+ }
1390
+ };
1391
+ define("ds-alert-dialog-action", DsAlertDialogAction);
1392
+
1393
+ // src/components/alert-dialog/alert-dialog-cancel.ts
1394
+ import { html as html18 } from "lit";
1395
+ var DsAlertDialogCancel = class extends DSElement {
1396
+ constructor() {
1397
+ super(...arguments);
1398
+ this.handleClick = () => {
1399
+ emitEvent(this, "ds:alert-dialog-cancel", { bubbles: true });
1400
+ };
1401
+ }
1402
+ connectedCallback() {
1403
+ super.connectedCallback();
1404
+ this.addEventListener("click", this.handleClick);
1405
+ }
1406
+ disconnectedCallback() {
1407
+ super.disconnectedCallback();
1408
+ this.removeEventListener("click", this.handleClick);
1409
+ }
1410
+ render() {
1411
+ return html18`<slot></slot>`;
1412
+ }
1413
+ };
1414
+ define("ds-alert-dialog-cancel", DsAlertDialogCancel);
1415
+
1416
+ // src/components/alert-dialog/alert-dialog.ts
1417
+ import {
1418
+ createDialogBehavior as createDialogBehavior2,
1419
+ createPresence as createPresence5,
1420
+ prefersReducedMotion as prefersReducedMotion5
1421
+ } from "@hypoth-ui/primitives-dom";
1422
+ import { html as html19 } from "lit";
1423
+ import { property as property11, state as state4 } from "lit/decorators.js";
1424
+ var DsAlertDialog = class extends DSElement {
1425
+ constructor() {
1426
+ super(...arguments);
1427
+ this.open = false;
1428
+ this.animated = true;
1429
+ this.isClosing = false;
1430
+ this.dialogBehavior = null;
1431
+ this.presence = null;
1432
+ this.handleTriggerClick = (event) => {
1433
+ const target = event.target;
1434
+ const trigger = target.closest('[slot="trigger"]');
1435
+ if (trigger && this.contains(trigger)) {
1436
+ this.dialogBehavior?.setTriggerElement(trigger);
1437
+ this.show();
1438
+ }
1439
+ };
1440
+ this.handleAction = () => {
1441
+ this.close();
1442
+ };
1443
+ this.handleCancel = () => {
1444
+ this.close();
1445
+ };
1446
+ }
1447
+ connectedCallback() {
1448
+ super.connectedCallback();
1449
+ this.addEventListener("click", this.handleTriggerClick);
1450
+ this.addEventListener("ds:alert-dialog-action", this.handleAction);
1451
+ this.addEventListener("ds:alert-dialog-cancel", this.handleCancel);
1452
+ this.initDialogBehavior();
1453
+ }
1454
+ disconnectedCallback() {
1455
+ super.disconnectedCallback();
1456
+ this.removeEventListener("click", this.handleTriggerClick);
1457
+ this.removeEventListener("ds:alert-dialog-action", this.handleAction);
1458
+ this.removeEventListener("ds:alert-dialog-cancel", this.handleCancel);
1459
+ this.cleanup();
1460
+ }
1461
+ /**
1462
+ * Initializes the dialog behavior primitive.
1463
+ * AlertDialog uses role="alertdialog" and disables dismiss on escape/outside click.
1464
+ */
1465
+ initDialogBehavior() {
1466
+ this.dialogBehavior = createDialogBehavior2({
1467
+ defaultOpen: this.open,
1468
+ role: "alertdialog",
1469
+ closeOnEscape: false,
1470
+ // AlertDialog does NOT close on escape
1471
+ closeOnOutsideClick: false,
1472
+ // AlertDialog does NOT close on outside click
1473
+ onOpenChange: () => {
1474
+ }
1475
+ });
1476
+ const trigger = this.querySelector('[slot="trigger"]');
1477
+ if (trigger) {
1478
+ this.dialogBehavior.setTriggerElement(trigger);
1479
+ }
1480
+ }
1481
+ /**
1482
+ * Opens the alert dialog.
1483
+ */
1484
+ show() {
1485
+ if (this.open) return;
1486
+ const trigger = this.querySelector('[slot="trigger"]');
1487
+ if (trigger) {
1488
+ this.dialogBehavior?.setTriggerElement(trigger);
1489
+ } else if (document.activeElement instanceof HTMLElement) {
1490
+ this.dialogBehavior?.setTriggerElement(document.activeElement);
1491
+ }
1492
+ this.open = true;
1493
+ this.dialogBehavior?.open();
1494
+ emitEvent(this, StandardEvents.OPEN);
1495
+ }
1496
+ /**
1497
+ * Closes the alert dialog.
1498
+ */
1499
+ close() {
1500
+ if (!this.open) return;
1501
+ const content = this.querySelector("ds-alert-dialog-content");
1502
+ this.dialogBehavior?.close();
1503
+ if (this.animated && content && !prefersReducedMotion5()) {
1504
+ this.isClosing = true;
1505
+ this.presence = createPresence5({
1506
+ onExitComplete: () => {
1507
+ this.completeClose();
1508
+ }
1509
+ });
1510
+ this.presence.hide(content);
1511
+ } else {
1512
+ this.open = false;
1513
+ this.isClosing = false;
1514
+ emitEvent(this, StandardEvents.CLOSE);
1515
+ }
1516
+ }
1517
+ /**
1518
+ * Completes the close after exit animation.
1519
+ */
1520
+ completeClose() {
1521
+ this.presence?.destroy();
1522
+ this.presence = null;
1523
+ this.open = false;
1524
+ this.isClosing = false;
1525
+ emitEvent(this, StandardEvents.CLOSE);
1526
+ }
1527
+ cleanup() {
1528
+ this.dialogBehavior?.destroy();
1529
+ this.dialogBehavior = null;
1530
+ this.presence?.destroy();
1531
+ this.presence = null;
1532
+ }
1533
+ async updated(changedProperties) {
1534
+ super.updated(changedProperties);
1535
+ if (changedProperties.has("open")) {
1536
+ const content = this.querySelector("ds-alert-dialog-content");
1537
+ if (this.open) {
1538
+ await this.updateComplete;
1539
+ if (content) {
1540
+ content.dataState = "open";
1541
+ }
1542
+ this.dialogBehavior?.setContentElement(content);
1543
+ this.updateContentAccessibility();
1544
+ } else {
1545
+ this.dialogBehavior?.setContentElement(null);
1546
+ }
1547
+ }
1548
+ }
1549
+ /**
1550
+ * Updates accessibility attributes on alert dialog content.
1551
+ */
1552
+ updateContentAccessibility() {
1553
+ const content = this.querySelector("ds-alert-dialog-content");
1554
+ if (!content || !this.dialogBehavior) return;
1555
+ const contentProps = this.dialogBehavior.getContentProps();
1556
+ content.setAttribute("role", "alertdialog");
1557
+ content.setAttribute("aria-modal", contentProps["aria-modal"]);
1558
+ if (!hasRequiredChild(this, "ds-alert-dialog-title") && !this.getAttribute("aria-label")) {
1559
+ devWarn(Warnings.dialogMissingTitle("ds-alert-dialog"));
1560
+ }
1561
+ const title = this.querySelector("ds-alert-dialog-title");
1562
+ if (title) {
1563
+ const titleProps = this.dialogBehavior.getTitleProps();
1564
+ if (!title.id) {
1565
+ title.id = titleProps.id;
1566
+ }
1567
+ content.setAttribute("aria-labelledby", title.id);
1568
+ }
1569
+ const description = this.querySelector("ds-alert-dialog-description");
1570
+ if (description) {
1571
+ const descProps = this.dialogBehavior.getDescriptionProps();
1572
+ if (!description.id) {
1573
+ description.id = descProps.id;
1574
+ }
1575
+ content.setAttribute("aria-describedby", description.id);
1576
+ this.dialogBehavior.setHasDescription(true);
1577
+ } else {
1578
+ if (title) {
1579
+ devWarn(Warnings.dialogMissingDescription("ds-alert-dialog"));
1580
+ }
1581
+ this.dialogBehavior.setHasDescription(false);
1582
+ }
1583
+ }
1584
+ render() {
1585
+ return html19`
1586
+ <slot name="trigger"></slot>
1587
+ <div
1588
+ class="ds-alert-dialog__backdrop"
1589
+ ?hidden=${!this.open}
1590
+ ?data-closing=${this.isClosing}
1591
+ >
1592
+ <slot></slot>
1593
+ </div>
1594
+ `;
1595
+ }
1596
+ };
1597
+ __decorateClass([
1598
+ property11({ type: Boolean, reflect: true })
1599
+ ], DsAlertDialog.prototype, "open", 2);
1600
+ __decorateClass([
1601
+ property11({ type: Boolean })
1602
+ ], DsAlertDialog.prototype, "animated", 2);
1603
+ __decorateClass([
1604
+ state4()
1605
+ ], DsAlertDialog.prototype, "isClosing", 2);
1606
+ define("ds-alert-dialog", DsAlertDialog);
1607
+
1608
+ // src/components/alert-dialog/alert-dialog-trigger.ts
1609
+ import { html as html20 } from "lit";
1610
+ var DsAlertDialogTrigger = class extends DSElement {
1611
+ constructor() {
1612
+ super(...arguments);
1613
+ this.handleClick = () => {
1614
+ const alertDialog = this.closest("ds-alert-dialog");
1615
+ alertDialog?.show();
1616
+ };
1617
+ }
1618
+ connectedCallback() {
1619
+ super.connectedCallback();
1620
+ this.setAttribute("slot", "trigger");
1621
+ this.addEventListener("click", this.handleClick);
1622
+ }
1623
+ disconnectedCallback() {
1624
+ super.disconnectedCallback();
1625
+ this.removeEventListener("click", this.handleClick);
1626
+ }
1627
+ render() {
1628
+ return html20`<slot></slot>`;
1629
+ }
1630
+ };
1631
+ define("ds-alert-dialog-trigger", DsAlertDialogTrigger);
1632
+
1633
+ // src/components/sheet/sheet-content.ts
1634
+ import { html as html21 } from "lit";
1635
+ import { property as property12 } from "lit/decorators.js";
1636
+ var DsSheetContent = class extends DSElement {
1637
+ constructor() {
1638
+ super(...arguments);
1639
+ this.side = "right";
1640
+ this.size = "md";
1641
+ this.dataState = "closed";
1642
+ }
1643
+ connectedCallback() {
1644
+ super.connectedCallback();
1645
+ }
1646
+ render() {
1647
+ return html21`<slot></slot>`;
1648
+ }
1649
+ };
1650
+ __decorateClass([
1651
+ property12({ reflect: true })
1652
+ ], DsSheetContent.prototype, "side", 2);
1653
+ __decorateClass([
1654
+ property12({ reflect: true })
1655
+ ], DsSheetContent.prototype, "size", 2);
1656
+ __decorateClass([
1657
+ property12({ attribute: "data-state", reflect: true })
1658
+ ], DsSheetContent.prototype, "dataState", 2);
1659
+ define("ds-sheet-content", DsSheetContent);
1660
+
1661
+ // src/components/sheet/sheet-overlay.ts
1662
+ import { html as html22 } from "lit";
1663
+ var DsSheetOverlay = class extends DSElement {
1664
+ render() {
1665
+ return html22``;
1666
+ }
1667
+ };
1668
+ define("ds-sheet-overlay", DsSheetOverlay);
1669
+
1670
+ // src/components/sheet/sheet-header.ts
1671
+ import { html as html23 } from "lit";
1672
+ var DsSheetHeader = class extends DSElement {
1673
+ render() {
1674
+ return html23`<slot></slot>`;
1675
+ }
1676
+ };
1677
+ define("ds-sheet-header", DsSheetHeader);
1678
+
1679
+ // src/components/sheet/sheet-footer.ts
1680
+ import { html as html24 } from "lit";
1681
+ var DsSheetFooter = class extends DSElement {
1682
+ render() {
1683
+ return html24`<slot></slot>`;
1684
+ }
1685
+ };
1686
+ define("ds-sheet-footer", DsSheetFooter);
1687
+
1688
+ // src/components/sheet/sheet-title.ts
1689
+ import { html as html25 } from "lit";
1690
+ var DsSheetTitle = class extends DSElement {
1691
+ connectedCallback() {
1692
+ super.connectedCallback();
1693
+ if (!this.id) {
1694
+ this.id = `sheet-title-${crypto.randomUUID().slice(0, 8)}`;
1695
+ }
1696
+ }
1697
+ render() {
1698
+ return html25`<slot></slot>`;
1699
+ }
1700
+ };
1701
+ define("ds-sheet-title", DsSheetTitle);
1702
+
1703
+ // src/components/sheet/sheet-description.ts
1704
+ import { html as html26 } from "lit";
1705
+ var DsSheetDescription = class extends DSElement {
1706
+ connectedCallback() {
1707
+ super.connectedCallback();
1708
+ if (!this.id) {
1709
+ this.id = `sheet-desc-${crypto.randomUUID().slice(0, 8)}`;
1710
+ }
1711
+ }
1712
+ render() {
1713
+ return html26`<slot></slot>`;
1714
+ }
1715
+ };
1716
+ define("ds-sheet-description", DsSheetDescription);
1717
+
1718
+ // src/components/sheet/sheet-close.ts
1719
+ import { html as html27 } from "lit";
1720
+ var DsSheetClose = class extends DSElement {
1721
+ constructor() {
1722
+ super(...arguments);
1723
+ this.handleClick = () => {
1724
+ emitEvent(this, "ds:sheet-close", { bubbles: true });
1725
+ };
1726
+ }
1727
+ connectedCallback() {
1728
+ super.connectedCallback();
1729
+ this.addEventListener("click", this.handleClick);
1730
+ }
1731
+ disconnectedCallback() {
1732
+ super.disconnectedCallback();
1733
+ this.removeEventListener("click", this.handleClick);
1734
+ }
1735
+ render() {
1736
+ return html27`<slot></slot>`;
1737
+ }
1738
+ };
1739
+ define("ds-sheet-close", DsSheetClose);
1740
+
1741
+ // src/components/sheet/sheet.ts
1742
+ import {
1743
+ createDialogBehavior as createDialogBehavior3,
1744
+ createPresence as createPresence6,
1745
+ prefersReducedMotion as prefersReducedMotion6
1746
+ } from "@hypoth-ui/primitives-dom";
1747
+ import { html as html28 } from "lit";
1748
+ import { property as property13, state as state5 } from "lit/decorators.js";
1749
+ var DsSheet = class extends DSElement {
1750
+ constructor() {
1751
+ super(...arguments);
1752
+ this.open = false;
1753
+ this.closeOnEscape = true;
1754
+ this.closeOnOverlay = true;
1755
+ this.animated = true;
1756
+ this.isClosing = false;
1757
+ this.dialogBehavior = null;
1758
+ this.presence = null;
1759
+ this.handleTriggerClick = (event) => {
1760
+ const target = event.target;
1761
+ const trigger = target.closest('[slot="trigger"]');
1762
+ if (trigger && this.contains(trigger)) {
1763
+ this.dialogBehavior?.setTriggerElement(trigger);
1764
+ this.show();
1765
+ }
1766
+ };
1767
+ this.handleCloseRequest = () => {
1768
+ this.close();
1769
+ };
1770
+ }
1771
+ connectedCallback() {
1772
+ super.connectedCallback();
1773
+ this.addEventListener("click", this.handleTriggerClick);
1774
+ this.addEventListener("ds:sheet-close", this.handleCloseRequest);
1775
+ this.initDialogBehavior();
1776
+ }
1777
+ disconnectedCallback() {
1778
+ super.disconnectedCallback();
1779
+ this.removeEventListener("click", this.handleTriggerClick);
1780
+ this.removeEventListener("ds:sheet-close", this.handleCloseRequest);
1781
+ this.cleanup();
1782
+ }
1783
+ /**
1784
+ * Initializes the dialog behavior primitive.
1785
+ */
1786
+ initDialogBehavior() {
1787
+ this.dialogBehavior = createDialogBehavior3({
1788
+ defaultOpen: this.open,
1789
+ role: "dialog",
1790
+ closeOnEscape: this.closeOnEscape,
1791
+ closeOnOutsideClick: this.closeOnOverlay,
1792
+ onOpenChange: (open) => {
1793
+ if (!open && this.open) {
1794
+ this.handleBehaviorClose();
1795
+ }
1796
+ }
1797
+ });
1798
+ const trigger = this.querySelector('[slot="trigger"]');
1799
+ if (trigger) {
1800
+ this.dialogBehavior.setTriggerElement(trigger);
1801
+ }
1802
+ }
1803
+ /**
1804
+ * Handles close triggered by the behavior (escape/outside click).
1805
+ */
1806
+ handleBehaviorClose() {
1807
+ const content = this.querySelector("ds-sheet-content");
1808
+ if (this.animated && content && !prefersReducedMotion6()) {
1809
+ this.isClosing = true;
1810
+ this.presence = createPresence6({
1811
+ onExitComplete: () => {
1812
+ this.completeClose();
1813
+ }
1814
+ });
1815
+ this.presence.hide(content);
1816
+ } else {
1817
+ this.open = false;
1818
+ this.isClosing = false;
1819
+ emitEvent(this, StandardEvents.CLOSE);
1820
+ }
1821
+ }
1822
+ /**
1823
+ * Opens the sheet.
1824
+ */
1825
+ show() {
1826
+ if (this.open) return;
1827
+ const trigger = this.querySelector('[slot="trigger"]');
1828
+ if (trigger) {
1829
+ this.dialogBehavior?.setTriggerElement(trigger);
1830
+ } else if (document.activeElement instanceof HTMLElement) {
1831
+ this.dialogBehavior?.setTriggerElement(document.activeElement);
1832
+ }
1833
+ this.open = true;
1834
+ this.dialogBehavior?.open();
1835
+ emitEvent(this, StandardEvents.OPEN);
1836
+ }
1837
+ /**
1838
+ * Closes the sheet.
1839
+ */
1840
+ close() {
1841
+ if (!this.open) return;
1842
+ const content = this.querySelector("ds-sheet-content");
1843
+ this.dialogBehavior?.close();
1844
+ if (this.animated && content && !prefersReducedMotion6()) {
1845
+ this.isClosing = true;
1846
+ this.presence = createPresence6({
1847
+ onExitComplete: () => {
1848
+ this.completeClose();
1849
+ }
1850
+ });
1851
+ this.presence.hide(content);
1852
+ } else {
1853
+ this.open = false;
1854
+ this.isClosing = false;
1855
+ emitEvent(this, StandardEvents.CLOSE);
1856
+ }
1857
+ }
1858
+ /**
1859
+ * Completes the close after exit animation.
1860
+ */
1861
+ completeClose() {
1862
+ this.presence?.destroy();
1863
+ this.presence = null;
1864
+ this.open = false;
1865
+ this.isClosing = false;
1866
+ emitEvent(this, StandardEvents.CLOSE);
1867
+ }
1868
+ cleanup() {
1869
+ this.dialogBehavior?.destroy();
1870
+ this.dialogBehavior = null;
1871
+ this.presence?.destroy();
1872
+ this.presence = null;
1873
+ }
1874
+ async updated(changedProperties) {
1875
+ super.updated(changedProperties);
1876
+ if (changedProperties.has("open")) {
1877
+ const content = this.querySelector("ds-sheet-content");
1878
+ if (this.open) {
1879
+ await this.updateComplete;
1880
+ if (content) {
1881
+ content.dataState = "open";
1882
+ }
1883
+ this.dialogBehavior?.setContentElement(content);
1884
+ this.updateContentAccessibility();
1885
+ } else {
1886
+ this.dialogBehavior?.setContentElement(null);
1887
+ }
1888
+ }
1889
+ if (changedProperties.has("closeOnEscape") || changedProperties.has("closeOnOverlay")) {
1890
+ const wasOpen = this.dialogBehavior?.state.open;
1891
+ this.dialogBehavior?.destroy();
1892
+ this.initDialogBehavior();
1893
+ if (wasOpen) {
1894
+ this.dialogBehavior?.open();
1895
+ const content = this.querySelector("ds-sheet-content");
1896
+ this.dialogBehavior?.setContentElement(content);
1897
+ }
1898
+ }
1899
+ }
1900
+ /**
1901
+ * Updates accessibility attributes on sheet content.
1902
+ */
1903
+ updateContentAccessibility() {
1904
+ const content = this.querySelector("ds-sheet-content");
1905
+ if (!content || !this.dialogBehavior) return;
1906
+ const contentProps = this.dialogBehavior.getContentProps();
1907
+ content.setAttribute("role", "dialog");
1908
+ content.setAttribute("aria-modal", contentProps["aria-modal"]);
1909
+ if (!hasRequiredChild(this, "ds-sheet-title") && !this.getAttribute("aria-label")) {
1910
+ devWarn(Warnings.dialogMissingTitle("ds-sheet"));
1911
+ }
1912
+ const title = this.querySelector("ds-sheet-title");
1913
+ if (title) {
1914
+ const titleProps = this.dialogBehavior.getTitleProps();
1915
+ if (!title.id) {
1916
+ title.id = titleProps.id;
1917
+ }
1918
+ content.setAttribute("aria-labelledby", title.id);
1919
+ }
1920
+ const description = this.querySelector("ds-sheet-description");
1921
+ if (description) {
1922
+ const descProps = this.dialogBehavior.getDescriptionProps();
1923
+ if (!description.id) {
1924
+ description.id = descProps.id;
1925
+ }
1926
+ content.setAttribute("aria-describedby", description.id);
1927
+ this.dialogBehavior.setHasDescription(true);
1928
+ } else {
1929
+ if (title) {
1930
+ devWarn(Warnings.dialogMissingDescription("ds-sheet"));
1931
+ }
1932
+ this.dialogBehavior.setHasDescription(false);
1933
+ }
1934
+ }
1935
+ render() {
1936
+ return html28`
1937
+ <slot name="trigger"></slot>
1938
+ <ds-sheet-overlay
1939
+ ?hidden=${!this.open}
1940
+ ?data-closing=${this.isClosing}
1941
+ @click=${this.closeOnOverlay ? this.handleCloseRequest : void 0}
1942
+ ></ds-sheet-overlay>
1943
+ <slot ?hidden=${!this.open}></slot>
1944
+ `;
1945
+ }
1946
+ };
1947
+ __decorateClass([
1948
+ property13({ type: Boolean, reflect: true })
1949
+ ], DsSheet.prototype, "open", 2);
1950
+ __decorateClass([
1951
+ property13({ type: Boolean, attribute: "close-on-escape" })
1952
+ ], DsSheet.prototype, "closeOnEscape", 2);
1953
+ __decorateClass([
1954
+ property13({ type: Boolean, attribute: "close-on-overlay" })
1955
+ ], DsSheet.prototype, "closeOnOverlay", 2);
1956
+ __decorateClass([
1957
+ property13({ type: Boolean })
1958
+ ], DsSheet.prototype, "animated", 2);
1959
+ __decorateClass([
1960
+ state5()
1961
+ ], DsSheet.prototype, "isClosing", 2);
1962
+ define("ds-sheet", DsSheet);
1963
+
1964
+ // src/components/drawer/drawer-content.ts
1965
+ import { html as html29 } from "lit";
1966
+ import { property as property14, state as state6 } from "lit/decorators.js";
1967
+ var DsDrawerContent = class extends DSElement {
1968
+ constructor() {
1969
+ super(...arguments);
1970
+ this.side = "bottom";
1971
+ this.dataState = "closed";
1972
+ this.swipeDismiss = true;
1973
+ this.swipeOffset = 0;
1974
+ this.isDragging = false;
1975
+ this.startY = 0;
1976
+ this.startX = 0;
1977
+ this.handleTouchStart = (event) => {
1978
+ if (!this.swipeDismiss) return;
1979
+ const touch = event.touches[0];
1980
+ if (!touch) return;
1981
+ this.startY = touch.clientY;
1982
+ this.startX = touch.clientX;
1983
+ this.isDragging = true;
1984
+ };
1985
+ this.handleTouchMove = (event) => {
1986
+ if (!this.swipeDismiss || !this.isDragging) return;
1987
+ const touch = event.touches[0];
1988
+ if (!touch) return;
1989
+ const deltaY = touch.clientY - this.startY;
1990
+ const deltaX = touch.clientX - this.startX;
1991
+ let offset = 0;
1992
+ switch (this.side) {
1993
+ case "bottom":
1994
+ offset = Math.max(0, deltaY);
1995
+ break;
1996
+ case "top":
1997
+ offset = Math.max(0, -deltaY);
1998
+ break;
1999
+ case "left":
2000
+ offset = Math.max(0, -deltaX);
2001
+ break;
2002
+ case "right":
2003
+ offset = Math.max(0, deltaX);
2004
+ break;
2005
+ }
2006
+ if (offset > 0) {
2007
+ event.preventDefault();
2008
+ this.swipeOffset = offset;
2009
+ this.updateSwipeTransform();
2010
+ }
2011
+ };
2012
+ this.handleTouchEnd = () => {
2013
+ if (!this.swipeDismiss || !this.isDragging) return;
2014
+ this.isDragging = false;
2015
+ const threshold = Math.min(100, this.offsetHeight * 0.3);
2016
+ if (this.swipeOffset > threshold) {
2017
+ emitEvent(this, "ds:drawer-close", { bubbles: true });
2018
+ } else {
2019
+ this.swipeOffset = 0;
2020
+ this.style.transform = "";
2021
+ }
2022
+ };
2023
+ }
2024
+ connectedCallback() {
2025
+ super.connectedCallback();
2026
+ this.addEventListener("touchstart", this.handleTouchStart, { passive: true });
2027
+ this.addEventListener("touchmove", this.handleTouchMove, { passive: false });
2028
+ this.addEventListener("touchend", this.handleTouchEnd, { passive: true });
2029
+ }
2030
+ disconnectedCallback() {
2031
+ super.disconnectedCallback();
2032
+ this.removeEventListener("touchstart", this.handleTouchStart);
2033
+ this.removeEventListener("touchmove", this.handleTouchMove);
2034
+ this.removeEventListener("touchend", this.handleTouchEnd);
2035
+ }
2036
+ updateSwipeTransform() {
2037
+ switch (this.side) {
2038
+ case "bottom":
2039
+ this.style.transform = `translateY(${this.swipeOffset}px)`;
2040
+ break;
2041
+ case "top":
2042
+ this.style.transform = `translateY(-${this.swipeOffset}px)`;
2043
+ break;
2044
+ case "left":
2045
+ this.style.transform = `translateX(-${this.swipeOffset}px)`;
2046
+ break;
2047
+ case "right":
2048
+ this.style.transform = `translateX(${this.swipeOffset}px)`;
2049
+ break;
2050
+ }
2051
+ }
2052
+ render() {
2053
+ return html29`
2054
+ <div class="ds-drawer__handle"></div>
2055
+ <slot></slot>
2056
+ `;
2057
+ }
2058
+ };
2059
+ __decorateClass([
2060
+ property14({ reflect: true })
2061
+ ], DsDrawerContent.prototype, "side", 2);
2062
+ __decorateClass([
2063
+ property14({ attribute: "data-state", reflect: true })
2064
+ ], DsDrawerContent.prototype, "dataState", 2);
2065
+ __decorateClass([
2066
+ property14({ type: Boolean, attribute: "swipe-dismiss" })
2067
+ ], DsDrawerContent.prototype, "swipeDismiss", 2);
2068
+ __decorateClass([
2069
+ state6()
2070
+ ], DsDrawerContent.prototype, "swipeOffset", 2);
2071
+ __decorateClass([
2072
+ state6()
2073
+ ], DsDrawerContent.prototype, "isDragging", 2);
2074
+ define("ds-drawer-content", DsDrawerContent);
2075
+
2076
+ // src/components/drawer/drawer-header.ts
2077
+ import { html as html30 } from "lit";
2078
+ var DsDrawerHeader = class extends DSElement {
2079
+ render() {
2080
+ return html30`<slot></slot>`;
2081
+ }
2082
+ };
2083
+ define("ds-drawer-header", DsDrawerHeader);
2084
+
2085
+ // src/components/drawer/drawer-footer.ts
2086
+ import { html as html31 } from "lit";
2087
+ var DsDrawerFooter = class extends DSElement {
2088
+ render() {
2089
+ return html31`<slot></slot>`;
2090
+ }
2091
+ };
2092
+ define("ds-drawer-footer", DsDrawerFooter);
2093
+
2094
+ // src/components/drawer/drawer-title.ts
2095
+ import { html as html32 } from "lit";
2096
+ var DsDrawerTitle = class extends DSElement {
2097
+ connectedCallback() {
2098
+ super.connectedCallback();
2099
+ if (!this.id) {
2100
+ this.id = `drawer-title-${crypto.randomUUID().slice(0, 8)}`;
2101
+ }
2102
+ }
2103
+ render() {
2104
+ return html32`<slot></slot>`;
2105
+ }
2106
+ };
2107
+ define("ds-drawer-title", DsDrawerTitle);
2108
+
2109
+ // src/components/drawer/drawer-description.ts
2110
+ import { html as html33 } from "lit";
2111
+ var DsDrawerDescription = class extends DSElement {
2112
+ connectedCallback() {
2113
+ super.connectedCallback();
2114
+ if (!this.id) {
2115
+ this.id = `drawer-desc-${crypto.randomUUID().slice(0, 8)}`;
2116
+ }
2117
+ }
2118
+ render() {
2119
+ return html33`<slot></slot>`;
2120
+ }
2121
+ };
2122
+ define("ds-drawer-description", DsDrawerDescription);
2123
+
2124
+ // src/components/drawer/drawer.ts
2125
+ import {
2126
+ createDialogBehavior as createDialogBehavior4,
2127
+ createPresence as createPresence7,
2128
+ prefersReducedMotion as prefersReducedMotion7
2129
+ } from "@hypoth-ui/primitives-dom";
2130
+ import { html as html34 } from "lit";
2131
+ import { property as property15, state as state7 } from "lit/decorators.js";
2132
+ var DsDrawer = class extends DSElement {
2133
+ constructor() {
2134
+ super(...arguments);
2135
+ this.open = false;
2136
+ this.side = "bottom";
2137
+ this.swipeDismiss = true;
2138
+ this.closeOnEscape = true;
2139
+ this.closeOnOverlay = true;
2140
+ this.animated = true;
2141
+ this.isClosing = false;
2142
+ this.dialogBehavior = null;
2143
+ this.presence = null;
2144
+ this.handleTriggerClick = (event) => {
2145
+ const target = event.target;
2146
+ const trigger = target.closest('[slot="trigger"]');
2147
+ if (trigger && this.contains(trigger)) {
2148
+ this.dialogBehavior?.setTriggerElement(trigger);
2149
+ this.show();
2150
+ }
2151
+ };
2152
+ this.handleCloseRequest = () => {
2153
+ this.close();
2154
+ };
2155
+ this.handleOverlayClick = () => {
2156
+ if (this.closeOnOverlay) {
2157
+ this.close();
2158
+ }
2159
+ };
2160
+ }
2161
+ connectedCallback() {
2162
+ super.connectedCallback();
2163
+ this.addEventListener("click", this.handleTriggerClick);
2164
+ this.addEventListener("ds:drawer-close", this.handleCloseRequest);
2165
+ this.initDialogBehavior();
2166
+ }
2167
+ disconnectedCallback() {
2168
+ super.disconnectedCallback();
2169
+ this.removeEventListener("click", this.handleTriggerClick);
2170
+ this.removeEventListener("ds:drawer-close", this.handleCloseRequest);
2171
+ this.cleanup();
2172
+ }
2173
+ /**
2174
+ * Initializes the dialog behavior primitive.
2175
+ */
2176
+ initDialogBehavior() {
2177
+ this.dialogBehavior = createDialogBehavior4({
2178
+ defaultOpen: this.open,
2179
+ role: "dialog",
2180
+ closeOnEscape: this.closeOnEscape,
2181
+ closeOnOutsideClick: this.closeOnOverlay,
2182
+ onOpenChange: (open) => {
2183
+ if (!open && this.open) {
2184
+ this.handleBehaviorClose();
2185
+ }
2186
+ }
2187
+ });
2188
+ const trigger = this.querySelector('[slot="trigger"]');
2189
+ if (trigger) {
2190
+ this.dialogBehavior.setTriggerElement(trigger);
2191
+ }
2192
+ }
2193
+ /**
2194
+ * Handles close triggered by the behavior (escape/outside click).
2195
+ */
2196
+ handleBehaviorClose() {
2197
+ const content = this.querySelector("ds-drawer-content");
2198
+ if (this.animated && content && !prefersReducedMotion7()) {
2199
+ this.isClosing = true;
2200
+ this.presence = createPresence7({
2201
+ onExitComplete: () => {
2202
+ this.completeClose();
2203
+ }
2204
+ });
2205
+ this.presence.hide(content);
2206
+ } else {
2207
+ this.open = false;
2208
+ this.isClosing = false;
2209
+ emitEvent(this, StandardEvents.CLOSE);
2210
+ }
2211
+ }
2212
+ /**
2213
+ * Opens the drawer.
2214
+ */
2215
+ show() {
2216
+ if (this.open) return;
2217
+ const trigger = this.querySelector('[slot="trigger"]');
2218
+ if (trigger) {
2219
+ this.dialogBehavior?.setTriggerElement(trigger);
2220
+ } else if (document.activeElement instanceof HTMLElement) {
2221
+ this.dialogBehavior?.setTriggerElement(document.activeElement);
2222
+ }
2223
+ this.open = true;
2224
+ this.dialogBehavior?.open();
2225
+ emitEvent(this, StandardEvents.OPEN);
2226
+ }
2227
+ /**
2228
+ * Closes the drawer.
2229
+ */
2230
+ close() {
2231
+ if (!this.open) return;
2232
+ const content = this.querySelector("ds-drawer-content");
2233
+ this.dialogBehavior?.close();
2234
+ if (this.animated && content && !prefersReducedMotion7()) {
2235
+ this.isClosing = true;
2236
+ this.presence = createPresence7({
2237
+ onExitComplete: () => {
2238
+ this.completeClose();
2239
+ }
2240
+ });
2241
+ this.presence.hide(content);
2242
+ } else {
2243
+ this.open = false;
2244
+ this.isClosing = false;
2245
+ emitEvent(this, StandardEvents.CLOSE);
2246
+ }
2247
+ }
2248
+ /**
2249
+ * Completes the close after exit animation.
2250
+ */
2251
+ completeClose() {
2252
+ this.presence?.destroy();
2253
+ this.presence = null;
2254
+ this.open = false;
2255
+ this.isClosing = false;
2256
+ emitEvent(this, StandardEvents.CLOSE);
2257
+ }
2258
+ cleanup() {
2259
+ this.dialogBehavior?.destroy();
2260
+ this.dialogBehavior = null;
2261
+ this.presence?.destroy();
2262
+ this.presence = null;
2263
+ }
2264
+ async updated(changedProperties) {
2265
+ super.updated(changedProperties);
2266
+ if (changedProperties.has("open")) {
2267
+ const content = this.querySelector("ds-drawer-content");
2268
+ if (this.open) {
2269
+ await this.updateComplete;
2270
+ if (content) {
2271
+ content.dataState = "open";
2272
+ content.side = this.side;
2273
+ }
2274
+ this.dialogBehavior?.setContentElement(content);
2275
+ this.updateContentAccessibility();
2276
+ } else {
2277
+ this.dialogBehavior?.setContentElement(null);
2278
+ }
2279
+ }
2280
+ if (changedProperties.has("closeOnEscape") || changedProperties.has("closeOnOverlay")) {
2281
+ const wasOpen = this.dialogBehavior?.state.open;
2282
+ this.dialogBehavior?.destroy();
2283
+ this.initDialogBehavior();
2284
+ if (wasOpen) {
2285
+ this.dialogBehavior?.open();
2286
+ const content = this.querySelector("ds-drawer-content");
2287
+ this.dialogBehavior?.setContentElement(content);
2288
+ }
2289
+ }
2290
+ }
2291
+ /**
2292
+ * Updates accessibility attributes on drawer content.
2293
+ */
2294
+ updateContentAccessibility() {
2295
+ const content = this.querySelector("ds-drawer-content");
2296
+ if (!content || !this.dialogBehavior) return;
2297
+ const contentProps = this.dialogBehavior.getContentProps();
2298
+ content.setAttribute("role", "dialog");
2299
+ content.setAttribute("aria-modal", contentProps["aria-modal"]);
2300
+ if (!hasRequiredChild(this, "ds-drawer-title") && !this.getAttribute("aria-label")) {
2301
+ devWarn(Warnings.dialogMissingTitle("ds-drawer"));
2302
+ }
2303
+ const title = this.querySelector("ds-drawer-title");
2304
+ if (title) {
2305
+ const titleProps = this.dialogBehavior.getTitleProps();
2306
+ if (!title.id) {
2307
+ title.id = titleProps.id;
2308
+ }
2309
+ content.setAttribute("aria-labelledby", title.id);
2310
+ }
2311
+ const description = this.querySelector("ds-drawer-description");
2312
+ if (description) {
2313
+ const descProps = this.dialogBehavior.getDescriptionProps();
2314
+ if (!description.id) {
2315
+ description.id = descProps.id;
2316
+ }
2317
+ content.setAttribute("aria-describedby", description.id);
2318
+ this.dialogBehavior.setHasDescription(true);
2319
+ } else {
2320
+ if (title) {
2321
+ devWarn(Warnings.dialogMissingDescription("ds-drawer"));
2322
+ }
2323
+ this.dialogBehavior.setHasDescription(false);
2324
+ }
2325
+ }
2326
+ render() {
2327
+ return html34`
2328
+ <slot name="trigger"></slot>
2329
+ <div
2330
+ class="ds-drawer__overlay"
2331
+ ?hidden=${!this.open}
2332
+ ?data-closing=${this.isClosing}
2333
+ @click=${this.handleOverlayClick}
2334
+ ></div>
2335
+ <slot ?hidden=${!this.open}></slot>
2336
+ `;
2337
+ }
2338
+ };
2339
+ __decorateClass([
2340
+ property15({ type: Boolean, reflect: true })
2341
+ ], DsDrawer.prototype, "open", 2);
2342
+ __decorateClass([
2343
+ property15({ reflect: true })
2344
+ ], DsDrawer.prototype, "side", 2);
2345
+ __decorateClass([
2346
+ property15({ type: Boolean, attribute: "swipe-dismiss" })
2347
+ ], DsDrawer.prototype, "swipeDismiss", 2);
2348
+ __decorateClass([
2349
+ property15({ type: Boolean, attribute: "close-on-escape" })
2350
+ ], DsDrawer.prototype, "closeOnEscape", 2);
2351
+ __decorateClass([
2352
+ property15({ type: Boolean, attribute: "close-on-overlay" })
2353
+ ], DsDrawer.prototype, "closeOnOverlay", 2);
2354
+ __decorateClass([
2355
+ property15({ type: Boolean })
2356
+ ], DsDrawer.prototype, "animated", 2);
2357
+ __decorateClass([
2358
+ state7()
2359
+ ], DsDrawer.prototype, "isClosing", 2);
2360
+ define("ds-drawer", DsDrawer);
2361
+
2362
+ // src/components/dropdown-menu/dropdown-menu-content.ts
2363
+ import { html as html35 } from "lit";
2364
+ import { property as property16 } from "lit/decorators.js";
2365
+ var DsDropdownMenuContent = class extends DSElement {
2366
+ constructor() {
2367
+ super(...arguments);
2368
+ this.dataState = "closed";
2369
+ }
2370
+ connectedCallback() {
2371
+ super.connectedCallback();
2372
+ if (!this.id) {
2373
+ this.id = `dropdown-menu-content-${crypto.randomUUID().slice(0, 8)}`;
2374
+ }
2375
+ this.setAttribute("role", "menu");
2376
+ this.setAttribute("hidden", "");
2377
+ }
2378
+ render() {
2379
+ return html35`<slot></slot>`;
2380
+ }
2381
+ };
2382
+ __decorateClass([
2383
+ property16({ attribute: "data-state", reflect: true })
2384
+ ], DsDropdownMenuContent.prototype, "dataState", 2);
2385
+ define("ds-dropdown-menu-content", DsDropdownMenuContent);
2386
+
2387
+ // src/components/dropdown-menu/dropdown-menu-item.ts
2388
+ import { html as html36 } from "lit";
2389
+ import { property as property17 } from "lit/decorators.js";
2390
+ var DsDropdownMenuItem = class extends DSElement {
2391
+ constructor() {
2392
+ super(...arguments);
2393
+ this.value = "";
2394
+ this.variant = "default";
2395
+ this.disabled = false;
2396
+ this.handleSelect = () => {
2397
+ if (this.disabled) return;
2398
+ emitEvent(this, "ds:select", {
2399
+ detail: { value: this.value },
2400
+ bubbles: true
2401
+ });
2402
+ };
2403
+ this.handleKeyDown = (event) => {
2404
+ if (this.disabled) return;
2405
+ if (event.key === "Enter" || event.key === " ") {
2406
+ event.preventDefault();
2407
+ this.handleSelect();
2408
+ }
2409
+ };
2410
+ }
2411
+ connectedCallback() {
2412
+ super.connectedCallback();
2413
+ this.setAttribute("role", "menuitem");
2414
+ this.setAttribute("tabindex", "-1");
2415
+ this.addEventListener("click", this.handleSelect);
2416
+ this.addEventListener("keydown", this.handleKeyDown);
2417
+ }
2418
+ disconnectedCallback() {
2419
+ super.disconnectedCallback();
2420
+ this.removeEventListener("click", this.handleSelect);
2421
+ this.removeEventListener("keydown", this.handleKeyDown);
2422
+ }
2423
+ updated(changedProperties) {
2424
+ if (changedProperties.has("disabled")) {
2425
+ this.setAttribute("aria-disabled", String(this.disabled));
2426
+ }
2427
+ }
2428
+ render() {
2429
+ return html36`<slot></slot>`;
2430
+ }
2431
+ };
2432
+ __decorateClass([
2433
+ property17()
2434
+ ], DsDropdownMenuItem.prototype, "value", 2);
2435
+ __decorateClass([
2436
+ property17({ reflect: true })
2437
+ ], DsDropdownMenuItem.prototype, "variant", 2);
2438
+ __decorateClass([
2439
+ property17({ type: Boolean, reflect: true })
2440
+ ], DsDropdownMenuItem.prototype, "disabled", 2);
2441
+ define("ds-dropdown-menu-item", DsDropdownMenuItem);
2442
+
2443
+ // src/components/dropdown-menu/dropdown-menu-separator.ts
2444
+ import { html as html37 } from "lit";
2445
+ var DsDropdownMenuSeparator = class extends DSElement {
2446
+ connectedCallback() {
2447
+ super.connectedCallback();
2448
+ this.setAttribute("role", "separator");
2449
+ }
2450
+ render() {
2451
+ return html37``;
2452
+ }
2453
+ };
2454
+ define("ds-dropdown-menu-separator", DsDropdownMenuSeparator);
2455
+
2456
+ // src/components/dropdown-menu/dropdown-menu-label.ts
2457
+ import { html as html38 } from "lit";
2458
+ var DsDropdownMenuLabel = class extends DSElement {
2459
+ connectedCallback() {
2460
+ super.connectedCallback();
2461
+ this.setAttribute("aria-hidden", "true");
2462
+ }
2463
+ render() {
2464
+ return html38`<slot></slot>`;
2465
+ }
2466
+ };
2467
+ define("ds-dropdown-menu-label", DsDropdownMenuLabel);
2468
+
2469
+ // src/components/dropdown-menu/dropdown-menu-checkbox-item.ts
2470
+ import { html as html39 } from "lit";
2471
+ import { property as property18 } from "lit/decorators.js";
2472
+ var DsDropdownMenuCheckboxItem = class extends DSElement {
2473
+ constructor() {
2474
+ super(...arguments);
2475
+ this.checked = false;
2476
+ this.disabled = false;
2477
+ this.handleToggle = () => {
2478
+ if (this.disabled) return;
2479
+ this.checked = !this.checked;
2480
+ this.updateAriaChecked();
2481
+ emitEvent(this, "ds:select", {
2482
+ detail: { checked: this.checked },
2483
+ bubbles: true
2484
+ });
2485
+ };
2486
+ this.handleKeyDown = (event) => {
2487
+ if (this.disabled) return;
2488
+ if (event.key === "Enter" || event.key === " ") {
2489
+ event.preventDefault();
2490
+ this.handleToggle();
2491
+ }
2492
+ };
2493
+ }
2494
+ connectedCallback() {
2495
+ super.connectedCallback();
2496
+ this.setAttribute("role", "menuitemcheckbox");
2497
+ this.setAttribute("tabindex", "-1");
2498
+ this.updateAriaChecked();
2499
+ this.addEventListener("click", this.handleToggle);
2500
+ this.addEventListener("keydown", this.handleKeyDown);
2501
+ }
2502
+ disconnectedCallback() {
2503
+ super.disconnectedCallback();
2504
+ this.removeEventListener("click", this.handleToggle);
2505
+ this.removeEventListener("keydown", this.handleKeyDown);
2506
+ }
2507
+ updateAriaChecked() {
2508
+ this.setAttribute("aria-checked", String(this.checked));
2509
+ }
2510
+ updated(changedProperties) {
2511
+ if (changedProperties.has("disabled")) {
2512
+ this.setAttribute("aria-disabled", String(this.disabled));
2513
+ }
2514
+ if (changedProperties.has("checked")) {
2515
+ this.updateAriaChecked();
2516
+ }
2517
+ }
2518
+ render() {
2519
+ return html39`
2520
+ <span class="ds-dropdown-menu-checkbox-item__indicator" aria-hidden="true">
2521
+ ${this.checked ? "\u2713" : ""}
2522
+ </span>
2523
+ <slot></slot>
2524
+ `;
2525
+ }
2526
+ };
2527
+ __decorateClass([
2528
+ property18({ type: Boolean, reflect: true })
2529
+ ], DsDropdownMenuCheckboxItem.prototype, "checked", 2);
2530
+ __decorateClass([
2531
+ property18({ type: Boolean, reflect: true })
2532
+ ], DsDropdownMenuCheckboxItem.prototype, "disabled", 2);
2533
+ define("ds-dropdown-menu-checkbox-item", DsDropdownMenuCheckboxItem);
2534
+
2535
+ // src/components/dropdown-menu/dropdown-menu-radio-group.ts
2536
+ import { html as html40 } from "lit";
2537
+ import { property as property19 } from "lit/decorators.js";
2538
+ var DsDropdownMenuRadioGroup = class extends DSElement {
2539
+ constructor() {
2540
+ super(...arguments);
2541
+ this.value = "";
2542
+ this.handleRadioSelect = (event) => {
2543
+ event.stopPropagation();
2544
+ const newValue = event.detail.value;
2545
+ if (newValue !== this.value) {
2546
+ this.value = newValue;
2547
+ this.updateRadioItems();
2548
+ emitEvent(this, "ds:change", {
2549
+ detail: { value: this.value },
2550
+ bubbles: true
2551
+ });
2552
+ }
2553
+ };
2554
+ }
2555
+ connectedCallback() {
2556
+ super.connectedCallback();
2557
+ this.setAttribute("role", "group");
2558
+ this.addEventListener("ds:radio-select", this.handleRadioSelect);
2559
+ }
2560
+ disconnectedCallback() {
2561
+ super.disconnectedCallback();
2562
+ this.removeEventListener("ds:radio-select", this.handleRadioSelect);
2563
+ }
2564
+ updateRadioItems() {
2565
+ const items = this.querySelectorAll("ds-dropdown-menu-radio-item");
2566
+ for (const item of items) {
2567
+ const itemValue = item.getAttribute("value");
2568
+ if (itemValue === this.value) {
2569
+ item.setAttribute("checked", "");
2570
+ } else {
2571
+ item.removeAttribute("checked");
2572
+ }
2573
+ }
2574
+ }
2575
+ updated(changedProperties) {
2576
+ if (changedProperties.has("value")) {
2577
+ this.updateRadioItems();
2578
+ }
2579
+ }
2580
+ render() {
2581
+ return html40`<slot></slot>`;
2582
+ }
2583
+ };
2584
+ __decorateClass([
2585
+ property19()
2586
+ ], DsDropdownMenuRadioGroup.prototype, "value", 2);
2587
+ define("ds-dropdown-menu-radio-group", DsDropdownMenuRadioGroup);
2588
+
2589
+ // src/components/dropdown-menu/dropdown-menu-radio-item.ts
2590
+ import { html as html41 } from "lit";
2591
+ import { property as property20 } from "lit/decorators.js";
2592
+ var DsDropdownMenuRadioItem = class extends DSElement {
2593
+ constructor() {
2594
+ super(...arguments);
2595
+ this.value = "";
2596
+ this.checked = false;
2597
+ this.disabled = false;
2598
+ this.handleSelect = () => {
2599
+ if (this.disabled || this.checked) return;
2600
+ emitEvent(this, "ds:radio-select", {
2601
+ detail: { value: this.value },
2602
+ bubbles: true
2603
+ });
2604
+ emitEvent(this, "ds:select", {
2605
+ detail: { value: this.value },
2606
+ bubbles: true
2607
+ });
2608
+ };
2609
+ this.handleKeyDown = (event) => {
2610
+ if (this.disabled) return;
2611
+ if (event.key === "Enter" || event.key === " ") {
2612
+ event.preventDefault();
2613
+ this.handleSelect();
2614
+ }
2615
+ };
2616
+ }
2617
+ connectedCallback() {
2618
+ super.connectedCallback();
2619
+ this.setAttribute("role", "menuitemradio");
2620
+ this.setAttribute("tabindex", "-1");
2621
+ this.updateAriaChecked();
2622
+ this.addEventListener("click", this.handleSelect);
2623
+ this.addEventListener("keydown", this.handleKeyDown);
2624
+ }
2625
+ disconnectedCallback() {
2626
+ super.disconnectedCallback();
2627
+ this.removeEventListener("click", this.handleSelect);
2628
+ this.removeEventListener("keydown", this.handleKeyDown);
2629
+ }
2630
+ updateAriaChecked() {
2631
+ this.setAttribute("aria-checked", String(this.checked));
2632
+ }
2633
+ updated(changedProperties) {
2634
+ if (changedProperties.has("disabled")) {
2635
+ this.setAttribute("aria-disabled", String(this.disabled));
2636
+ }
2637
+ if (changedProperties.has("checked")) {
2638
+ this.updateAriaChecked();
2639
+ }
2640
+ }
2641
+ render() {
2642
+ return html41`
2643
+ <span class="ds-dropdown-menu-radio-item__indicator" aria-hidden="true">
2644
+ ${this.checked ? "\u25CF" : "\u25CB"}
2645
+ </span>
2646
+ <slot></slot>
2647
+ `;
2648
+ }
2649
+ };
2650
+ __decorateClass([
2651
+ property20()
2652
+ ], DsDropdownMenuRadioItem.prototype, "value", 2);
2653
+ __decorateClass([
2654
+ property20({ type: Boolean, reflect: true })
2655
+ ], DsDropdownMenuRadioItem.prototype, "checked", 2);
2656
+ __decorateClass([
2657
+ property20({ type: Boolean, reflect: true })
2658
+ ], DsDropdownMenuRadioItem.prototype, "disabled", 2);
2659
+ define("ds-dropdown-menu-radio-item", DsDropdownMenuRadioItem);
2660
+
2661
+ // src/components/dropdown-menu/dropdown-menu.ts
2662
+ import {
2663
+ createMenuBehavior,
2664
+ createPresence as createPresence8,
2665
+ prefersReducedMotion as prefersReducedMotion8
2666
+ } from "@hypoth-ui/primitives-dom";
2667
+ import { html as html42 } from "lit";
2668
+ import { property as property21 } from "lit/decorators.js";
2669
+ var DsDropdownMenu = class extends DSElement {
2670
+ constructor() {
2671
+ super(...arguments);
2672
+ this.open = false;
2673
+ this.placement = "bottom-start";
2674
+ this.offset = 4;
2675
+ this.flip = true;
2676
+ this.animated = true;
2677
+ this.modal = true;
2678
+ this.menuBehavior = null;
2679
+ this.presence = null;
2680
+ this.focusFirstOnOpen = null;
2681
+ this.handleTriggerClick = (event) => {
2682
+ const target = event.target;
2683
+ const trigger = target.closest('[slot="trigger"]');
2684
+ if (trigger && this.contains(trigger)) {
2685
+ event.preventDefault();
2686
+ this.menuBehavior?.setTriggerElement(trigger);
2687
+ this.focusFirstOnOpen = "first";
2688
+ this.toggle();
2689
+ }
2690
+ };
2691
+ this.handleTriggerKeyDown = (event) => {
2692
+ const target = event.target;
2693
+ const trigger = target.closest('[slot="trigger"]');
2694
+ if (!trigger || !this.contains(trigger)) return;
2695
+ this.menuBehavior?.setTriggerElement(trigger);
2696
+ switch (event.key) {
2697
+ case "Enter":
2698
+ case " ":
2699
+ event.preventDefault();
2700
+ this.focusFirstOnOpen = "first";
2701
+ this.toggle();
2702
+ break;
2703
+ case "ArrowDown":
2704
+ event.preventDefault();
2705
+ this.focusFirstOnOpen = "first";
2706
+ if (!this.open) this.show();
2707
+ break;
2708
+ case "ArrowUp":
2709
+ event.preventDefault();
2710
+ this.focusFirstOnOpen = "last";
2711
+ if (!this.open) this.show();
2712
+ break;
2713
+ }
2714
+ };
2715
+ this.handleItemSelect = () => {
2716
+ this.close();
2717
+ };
2718
+ }
2719
+ connectedCallback() {
2720
+ super.connectedCallback();
2721
+ this.addEventListener("click", this.handleTriggerClick);
2722
+ this.addEventListener("keydown", this.handleTriggerKeyDown);
2723
+ this.addEventListener("ds:select", this.handleItemSelect);
2724
+ this.initMenuBehavior();
2725
+ this.updateComplete.then(() => {
2726
+ this.setupTriggerAccessibility();
2727
+ });
2728
+ }
2729
+ disconnectedCallback() {
2730
+ super.disconnectedCallback();
2731
+ this.removeEventListener("click", this.handleTriggerClick);
2732
+ this.removeEventListener("keydown", this.handleTriggerKeyDown);
2733
+ this.removeEventListener("ds:select", this.handleItemSelect);
2734
+ this.cleanup();
2735
+ }
2736
+ /**
2737
+ * Initializes the menu behavior primitive.
2738
+ */
2739
+ initMenuBehavior() {
2740
+ this.menuBehavior = createMenuBehavior({
2741
+ defaultOpen: this.open,
2742
+ placement: this.placement,
2743
+ offset: this.offset,
2744
+ flip: this.flip,
2745
+ loop: true,
2746
+ onOpenChange: (open) => {
2747
+ if (!open && this.open) {
2748
+ this.handleBehaviorClose();
2749
+ }
2750
+ },
2751
+ onSelect: (value) => {
2752
+ emitEvent(this, StandardEvents.SELECT, { detail: { value } });
2753
+ }
2754
+ });
2755
+ const trigger = this.querySelector('[slot="trigger"]');
2756
+ if (trigger) {
2757
+ this.menuBehavior.setTriggerElement(trigger);
2758
+ }
2759
+ }
2760
+ /**
2761
+ * Handles close triggered by the behavior (escape/outside click).
2762
+ */
2763
+ handleBehaviorClose() {
2764
+ const content = this.querySelector("ds-dropdown-menu-content");
2765
+ if (this.animated && content && !prefersReducedMotion8()) {
2766
+ this.presence = createPresence8({
2767
+ onExitComplete: () => {
2768
+ this.completeClose();
2769
+ }
2770
+ });
2771
+ this.presence.hide(content);
2772
+ } else {
2773
+ this.open = false;
2774
+ emitEvent(this, StandardEvents.CLOSE);
2775
+ }
2776
+ }
2777
+ /**
2778
+ * Opens the menu.
2779
+ */
2780
+ show() {
2781
+ if (this.open) return;
2782
+ this.open = true;
2783
+ this.menuBehavior?.open(this.focusFirstOnOpen ?? "first");
2784
+ emitEvent(this, StandardEvents.OPEN);
2785
+ }
2786
+ /**
2787
+ * Closes the menu.
2788
+ */
2789
+ close() {
2790
+ if (!this.open) return;
2791
+ const content = this.querySelector("ds-dropdown-menu-content");
2792
+ this.menuBehavior?.close();
2793
+ if (this.animated && content && !prefersReducedMotion8()) {
2794
+ this.presence = createPresence8({
2795
+ onExitComplete: () => {
2796
+ this.completeClose();
2797
+ }
2798
+ });
2799
+ this.presence.hide(content);
2800
+ } else {
2801
+ this.open = false;
2802
+ emitEvent(this, StandardEvents.CLOSE);
2803
+ }
2804
+ }
2805
+ completeClose() {
2806
+ this.presence?.destroy();
2807
+ this.presence = null;
2808
+ this.open = false;
2809
+ emitEvent(this, StandardEvents.CLOSE);
2810
+ }
2811
+ toggle() {
2812
+ if (this.open) {
2813
+ this.close();
2814
+ } else {
2815
+ this.show();
2816
+ }
2817
+ }
2818
+ setupTriggerAccessibility() {
2819
+ const trigger = this.querySelector('[slot="trigger"]');
2820
+ const content = this.querySelector("ds-dropdown-menu-content");
2821
+ if (trigger && content && this.menuBehavior) {
2822
+ this.menuBehavior.setTriggerElement(trigger);
2823
+ const triggerProps = this.menuBehavior.getTriggerProps();
2824
+ trigger.setAttribute("aria-haspopup", triggerProps["aria-haspopup"]);
2825
+ trigger.setAttribute("aria-expanded", triggerProps["aria-expanded"]);
2826
+ trigger.setAttribute("aria-controls", triggerProps["aria-controls"]);
2827
+ }
2828
+ }
2829
+ updateTriggerAria() {
2830
+ const trigger = this.querySelector('[slot="trigger"]');
2831
+ if (trigger && this.menuBehavior) {
2832
+ const triggerProps = this.menuBehavior.getTriggerProps();
2833
+ trigger.setAttribute("aria-expanded", triggerProps["aria-expanded"]);
2834
+ }
2835
+ }
2836
+ registerMenuItems() {
2837
+ const content = this.querySelector("ds-dropdown-menu-content");
2838
+ if (!content || !this.menuBehavior) return;
2839
+ const items = content.querySelectorAll(
2840
+ "ds-dropdown-menu-item:not([disabled]), ds-dropdown-menu-checkbox-item:not([disabled]), ds-dropdown-menu-radio-item:not([disabled])"
2841
+ );
2842
+ items.forEach((item) => {
2843
+ this.menuBehavior?.registerItem(item);
2844
+ });
2845
+ }
2846
+ cleanup() {
2847
+ this.menuBehavior?.destroy();
2848
+ this.menuBehavior = null;
2849
+ this.presence?.destroy();
2850
+ this.presence = null;
2851
+ }
2852
+ async updated(changedProperties) {
2853
+ super.updated(changedProperties);
2854
+ if (changedProperties.has("open")) {
2855
+ this.updateTriggerAria();
2856
+ const content = this.querySelector(
2857
+ "ds-dropdown-menu-content"
2858
+ );
2859
+ if (this.open) {
2860
+ content?.removeAttribute("hidden");
2861
+ if (content) {
2862
+ content.dataState = "open";
2863
+ }
2864
+ await this.updateComplete;
2865
+ this.registerMenuItems();
2866
+ this.menuBehavior?.setContentElement(content);
2867
+ } else {
2868
+ content?.setAttribute("hidden", "");
2869
+ this.menuBehavior?.setContentElement(null);
2870
+ }
2871
+ }
2872
+ if (changedProperties.has("placement") || changedProperties.has("offset") || changedProperties.has("flip")) {
2873
+ const wasOpen = this.menuBehavior?.state.open;
2874
+ this.menuBehavior?.destroy();
2875
+ this.initMenuBehavior();
2876
+ if (wasOpen) {
2877
+ this.menuBehavior?.open();
2878
+ const content = this.querySelector("ds-dropdown-menu-content");
2879
+ this.registerMenuItems();
2880
+ this.menuBehavior?.setContentElement(content);
2881
+ }
2882
+ }
2883
+ }
2884
+ render() {
2885
+ return html42`
2886
+ <slot name="trigger"></slot>
2887
+ <slot></slot>
2888
+ `;
2889
+ }
2890
+ };
2891
+ __decorateClass([
2892
+ property21({ type: Boolean, reflect: true })
2893
+ ], DsDropdownMenu.prototype, "open", 2);
2894
+ __decorateClass([
2895
+ property21({ type: String, reflect: true })
2896
+ ], DsDropdownMenu.prototype, "placement", 2);
2897
+ __decorateClass([
2898
+ property21({ type: Number })
2899
+ ], DsDropdownMenu.prototype, "offset", 2);
2900
+ __decorateClass([
2901
+ property21({ type: Boolean })
2902
+ ], DsDropdownMenu.prototype, "flip", 2);
2903
+ __decorateClass([
2904
+ property21({ type: Boolean })
2905
+ ], DsDropdownMenu.prototype, "animated", 2);
2906
+ __decorateClass([
2907
+ property21({ type: Boolean })
2908
+ ], DsDropdownMenu.prototype, "modal", 2);
2909
+ define("ds-dropdown-menu", DsDropdownMenu);
2910
+
2911
+ // src/components/context-menu/context-menu-content.ts
2912
+ import { html as html43 } from "lit";
2913
+ import { property as property22 } from "lit/decorators.js";
2914
+ var DsContextMenuContent = class extends DSElement {
2915
+ constructor() {
2916
+ super(...arguments);
2917
+ this.dataState = "closed";
2918
+ }
2919
+ connectedCallback() {
2920
+ super.connectedCallback();
2921
+ if (!this.id) {
2922
+ this.id = `context-menu-content-${crypto.randomUUID().slice(0, 8)}`;
2923
+ }
2924
+ this.setAttribute("role", "menu");
2925
+ this.setAttribute("hidden", "");
2926
+ }
2927
+ render() {
2928
+ return html43`<slot></slot>`;
2929
+ }
2930
+ };
2931
+ __decorateClass([
2932
+ property22({ attribute: "data-state", reflect: true })
2933
+ ], DsContextMenuContent.prototype, "dataState", 2);
2934
+ define("ds-context-menu-content", DsContextMenuContent);
2935
+
2936
+ // src/components/context-menu/context-menu-item.ts
2937
+ import { html as html44 } from "lit";
2938
+ import { property as property23 } from "lit/decorators.js";
2939
+ var DsContextMenuItem = class extends DSElement {
2940
+ constructor() {
2941
+ super(...arguments);
2942
+ this.value = "";
2943
+ this.variant = "default";
2944
+ this.disabled = false;
2945
+ this.handleSelect = () => {
2946
+ if (this.disabled) return;
2947
+ emitEvent(this, "ds:select", {
2948
+ detail: { value: this.value },
2949
+ bubbles: true
2950
+ });
2951
+ };
2952
+ this.handleKeyDown = (event) => {
2953
+ if (this.disabled) return;
2954
+ if (event.key === "Enter" || event.key === " ") {
2955
+ event.preventDefault();
2956
+ this.handleSelect();
2957
+ }
2958
+ };
2959
+ }
2960
+ connectedCallback() {
2961
+ super.connectedCallback();
2962
+ this.setAttribute("role", "menuitem");
2963
+ this.setAttribute("tabindex", "-1");
2964
+ this.addEventListener("click", this.handleSelect);
2965
+ this.addEventListener("keydown", this.handleKeyDown);
2966
+ }
2967
+ disconnectedCallback() {
2968
+ super.disconnectedCallback();
2969
+ this.removeEventListener("click", this.handleSelect);
2970
+ this.removeEventListener("keydown", this.handleKeyDown);
2971
+ }
2972
+ updated(changedProperties) {
2973
+ if (changedProperties.has("disabled")) {
2974
+ this.setAttribute("aria-disabled", String(this.disabled));
2975
+ }
2976
+ }
2977
+ render() {
2978
+ return html44`<slot></slot>`;
2979
+ }
2980
+ };
2981
+ __decorateClass([
2982
+ property23()
2983
+ ], DsContextMenuItem.prototype, "value", 2);
2984
+ __decorateClass([
2985
+ property23({ reflect: true })
2986
+ ], DsContextMenuItem.prototype, "variant", 2);
2987
+ __decorateClass([
2988
+ property23({ type: Boolean, reflect: true })
2989
+ ], DsContextMenuItem.prototype, "disabled", 2);
2990
+ define("ds-context-menu-item", DsContextMenuItem);
2991
+
2992
+ // src/components/context-menu/context-menu-separator.ts
2993
+ import { html as html45 } from "lit";
2994
+ var DsContextMenuSeparator = class extends DSElement {
2995
+ connectedCallback() {
2996
+ super.connectedCallback();
2997
+ this.setAttribute("role", "separator");
2998
+ }
2999
+ render() {
3000
+ return html45``;
3001
+ }
3002
+ };
3003
+ define("ds-context-menu-separator", DsContextMenuSeparator);
3004
+
3005
+ // src/components/context-menu/context-menu-label.ts
3006
+ import { html as html46 } from "lit";
3007
+ var DsContextMenuLabel = class extends DSElement {
3008
+ connectedCallback() {
3009
+ super.connectedCallback();
3010
+ this.setAttribute("aria-hidden", "true");
3011
+ }
3012
+ render() {
3013
+ return html46`<slot></slot>`;
3014
+ }
3015
+ };
3016
+ define("ds-context-menu-label", DsContextMenuLabel);
3017
+
3018
+ // src/components/context-menu/context-menu.ts
3019
+ import {
3020
+ createMenuBehavior as createMenuBehavior2,
3021
+ createPresence as createPresence9,
3022
+ prefersReducedMotion as prefersReducedMotion9
3023
+ } from "@hypoth-ui/primitives-dom";
3024
+ import { html as html47 } from "lit";
3025
+ import { property as property24, state as state8 } from "lit/decorators.js";
3026
+ var DsContextMenu = class extends DSElement {
3027
+ constructor() {
3028
+ super(...arguments);
3029
+ this.open = false;
3030
+ this.animated = true;
3031
+ this.pointerX = 0;
3032
+ this.pointerY = 0;
3033
+ this.menuBehavior = null;
3034
+ this.presence = null;
3035
+ this.longPressTimer = null;
3036
+ this.handleContextMenu = (event) => {
3037
+ const target = event.target;
3038
+ const trigger = target.closest('[slot="trigger"]');
3039
+ if (trigger && this.contains(trigger)) {
3040
+ event.preventDefault();
3041
+ this.show(event.clientX, event.clientY);
3042
+ }
3043
+ };
3044
+ this.handleTouchStart = (event) => {
3045
+ const target = event.target;
3046
+ const trigger = target.closest('[slot="trigger"]');
3047
+ if (trigger && this.contains(trigger)) {
3048
+ const touch = event.touches[0];
3049
+ if (touch) {
3050
+ this.longPressTimer = setTimeout(() => {
3051
+ this.show(touch.clientX, touch.clientY);
3052
+ }, 500);
3053
+ }
3054
+ }
3055
+ };
3056
+ this.handleTouchEnd = () => {
3057
+ if (this.longPressTimer) {
3058
+ clearTimeout(this.longPressTimer);
3059
+ this.longPressTimer = null;
3060
+ }
3061
+ };
3062
+ this.handleTouchMove = () => {
3063
+ if (this.longPressTimer) {
3064
+ clearTimeout(this.longPressTimer);
3065
+ this.longPressTimer = null;
3066
+ }
3067
+ };
3068
+ this.handleItemSelect = () => {
3069
+ this.close();
3070
+ };
3071
+ }
3072
+ connectedCallback() {
3073
+ super.connectedCallback();
3074
+ this.addEventListener("contextmenu", this.handleContextMenu);
3075
+ this.addEventListener("touchstart", this.handleTouchStart, { passive: true });
3076
+ this.addEventListener("touchend", this.handleTouchEnd, { passive: true });
3077
+ this.addEventListener("touchmove", this.handleTouchMove, { passive: true });
3078
+ this.addEventListener("ds:select", this.handleItemSelect);
3079
+ this.initMenuBehavior();
3080
+ }
3081
+ disconnectedCallback() {
3082
+ super.disconnectedCallback();
3083
+ this.removeEventListener("contextmenu", this.handleContextMenu);
3084
+ this.removeEventListener("touchstart", this.handleTouchStart);
3085
+ this.removeEventListener("touchend", this.handleTouchEnd);
3086
+ this.removeEventListener("touchmove", this.handleTouchMove);
3087
+ this.removeEventListener("ds:select", this.handleItemSelect);
3088
+ this.cleanup();
3089
+ }
3090
+ /**
3091
+ * Initializes the menu behavior primitive.
3092
+ */
3093
+ initMenuBehavior() {
3094
+ this.menuBehavior = createMenuBehavior2({
3095
+ defaultOpen: this.open,
3096
+ loop: true,
3097
+ onOpenChange: (open) => {
3098
+ if (!open && this.open) {
3099
+ this.handleBehaviorClose();
3100
+ }
3101
+ },
3102
+ onSelect: (value) => {
3103
+ emitEvent(this, StandardEvents.SELECT, { detail: { value } });
3104
+ }
3105
+ });
3106
+ }
3107
+ /**
3108
+ * Handles close triggered by the behavior (escape/outside click).
3109
+ */
3110
+ handleBehaviorClose() {
3111
+ const content = this.querySelector("ds-context-menu-content");
3112
+ if (this.animated && content && !prefersReducedMotion9()) {
3113
+ this.presence = createPresence9({
3114
+ onExitComplete: () => {
3115
+ this.completeClose();
3116
+ }
3117
+ });
3118
+ this.presence.hide(content);
3119
+ } else {
3120
+ this.open = false;
3121
+ emitEvent(this, StandardEvents.CLOSE);
3122
+ }
3123
+ }
3124
+ /**
3125
+ * Opens the menu at the specified position.
3126
+ */
3127
+ show(x, y) {
3128
+ if (this.open) {
3129
+ this.close();
3130
+ }
3131
+ this.pointerX = x;
3132
+ this.pointerY = y;
3133
+ this.open = true;
3134
+ this.menuBehavior?.open("first");
3135
+ emitEvent(this, StandardEvents.OPEN);
3136
+ }
3137
+ /**
3138
+ * Closes the menu.
3139
+ */
3140
+ close() {
3141
+ if (!this.open) return;
3142
+ const content = this.querySelector("ds-context-menu-content");
3143
+ this.menuBehavior?.close();
3144
+ if (this.animated && content && !prefersReducedMotion9()) {
3145
+ this.presence = createPresence9({
3146
+ onExitComplete: () => {
3147
+ this.completeClose();
3148
+ }
3149
+ });
3150
+ this.presence.hide(content);
3151
+ } else {
3152
+ this.open = false;
3153
+ emitEvent(this, StandardEvents.CLOSE);
3154
+ }
3155
+ }
3156
+ completeClose() {
3157
+ this.presence?.destroy();
3158
+ this.presence = null;
3159
+ this.open = false;
3160
+ emitEvent(this, StandardEvents.CLOSE);
3161
+ }
3162
+ positionContent() {
3163
+ const content = this.querySelector("ds-context-menu-content");
3164
+ if (!content) return;
3165
+ let x = this.pointerX;
3166
+ let y = this.pointerY;
3167
+ const rect = content.getBoundingClientRect();
3168
+ const viewportWidth = window.innerWidth;
3169
+ const viewportHeight = window.innerHeight;
3170
+ if (x + rect.width > viewportWidth) {
3171
+ x = viewportWidth - rect.width - 8;
3172
+ }
3173
+ if (y + rect.height > viewportHeight) {
3174
+ y = viewportHeight - rect.height - 8;
3175
+ }
3176
+ x = Math.max(8, x);
3177
+ y = Math.max(8, y);
3178
+ content.style.left = `${x}px`;
3179
+ content.style.top = `${y}px`;
3180
+ }
3181
+ registerMenuItems() {
3182
+ const content = this.querySelector("ds-context-menu-content");
3183
+ if (!content || !this.menuBehavior) return;
3184
+ const items = content.querySelectorAll("ds-context-menu-item:not([disabled])");
3185
+ items.forEach((item) => {
3186
+ this.menuBehavior?.registerItem(item);
3187
+ });
3188
+ }
3189
+ cleanup() {
3190
+ this.menuBehavior?.destroy();
3191
+ this.menuBehavior = null;
3192
+ this.presence?.destroy();
3193
+ this.presence = null;
3194
+ if (this.longPressTimer) {
3195
+ clearTimeout(this.longPressTimer);
3196
+ this.longPressTimer = null;
3197
+ }
3198
+ }
3199
+ async updated(changedProperties) {
3200
+ super.updated(changedProperties);
3201
+ if (changedProperties.has("open")) {
3202
+ const content = this.querySelector("ds-context-menu-content");
3203
+ if (this.open) {
3204
+ content?.removeAttribute("hidden");
3205
+ if (content) {
3206
+ content.dataState = "open";
3207
+ }
3208
+ await this.updateComplete;
3209
+ this.positionContent();
3210
+ this.registerMenuItems();
3211
+ this.menuBehavior?.setContentElement(content);
3212
+ } else {
3213
+ content?.setAttribute("hidden", "");
3214
+ this.menuBehavior?.setContentElement(null);
3215
+ }
3216
+ }
3217
+ }
3218
+ render() {
3219
+ return html47`
3220
+ <slot name="trigger"></slot>
3221
+ <slot></slot>
3222
+ `;
3223
+ }
3224
+ };
3225
+ __decorateClass([
3226
+ property24({ type: Boolean, reflect: true })
3227
+ ], DsContextMenu.prototype, "open", 2);
3228
+ __decorateClass([
3229
+ property24({ type: Boolean })
3230
+ ], DsContextMenu.prototype, "animated", 2);
3231
+ __decorateClass([
3232
+ state8()
3233
+ ], DsContextMenu.prototype, "pointerX", 2);
3234
+ __decorateClass([
3235
+ state8()
3236
+ ], DsContextMenu.prototype, "pointerY", 2);
3237
+ define("ds-context-menu", DsContextMenu);
3238
+
3239
+ // src/components/hover-card/hover-card-content.ts
3240
+ import { html as html48 } from "lit";
3241
+ import { property as property25 } from "lit/decorators.js";
3242
+ var DsHoverCardContent = class extends DSElement {
3243
+ constructor() {
3244
+ super(...arguments);
3245
+ this.id = "";
3246
+ this.dataState = "closed";
3247
+ }
3248
+ connectedCallback() {
3249
+ super.connectedCallback();
3250
+ if (!this.id) {
3251
+ this.id = `hover-card-content-${crypto.randomUUID().slice(0, 8)}`;
3252
+ }
3253
+ this.setAttribute("hidden", "");
3254
+ }
3255
+ render() {
3256
+ return html48`<slot></slot>`;
3257
+ }
3258
+ };
3259
+ __decorateClass([
3260
+ property25({ type: String, reflect: true })
3261
+ ], DsHoverCardContent.prototype, "id", 2);
3262
+ __decorateClass([
3263
+ property25({ type: String, reflect: true, attribute: "data-state" })
3264
+ ], DsHoverCardContent.prototype, "dataState", 2);
3265
+ define("ds-hover-card-content", DsHoverCardContent);
3266
+
3267
+ // src/components/hover-card/hover-card.ts
3268
+ import {
3269
+ createAnchorPosition as createAnchorPosition4,
3270
+ createDismissableLayer as createDismissableLayer3,
3271
+ createPresence as createPresence10,
3272
+ prefersReducedMotion as prefersReducedMotion10
3273
+ } from "@hypoth-ui/primitives-dom";
3274
+ import { html as html49 } from "lit";
3275
+ import { property as property26 } from "lit/decorators.js";
3276
+ var DsHoverCard = class extends DSElement {
3277
+ constructor() {
3278
+ super(...arguments);
3279
+ this.open = false;
3280
+ this.placement = "bottom";
3281
+ this.offset = 8;
3282
+ this.flip = true;
3283
+ this.openDelay = 700;
3284
+ this.closeDelay = 300;
3285
+ this.animated = true;
3286
+ this.anchorPosition = null;
3287
+ this.dismissLayer = null;
3288
+ this.presence = null;
3289
+ this.resizeObserver = null;
3290
+ this.scrollHandler = null;
3291
+ this.openTimer = null;
3292
+ this.closeTimer = null;
3293
+ this.isHoveringTrigger = false;
3294
+ this.isHoveringContent = false;
3295
+ this.handleTriggerMouseEnter = (event) => {
3296
+ const target = event.target;
3297
+ const trigger = target.closest('[slot="trigger"]');
3298
+ const content = target.closest("ds-hover-card-content");
3299
+ if (trigger && this.contains(trigger)) {
3300
+ this.isHoveringTrigger = true;
3301
+ this.scheduleOpen();
3302
+ } else if (content && this.contains(content)) {
3303
+ this.isHoveringContent = true;
3304
+ this.cancelClose();
3305
+ }
3306
+ };
3307
+ this.handleTriggerMouseLeave = (event) => {
3308
+ const target = event.target;
3309
+ const trigger = target.closest('[slot="trigger"]');
3310
+ const content = target.closest("ds-hover-card-content");
3311
+ if (trigger && this.contains(trigger)) {
3312
+ this.isHoveringTrigger = false;
3313
+ this.scheduleClose();
3314
+ } else if (content && this.contains(content)) {
3315
+ this.isHoveringContent = false;
3316
+ this.scheduleClose();
3317
+ }
3318
+ };
3319
+ this.handleFocusIn = (event) => {
3320
+ const target = event.target;
3321
+ const trigger = target.closest('[slot="trigger"]');
3322
+ if (trigger && this.contains(trigger)) {
3323
+ this.clearTimers();
3324
+ this.show();
3325
+ }
3326
+ };
3327
+ this.handleFocusOut = (event) => {
3328
+ const relatedTarget = event.relatedTarget;
3329
+ if (relatedTarget && this.contains(relatedTarget)) {
3330
+ return;
3331
+ }
3332
+ this.scheduleClose();
3333
+ };
3334
+ this.handleDismiss = () => {
3335
+ this.close();
3336
+ };
3337
+ }
3338
+ connectedCallback() {
3339
+ super.connectedCallback();
3340
+ this.addEventListener("mouseenter", this.handleTriggerMouseEnter, true);
3341
+ this.addEventListener("mouseleave", this.handleTriggerMouseLeave, true);
3342
+ this.addEventListener("focusin", this.handleFocusIn);
3343
+ this.addEventListener("focusout", this.handleFocusOut);
3344
+ this.updateComplete.then(() => {
3345
+ this.setupTriggerAccessibility();
3346
+ });
3347
+ }
3348
+ disconnectedCallback() {
3349
+ super.disconnectedCallback();
3350
+ this.removeEventListener("mouseenter", this.handleTriggerMouseEnter, true);
3351
+ this.removeEventListener("mouseleave", this.handleTriggerMouseLeave, true);
3352
+ this.removeEventListener("focusin", this.handleFocusIn);
3353
+ this.removeEventListener("focusout", this.handleFocusOut);
3354
+ this.clearTimers();
3355
+ this.cleanup();
3356
+ }
3357
+ /**
3358
+ * Opens the hover card.
3359
+ */
3360
+ show() {
3361
+ if (this.open) return;
3362
+ this.clearTimers();
3363
+ this.open = true;
3364
+ emitEvent(this, StandardEvents.OPEN);
3365
+ }
3366
+ /**
3367
+ * Closes the hover card.
3368
+ */
3369
+ close() {
3370
+ if (!this.open) return;
3371
+ this.clearTimers();
3372
+ const content = this.querySelector("ds-hover-card-content");
3373
+ if (this.animated && content && !prefersReducedMotion10()) {
3374
+ this.dismissLayer?.deactivate();
3375
+ this.dismissLayer = null;
3376
+ this.presence = createPresence10({
3377
+ onExitComplete: () => {
3378
+ this.completeClose();
3379
+ }
3380
+ });
3381
+ this.presence.hide(content);
3382
+ } else {
3383
+ this.cleanup();
3384
+ this.open = false;
3385
+ emitEvent(this, StandardEvents.CLOSE);
3386
+ }
3387
+ }
3388
+ completeClose() {
3389
+ this.cleanup();
3390
+ this.open = false;
3391
+ emitEvent(this, StandardEvents.CLOSE);
3392
+ }
3393
+ clearTimers() {
3394
+ if (this.openTimer) {
3395
+ clearTimeout(this.openTimer);
3396
+ this.openTimer = null;
3397
+ }
3398
+ if (this.closeTimer) {
3399
+ clearTimeout(this.closeTimer);
3400
+ this.closeTimer = null;
3401
+ }
3402
+ }
3403
+ scheduleOpen() {
3404
+ this.cancelClose();
3405
+ if (this.open) return;
3406
+ this.openTimer = setTimeout(() => {
3407
+ this.show();
3408
+ }, this.openDelay);
3409
+ }
3410
+ scheduleClose() {
3411
+ this.cancelOpen();
3412
+ if (this.isHoveringTrigger || this.isHoveringContent) {
3413
+ return;
3414
+ }
3415
+ if (!this.open) return;
3416
+ this.closeTimer = setTimeout(() => {
3417
+ this.close();
3418
+ }, this.closeDelay);
3419
+ }
3420
+ cancelOpen() {
3421
+ if (this.openTimer) {
3422
+ clearTimeout(this.openTimer);
3423
+ this.openTimer = null;
3424
+ }
3425
+ }
3426
+ cancelClose() {
3427
+ if (this.closeTimer) {
3428
+ clearTimeout(this.closeTimer);
3429
+ this.closeTimer = null;
3430
+ }
3431
+ }
3432
+ setupTriggerAccessibility() {
3433
+ const trigger = this.querySelector('[slot="trigger"]');
3434
+ const content = this.querySelector("ds-hover-card-content");
3435
+ if (trigger && content) {
3436
+ trigger.setAttribute("aria-haspopup", "true");
3437
+ trigger.setAttribute("aria-expanded", String(this.open));
3438
+ if (content.id) {
3439
+ trigger.setAttribute("aria-controls", content.id);
3440
+ }
3441
+ }
3442
+ }
3443
+ updateTriggerAria() {
3444
+ const trigger = this.querySelector('[slot="trigger"]');
3445
+ if (trigger) {
3446
+ trigger.setAttribute("aria-expanded", String(this.open));
3447
+ }
3448
+ }
3449
+ setupPositioning() {
3450
+ const trigger = this.querySelector('[slot="trigger"]');
3451
+ const content = this.querySelector("ds-hover-card-content");
3452
+ if (!trigger || !content) return;
3453
+ this.anchorPosition = createAnchorPosition4({
3454
+ anchor: trigger,
3455
+ floating: content,
3456
+ placement: this.placement,
3457
+ offset: this.offset,
3458
+ flip: this.flip,
3459
+ onPositionChange: (pos) => {
3460
+ content.setAttribute("data-placement", pos.placement);
3461
+ }
3462
+ });
3463
+ this.resizeObserver = new ResizeObserver(() => {
3464
+ this.anchorPosition?.update();
3465
+ });
3466
+ this.resizeObserver.observe(trigger);
3467
+ this.resizeObserver.observe(content);
3468
+ this.scrollHandler = () => {
3469
+ this.anchorPosition?.update();
3470
+ };
3471
+ window.addEventListener("scroll", this.scrollHandler, { passive: true });
3472
+ window.addEventListener("resize", this.scrollHandler, { passive: true });
3473
+ }
3474
+ setupDismissLayer() {
3475
+ const content = this.querySelector("ds-hover-card-content");
3476
+ const trigger = this.querySelector('[slot="trigger"]');
3477
+ if (!content) return;
3478
+ this.dismissLayer = createDismissableLayer3({
3479
+ container: content,
3480
+ excludeElements: trigger ? [trigger] : [],
3481
+ onDismiss: this.handleDismiss,
3482
+ closeOnEscape: true,
3483
+ closeOnOutsideClick: false
3484
+ // Non-modal, only close on escape
3485
+ });
3486
+ this.dismissLayer.activate();
3487
+ }
3488
+ cleanup() {
3489
+ this.anchorPosition?.destroy();
3490
+ this.anchorPosition = null;
3491
+ this.dismissLayer?.deactivate();
3492
+ this.dismissLayer = null;
3493
+ this.presence?.destroy();
3494
+ this.presence = null;
3495
+ this.resizeObserver?.disconnect();
3496
+ this.resizeObserver = null;
3497
+ if (this.scrollHandler) {
3498
+ window.removeEventListener("scroll", this.scrollHandler);
3499
+ window.removeEventListener("resize", this.scrollHandler);
3500
+ this.scrollHandler = null;
3501
+ }
3502
+ }
3503
+ async updated(changedProperties) {
3504
+ super.updated(changedProperties);
3505
+ if (changedProperties.has("open")) {
3506
+ this.updateTriggerAria();
3507
+ const content = this.querySelector("ds-hover-card-content");
3508
+ if (this.open) {
3509
+ content?.removeAttribute("hidden");
3510
+ if (content) {
3511
+ content.dataState = "open";
3512
+ }
3513
+ await this.updateComplete;
3514
+ this.setupPositioning();
3515
+ this.setupDismissLayer();
3516
+ } else {
3517
+ content?.setAttribute("hidden", "");
3518
+ }
3519
+ }
3520
+ }
3521
+ render() {
3522
+ return html49`
3523
+ <slot name="trigger"></slot>
3524
+ <slot></slot>
3525
+ `;
3526
+ }
3527
+ };
3528
+ __decorateClass([
3529
+ property26({ type: Boolean, reflect: true })
3530
+ ], DsHoverCard.prototype, "open", 2);
3531
+ __decorateClass([
3532
+ property26({ type: String, reflect: true })
3533
+ ], DsHoverCard.prototype, "placement", 2);
3534
+ __decorateClass([
3535
+ property26({ type: Number })
3536
+ ], DsHoverCard.prototype, "offset", 2);
3537
+ __decorateClass([
3538
+ property26({ type: Boolean })
3539
+ ], DsHoverCard.prototype, "flip", 2);
3540
+ __decorateClass([
3541
+ property26({ type: Number, attribute: "open-delay" })
3542
+ ], DsHoverCard.prototype, "openDelay", 2);
3543
+ __decorateClass([
3544
+ property26({ type: Number, attribute: "close-delay" })
3545
+ ], DsHoverCard.prototype, "closeDelay", 2);
3546
+ __decorateClass([
3547
+ property26({ type: Boolean })
3548
+ ], DsHoverCard.prototype, "animated", 2);
3549
+ define("ds-hover-card", DsHoverCard);
3550
+
3551
+ export {
3552
+ DsDialogContent,
3553
+ DsDialogTitle,
3554
+ DsDialogDescription,
3555
+ DsDialog,
3556
+ DsPopoverContent,
3557
+ DsPopover,
3558
+ DsTooltipContent,
3559
+ DsTooltip,
3560
+ DsMenuContent,
3561
+ DsMenuItem,
3562
+ DsMenu,
3563
+ DsAlertDialogContent,
3564
+ DsAlertDialogHeader,
3565
+ DsAlertDialogFooter,
3566
+ DsAlertDialogTitle,
3567
+ DsAlertDialogDescription,
3568
+ DsAlertDialogAction,
3569
+ DsAlertDialogCancel,
3570
+ DsAlertDialog,
3571
+ DsAlertDialogTrigger,
3572
+ DsSheetContent,
3573
+ DsSheetOverlay,
3574
+ DsSheetHeader,
3575
+ DsSheetFooter,
3576
+ DsSheetTitle,
3577
+ DsSheetDescription,
3578
+ DsSheetClose,
3579
+ DsSheet,
3580
+ DsDrawerContent,
3581
+ DsDrawerHeader,
3582
+ DsDrawerFooter,
3583
+ DsDrawerTitle,
3584
+ DsDrawerDescription,
3585
+ DsDrawer,
3586
+ DsDropdownMenuContent,
3587
+ DsDropdownMenuItem,
3588
+ DsDropdownMenuSeparator,
3589
+ DsDropdownMenuLabel,
3590
+ DsDropdownMenuCheckboxItem,
3591
+ DsDropdownMenuRadioGroup,
3592
+ DsDropdownMenuRadioItem,
3593
+ DsDropdownMenu,
3594
+ DsContextMenuContent,
3595
+ DsContextMenuItem,
3596
+ DsContextMenuSeparator,
3597
+ DsContextMenuLabel,
3598
+ DsContextMenu,
3599
+ DsHoverCardContent,
3600
+ DsHoverCard
3601
+ };
3602
+ //# sourceMappingURL=chunk-55ID7LJL.js.map