@sekiui/elements 0.0.88 → 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 (211) hide show
  1. package/dist/cdn/p-C9-yH6MD.js +33 -0
  2. package/dist/cdn/p-CQQRfw1L.js +18 -0
  3. package/dist/cdn/seki-carousel-dots.js +7 -3
  4. package/dist/cdn/seki-carousel-next.js +8 -6
  5. package/dist/cdn/seki-carousel-previous.js +8 -6
  6. package/dist/cdn/seki-carousel.js +15 -1
  7. package/dist/cdn/seki-date-picker.js +71 -36
  8. package/dist/cdn/seki-drawer.js +76 -32
  9. package/dist/cdn/seki-hover-card-content.js +2 -2
  10. package/dist/cdn/seki-hover-card-trigger.js +3 -3
  11. package/dist/cdn/seki-hover-card.js +59 -4
  12. package/dist/cdn/seki-resizable-handle.js +11 -2
  13. package/dist/cdn/seki-resizable-panel-group.js +9 -3
  14. package/dist/cdn/seki-resizable-panel.js +42 -20
  15. package/dist/cdn/seki-select-content.js +21 -13
  16. package/dist/cdn/seki-select-group.js +3 -4
  17. package/dist/cdn/seki-select-option.js +33 -15
  18. package/dist/cdn/seki-select-trigger.js +6 -4
  19. package/dist/cdn/seki-select.js +2 -2
  20. package/dist/cdn/seki-sheet.js +71 -30
  21. package/dist/cdn/seki-sidebar-footer.js +3 -1
  22. package/dist/cdn/seki-sidebar-header.js +3 -1
  23. package/dist/cdn/seki-sidebar-menu-button.js +3 -1
  24. package/dist/cdn/seki-sidebar-rail.js +3 -1
  25. package/dist/cdn/seki-sidebar-trigger.js +6 -1
  26. package/dist/cdn/seki-sidebar.js +5 -2
  27. package/dist/cdn/seki-tooltip.js +47 -2
  28. package/dist/cjs/loader.cjs.js +1 -1
  29. package/dist/cjs/option-id-wIa73qWK.js +20 -0
  30. package/dist/cjs/seki-carousel-dots.cjs.entry.js +7 -3
  31. package/dist/cjs/seki-carousel-next.cjs.entry.js +8 -6
  32. package/dist/cjs/seki-carousel-previous.cjs.entry.js +8 -6
  33. package/dist/cjs/seki-carousel.cjs.entry.js +15 -1
  34. package/dist/cjs/seki-date-picker.cjs.entry.js +64 -32
  35. package/dist/cjs/seki-drawer.cjs.entry.js +67 -27
  36. package/dist/cjs/seki-hover-card-content.cjs.entry.js +2 -2
  37. package/dist/cjs/seki-hover-card-trigger.cjs.entry.js +3 -3
  38. package/dist/cjs/seki-hover-card.cjs.entry.js +53 -3
  39. package/dist/cjs/seki-resizable-handle.cjs.entry.js +11 -2
  40. package/dist/cjs/seki-resizable-panel-group.cjs.entry.js +9 -3
  41. package/dist/cjs/seki-resizable-panel.cjs.entry.js +42 -20
  42. package/dist/cjs/seki-select-content.cjs.entry.js +20 -11
  43. package/dist/cjs/seki-select-group.cjs.entry.js +2 -2
  44. package/dist/cjs/seki-select-option.cjs.entry.js +32 -13
  45. package/dist/cjs/seki-select-trigger.cjs.entry.js +5 -2
  46. package/dist/cjs/seki-select.cjs.entry.js +2 -2
  47. package/dist/cjs/seki-sheet.cjs.entry.js +62 -25
  48. package/dist/cjs/seki-sidebar-footer.cjs.entry.js +3 -1
  49. package/dist/cjs/seki-sidebar-header.cjs.entry.js +3 -1
  50. package/dist/cjs/seki-sidebar-menu-button.cjs.entry.js +3 -1
  51. package/dist/cjs/seki-sidebar-rail.cjs.entry.js +3 -1
  52. package/dist/cjs/seki-sidebar-trigger.cjs.entry.js +6 -1
  53. package/dist/cjs/seki-sidebar.cjs.entry.js +5 -2
  54. package/dist/cjs/seki-tooltip.cjs.entry.js +43 -2
  55. package/dist/cjs/sekiui.cjs.js +1 -1
  56. package/dist/cjs/when-defined-B2Lkz6uR.js +36 -0
  57. package/dist/collection/components/carousel/seki-carousel-dots.js +7 -3
  58. package/dist/collection/components/carousel/seki-carousel-next.js +8 -6
  59. package/dist/collection/components/carousel/seki-carousel-previous.js +8 -6
  60. package/dist/collection/components/carousel/seki-carousel.js +15 -1
  61. package/dist/collection/components/date-picker/seki-date-picker.js +124 -36
  62. package/dist/collection/components/drawer/seki-drawer.js +132 -31
  63. package/dist/collection/components/hover-card/seki-hover-card-content.js +2 -2
  64. package/dist/collection/components/hover-card/seki-hover-card-trigger.js +3 -3
  65. package/dist/collection/components/hover-card/seki-hover-card.js +142 -6
  66. package/dist/collection/components/resizable/seki-resizable-handle.js +11 -2
  67. package/dist/collection/components/resizable/seki-resizable-panel-group.js +23 -3
  68. package/dist/collection/components/resizable/seki-resizable-panel.js +42 -20
  69. package/dist/collection/components/select/seki-select.js +6 -12
  70. package/dist/collection/components/select-content/seki-select-content.css +8 -0
  71. package/dist/collection/components/select-content/seki-select-content.js +20 -11
  72. package/dist/collection/components/select-group/seki-select-group.js +2 -2
  73. package/dist/collection/components/select-option/seki-select-option.js +32 -13
  74. package/dist/collection/components/select-trigger/seki-select-trigger.js +5 -2
  75. package/dist/collection/components/sheet/seki-sheet.js +127 -29
  76. package/dist/collection/components/sidebar/seki-sidebar-footer.js +3 -1
  77. package/dist/collection/components/sidebar/seki-sidebar-header.js +3 -1
  78. package/dist/collection/components/sidebar/seki-sidebar-menu-button.js +3 -1
  79. package/dist/collection/components/sidebar/seki-sidebar-rail.js +3 -1
  80. package/dist/collection/components/sidebar/seki-sidebar-trigger.js +6 -1
  81. package/dist/collection/components/sidebar/seki-sidebar.js +5 -2
  82. package/dist/collection/components/tooltip/seki-tooltip.js +92 -2
  83. package/dist/collection/utils/select/index.js +1 -0
  84. package/dist/collection/utils/select/option-id.js +16 -0
  85. package/dist/collection/utils/when-defined.js +31 -0
  86. package/dist/components/p-C9-yH6MD.js +33 -0
  87. package/dist/components/p-CQQRfw1L.js +18 -0
  88. package/dist/components/seki-carousel-dots.js +7 -3
  89. package/dist/components/seki-carousel-next.js +8 -6
  90. package/dist/components/seki-carousel-previous.js +8 -6
  91. package/dist/components/seki-carousel.js +15 -1
  92. package/dist/components/seki-date-picker.js +71 -36
  93. package/dist/components/seki-drawer.js +76 -32
  94. package/dist/components/seki-hover-card-content.js +2 -2
  95. package/dist/components/seki-hover-card-trigger.js +3 -3
  96. package/dist/components/seki-hover-card.js +59 -4
  97. package/dist/components/seki-resizable-handle.js +11 -2
  98. package/dist/components/seki-resizable-panel-group.js +9 -3
  99. package/dist/components/seki-resizable-panel.js +42 -20
  100. package/dist/components/seki-select-content.js +21 -13
  101. package/dist/components/seki-select-group.js +3 -4
  102. package/dist/components/seki-select-option.js +33 -15
  103. package/dist/components/seki-select-trigger.js +6 -4
  104. package/dist/components/seki-select.js +2 -2
  105. package/dist/components/seki-sheet.js +71 -30
  106. package/dist/components/seki-sidebar-footer.js +3 -1
  107. package/dist/components/seki-sidebar-header.js +3 -1
  108. package/dist/components/seki-sidebar-menu-button.js +3 -1
  109. package/dist/components/seki-sidebar-rail.js +3 -1
  110. package/dist/components/seki-sidebar-trigger.js +6 -1
  111. package/dist/components/seki-sidebar.js +5 -2
  112. package/dist/components/seki-tooltip.js +47 -2
  113. package/dist/esm/loader.js +1 -1
  114. package/dist/esm/option-id-CQQRfw1L.js +18 -0
  115. package/dist/esm/seki-carousel-dots.entry.js +7 -3
  116. package/dist/esm/seki-carousel-next.entry.js +8 -6
  117. package/dist/esm/seki-carousel-previous.entry.js +8 -6
  118. package/dist/esm/seki-carousel.entry.js +15 -1
  119. package/dist/esm/seki-date-picker.entry.js +64 -32
  120. package/dist/esm/seki-drawer.entry.js +67 -27
  121. package/dist/esm/seki-hover-card-content.entry.js +2 -2
  122. package/dist/esm/seki-hover-card-trigger.entry.js +3 -3
  123. package/dist/esm/seki-hover-card.entry.js +53 -3
  124. package/dist/esm/seki-resizable-handle.entry.js +11 -2
  125. package/dist/esm/seki-resizable-panel-group.entry.js +9 -3
  126. package/dist/esm/seki-resizable-panel.entry.js +42 -20
  127. package/dist/esm/seki-select-content.entry.js +20 -11
  128. package/dist/esm/seki-select-group.entry.js +2 -2
  129. package/dist/esm/seki-select-option.entry.js +32 -13
  130. package/dist/esm/seki-select-trigger.entry.js +5 -2
  131. package/dist/esm/seki-select.entry.js +2 -2
  132. package/dist/esm/seki-sheet.entry.js +62 -25
  133. package/dist/esm/seki-sidebar-footer.entry.js +3 -1
  134. package/dist/esm/seki-sidebar-header.entry.js +3 -1
  135. package/dist/esm/seki-sidebar-menu-button.entry.js +3 -1
  136. package/dist/esm/seki-sidebar-rail.entry.js +3 -1
  137. package/dist/esm/seki-sidebar-trigger.entry.js +6 -1
  138. package/dist/esm/seki-sidebar.entry.js +5 -2
  139. package/dist/esm/seki-tooltip.entry.js +43 -2
  140. package/dist/esm/sekiui.js +1 -1
  141. package/dist/esm/when-defined-C9-yH6MD.js +33 -0
  142. package/dist/sekiui/p-02f1728e.entry.js +1 -0
  143. package/dist/sekiui/p-05b33a61.entry.js +1 -0
  144. package/dist/sekiui/p-12e36a4f.entry.js +1 -0
  145. package/dist/sekiui/p-1cd6b3e6.entry.js +1 -0
  146. package/dist/sekiui/p-1e24698b.entry.js +1 -0
  147. package/dist/sekiui/p-26bb17cb.entry.js +1 -0
  148. package/dist/sekiui/p-26d433ff.entry.js +1 -0
  149. package/dist/sekiui/p-26f96e2d.entry.js +1 -0
  150. package/dist/sekiui/p-29b22c0f.entry.js +1 -0
  151. package/dist/sekiui/p-30fafcc6.entry.js +1 -0
  152. package/dist/sekiui/p-3de5878b.entry.js +1 -0
  153. package/dist/sekiui/p-649dbdf0.entry.js +1 -0
  154. package/dist/sekiui/p-71656184.entry.js +1 -0
  155. package/dist/sekiui/p-7926c04a.entry.js +1 -0
  156. package/dist/sekiui/p-9f4149b9.entry.js +1 -0
  157. package/dist/sekiui/p-C9-yH6MD.js +1 -0
  158. package/dist/sekiui/p-CQQRfw1L.js +1 -0
  159. package/dist/sekiui/p-ae87ca35.entry.js +1 -0
  160. package/dist/sekiui/p-b82c2267.entry.js +1 -0
  161. package/dist/sekiui/p-bf151423.entry.js +1 -0
  162. package/dist/sekiui/{p-219c8350.entry.js → p-c0f21b6a.entry.js} +1 -1
  163. package/dist/sekiui/p-c3ef507f.entry.js +1 -0
  164. package/dist/sekiui/p-d10a186d.entry.js +1 -0
  165. package/dist/sekiui/p-d1c72c91.entry.js +1 -0
  166. package/dist/sekiui/p-d1d3ae40.entry.js +1 -0
  167. package/dist/sekiui/p-fba3fa73.entry.js +1 -0
  168. package/dist/sekiui/p-fe3e661d.entry.js +1 -0
  169. package/dist/sekiui/sekiui.esm.js +1 -1
  170. package/dist/types/components/carousel/seki-carousel.d.ts +1 -0
  171. package/dist/types/components/date-picker/seki-date-picker.d.ts +21 -5
  172. package/dist/types/components/drawer/seki-drawer.d.ts +22 -6
  173. package/dist/types/components/hover-card/seki-hover-card.d.ts +24 -4
  174. package/dist/types/components/resizable/seki-resizable-handle.d.ts +1 -0
  175. package/dist/types/components/resizable/seki-resizable-panel-group.d.ts +6 -0
  176. package/dist/types/components/resizable/seki-resizable-panel.d.ts +9 -0
  177. package/dist/types/components/select/seki-select.d.ts +3 -3
  178. package/dist/types/components/select-content/seki-select-content.d.ts +8 -5
  179. package/dist/types/components/select-option/seki-select-option.d.ts +6 -4
  180. package/dist/types/components/sheet/seki-sheet.d.ts +22 -6
  181. package/dist/types/components/tooltip/seki-tooltip.d.ts +13 -0
  182. package/dist/types/components.d.ts +145 -17
  183. package/dist/types/utils/select/index.d.ts +1 -0
  184. package/dist/types/utils/select/option-id.d.ts +14 -0
  185. package/dist/types/utils/select/types.d.ts +0 -7
  186. package/dist/types/utils/when-defined.d.ts +19 -0
  187. package/package.json +3 -1
  188. package/dist/sekiui/p-01f26bec.entry.js +0 -1
  189. package/dist/sekiui/p-117b6f5a.entry.js +0 -1
  190. package/dist/sekiui/p-1250cad1.entry.js +0 -1
  191. package/dist/sekiui/p-1866201e.entry.js +0 -1
  192. package/dist/sekiui/p-2e18933c.entry.js +0 -1
  193. package/dist/sekiui/p-2e2e7d0b.entry.js +0 -1
  194. package/dist/sekiui/p-346cc18f.entry.js +0 -1
  195. package/dist/sekiui/p-6311a4d8.entry.js +0 -1
  196. package/dist/sekiui/p-69843ed8.entry.js +0 -1
  197. package/dist/sekiui/p-779764c0.entry.js +0 -1
  198. package/dist/sekiui/p-786c153b.entry.js +0 -1
  199. package/dist/sekiui/p-87bcbb66.entry.js +0 -1
  200. package/dist/sekiui/p-88dd3e1f.entry.js +0 -1
  201. package/dist/sekiui/p-944c70a1.entry.js +0 -1
  202. package/dist/sekiui/p-9820cd16.entry.js +0 -1
  203. package/dist/sekiui/p-9abfa3a5.entry.js +0 -1
  204. package/dist/sekiui/p-ac7bd611.entry.js +0 -1
  205. package/dist/sekiui/p-b45e11d8.entry.js +0 -1
  206. package/dist/sekiui/p-c62c4ad7.entry.js +0 -1
  207. package/dist/sekiui/p-caa51bdf.entry.js +0 -1
  208. package/dist/sekiui/p-ce986fde.entry.js +0 -1
  209. package/dist/sekiui/p-e45e6992.entry.js +0 -1
  210. package/dist/sekiui/p-ede4bb0c.entry.js +0 -1
  211. package/dist/sekiui/p-f4abd9a2.entry.js +0 -1
@@ -41,6 +41,17 @@ export class SekiTooltip {
41
41
  * @min 0
42
42
  */
43
43
  this.offset = 8;
44
+ /**
45
+ * Controlled open state. Reflects to the `open` attribute, so
46
+ * `<seki-tooltip open>` renders visible with no script involved.
47
+ * @default false
48
+ */
49
+ this.open = false;
50
+ /**
51
+ * Initial open state for uncontrolled usage
52
+ * @default false
53
+ */
54
+ this.defaultOpen = false;
44
55
  /**
45
56
  * Internal state: whether tooltip is currently visible
46
57
  */
@@ -181,8 +192,11 @@ export class SekiTooltip {
181
192
  * @returns Promise resolves when tooltip is visible
182
193
  */
183
194
  async show() {
184
- if (this.disabled)
195
+ if (this.disabled) {
196
+ // Keep the reflected prop honest when a show request is refused.
197
+ this.open = false;
185
198
  return;
199
+ }
186
200
  // Clear any pending hide timer
187
201
  if (this.hideTimer) {
188
202
  clearTimeout(this.hideTimer);
@@ -190,6 +204,7 @@ export class SekiTooltip {
190
204
  }
191
205
  // Set visible state
192
206
  this.isVisible = true;
207
+ this.open = true;
193
208
  // Calculate position
194
209
  this.calculatePosition();
195
210
  // Emit show event
@@ -207,6 +222,7 @@ export class SekiTooltip {
207
222
  }
208
223
  // Set hidden state
209
224
  this.isVisible = false;
225
+ this.open = false;
210
226
  // Emit hide event
211
227
  this.hideTooltip.emit({ reason: 'blur' });
212
228
  }
@@ -338,9 +354,31 @@ export class SekiTooltip {
338
354
  // here so it does not leak (and keep firing) after the tooltip is detached.
339
355
  document.removeEventListener('keydown', this.onEscapeKey);
340
356
  }
357
+ componentWillLoad() {
358
+ // `disabled` wins over a requested initial open state.
359
+ this.isVisible = (this.open || this.defaultOpen) && !this.disabled;
360
+ this.open = this.isVisible;
361
+ }
341
362
  componentDidLoad() {
342
363
  this.hasLoaded = true;
343
364
  this.attachTriggerListeners();
365
+ if (this.isVisible) {
366
+ // Children are only in place now, so the initial position can finally be
367
+ // measured against the trigger.
368
+ this.calculatePosition();
369
+ }
370
+ }
371
+ openChanged(newValue) {
372
+ // An outside assignment (`tooltip.open = true`) has to win after first render;
373
+ // `open` is only read once in componentWillLoad otherwise.
374
+ if (newValue === this.isVisible)
375
+ return;
376
+ if (newValue) {
377
+ this.show();
378
+ }
379
+ else {
380
+ this.hide();
381
+ }
344
382
  }
345
383
  connectedCallback() {
346
384
  syncTheme(this.el);
@@ -363,7 +401,7 @@ export class SekiTooltip {
363
401
  clearTimeout(this.longPressTimer);
364
402
  }
365
403
  render() {
366
- return (h("div", { key: '70d4c876ab2b64a306893b555301ed08e438fff7', class: `tooltip ${this.isVisible ? 'tooltip--visible' : ''}`, role: "tooltip" }, h("slot", { key: '6bcde89ad0903a7859e1717c45204416554bd78f', name: "content" }), h("div", { key: '481b96927ad6431e0415fce2695fc1c13011aa72', class: "tooltip-arrow" })));
404
+ return (h("div", { key: 'd934fb59ac9e6b47e208113f430dbdf151e4b9d8', class: `tooltip ${this.isVisible ? 'tooltip--visible' : ''}`, role: "tooltip" }, h("slot", { key: '0fe73a7b7b0bcd405dec9a77ddcf0c4a7e2b4b09', name: "content" }), h("div", { key: '9917e3661c8740b69bdaca4e8e7aa168b0c7c47c', class: "tooltip-arrow" })));
367
405
  }
368
406
  static get is() { return "seki-tooltip"; }
369
407
  static get encapsulation() { return "shadow"; }
@@ -485,6 +523,52 @@ export class SekiTooltip {
485
523
  "reflect": false,
486
524
  "attribute": "offset",
487
525
  "defaultValue": "8"
526
+ },
527
+ "open": {
528
+ "type": "boolean",
529
+ "mutable": true,
530
+ "complexType": {
531
+ "original": "boolean",
532
+ "resolved": "boolean",
533
+ "references": {}
534
+ },
535
+ "required": false,
536
+ "optional": false,
537
+ "docs": {
538
+ "tags": [{
539
+ "name": "default",
540
+ "text": "false"
541
+ }],
542
+ "text": "Controlled open state. Reflects to the `open` attribute, so\n`<seki-tooltip open>` renders visible with no script involved."
543
+ },
544
+ "getter": false,
545
+ "setter": false,
546
+ "reflect": true,
547
+ "attribute": "open",
548
+ "defaultValue": "false"
549
+ },
550
+ "defaultOpen": {
551
+ "type": "boolean",
552
+ "mutable": false,
553
+ "complexType": {
554
+ "original": "boolean",
555
+ "resolved": "boolean",
556
+ "references": {}
557
+ },
558
+ "required": false,
559
+ "optional": false,
560
+ "docs": {
561
+ "tags": [{
562
+ "name": "default",
563
+ "text": "false"
564
+ }],
565
+ "text": "Initial open state for uncontrolled usage"
566
+ },
567
+ "getter": false,
568
+ "setter": false,
569
+ "reflect": false,
570
+ "attribute": "default-open",
571
+ "defaultValue": "false"
488
572
  }
489
573
  };
490
574
  }
@@ -622,4 +706,10 @@ export class SekiTooltip {
622
706
  };
623
707
  }
624
708
  static get elementRef() { return "el"; }
709
+ static get watchers() {
710
+ return [{
711
+ "propName": "open",
712
+ "methodName": "openChanged"
713
+ }];
714
+ }
625
715
  }
@@ -4,3 +4,4 @@
4
4
  */
5
5
  export * from './types';
6
6
  export * from './select-context';
7
+ export * from './option-id';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Deterministic, per-select-instance option id.
3
+ *
4
+ * seki-select's `contentId` (see `SelectContext.contentId` in
5
+ * `src/utils/select/types.ts`) is randomized once per `<seki-select>`
6
+ * instance. Prefixing the option id with it keeps ids collision-free across
7
+ * multiple `<seki-select>` instances on the same page that happen to share
8
+ * an option `value` — this only matters now that seki-select-option renders
9
+ * in scoped (non-shadow) mode and its `id` is a real, page-scoped DOM id
10
+ * assistive tech can actually resolve (see #300). Exported so both
11
+ * seki-select-option (which sets the id) and seki-select-trigger (which
12
+ * references it via aria-activedescendant) compute the exact same string.
13
+ */
14
+ export function buildOptionId(contentId, value) {
15
+ return `${contentId}-option-${value}`;
16
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Custom-element definition helpers for compound components.
3
+ *
4
+ * In the lazy-loaded build every tag is registered up front (as a proxy), so a
5
+ * child can always reach its parent's `@Method`s. In the `dist/components`
6
+ * custom-elements build each tag is defined by its own module, in whatever
7
+ * order those modules resolve — over a CDN that can be seconds apart. A child
8
+ * that calls `closest('seki-parent').someMethod()` while the parent is still
9
+ * an un-upgraded `HTMLElement` throws "someMethod is not a function" and the
10
+ * component silently loses its initial state (#314).
11
+ *
12
+ * `whenDefined(tag)` resolves immediately when the tag is already registered
13
+ * or when there is no `customElements` registry (SSR, some test runners), so
14
+ * awaiting it costs nothing on the happy path.
15
+ */
16
+ function registry() {
17
+ return typeof globalThis !== 'undefined' && globalThis.customElements ? globalThis.customElements : null;
18
+ }
19
+ /** True when `tag` is registered (or when there is no registry to ask). */
20
+ export function isDefined(tag) {
21
+ const reg = registry();
22
+ return !reg || typeof reg.get !== 'function' || !!reg.get(tag);
23
+ }
24
+ /** Resolves once `tag` is registered. Never rejects. */
25
+ export function whenDefined(tag) {
26
+ const reg = registry();
27
+ if (!reg || typeof reg.whenDefined !== 'function' || isDefined(tag)) {
28
+ return Promise.resolve();
29
+ }
30
+ return reg.whenDefined(tag).then(() => undefined, () => undefined);
31
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Custom-element definition helpers for compound components.
3
+ *
4
+ * In the lazy-loaded build every tag is registered up front (as a proxy), so a
5
+ * child can always reach its parent's `@Method`s. In the `dist/components`
6
+ * custom-elements build each tag is defined by its own module, in whatever
7
+ * order those modules resolve — over a CDN that can be seconds apart. A child
8
+ * that calls `closest('seki-parent').someMethod()` while the parent is still
9
+ * an un-upgraded `HTMLElement` throws "someMethod is not a function" and the
10
+ * component silently loses its initial state (#314).
11
+ *
12
+ * `whenDefined(tag)` resolves immediately when the tag is already registered
13
+ * or when there is no `customElements` registry (SSR, some test runners), so
14
+ * awaiting it costs nothing on the happy path.
15
+ */
16
+ function registry() {
17
+ return typeof globalThis !== 'undefined' && globalThis.customElements ? globalThis.customElements : null;
18
+ }
19
+ /** True when `tag` is registered (or when there is no registry to ask). */
20
+ function isDefined(tag) {
21
+ const reg = registry();
22
+ return !reg || typeof reg.get !== 'function' || !!reg.get(tag);
23
+ }
24
+ /** Resolves once `tag` is registered. Never rejects. */
25
+ function whenDefined(tag) {
26
+ const reg = registry();
27
+ if (!reg || typeof reg.whenDefined !== 'function' || isDefined(tag)) {
28
+ return Promise.resolve();
29
+ }
30
+ return reg.whenDefined(tag).then(() => undefined, () => undefined);
31
+ }
32
+
33
+ export { isDefined as i, whenDefined as w };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Deterministic, per-select-instance option id.
3
+ *
4
+ * seki-select's `contentId` (see `SelectContext.contentId` in
5
+ * `src/utils/select/types.ts`) is randomized once per `<seki-select>`
6
+ * instance. Prefixing the option id with it keeps ids collision-free across
7
+ * multiple `<seki-select>` instances on the same page that happen to share
8
+ * an option `value` — this only matters now that seki-select-option renders
9
+ * in scoped (non-shadow) mode and its `id` is a real, page-scoped DOM id
10
+ * assistive tech can actually resolve (see #300). Exported so both
11
+ * seki-select-option (which sets the id) and seki-select-trigger (which
12
+ * references it via aria-activedescendant) compute the exact same string.
13
+ */
14
+ function buildOptionId(contentId, value) {
15
+ return `${contentId}-option-${value}`;
16
+ }
17
+
18
+ export { buildOptionId as b };
@@ -1,5 +1,6 @@
1
1
  import { p as proxyCustomElement, H, d as syncTheme, h, e as Host } from './p-BGFP3hxa.js';
2
2
  import { s as subscribeToContextChange } from './p-DJMgrCw3.js';
3
+ import { w as whenDefined } from './p-C9-yH6MD.js';
3
4
 
4
5
  const sekiCarouselDotsCss = ":host{display:flex;justify-content:center;width:100%;padding-top:0.75rem}.carousel-dots__container{display:flex;align-items:center;justify-content:center;gap:var(--seki-carousel-dot-gap, 0.5rem)}.carousel-dots__dot{display:flex;align-items:center;justify-content:center;padding:0.25rem;border:none;background:transparent;cursor:pointer;transition:transform 0.2s ease}.carousel-dots__dot:hover{transform:scale(1.2)}.carousel-dots__dot:focus-visible{outline:2px solid var(--seki-ring, hsl(0, 0%, 3.9%));outline-offset:2px;border-radius:50%}.carousel-dots__dot-inner{display:block;width:var(--seki-carousel-dot-size, 0.5rem);height:var(--seki-carousel-dot-size, 0.5rem);border-radius:50%;background:var(--seki-carousel-dot-color, var(--seki-muted-foreground, hsl(0, 0%, 42%)));transition:background-color 0.2s ease, width 0.2s ease, height 0.2s ease}.carousel-dots__dot--active .carousel-dots__dot-inner{width:var(--seki-carousel-dot-active-size, 0.625rem);height:var(--seki-carousel-dot-active-size, 0.625rem);background:var(--seki-carousel-dot-active-color, var(--seki-foreground, hsl(0, 0%, 3.9%)))}@media (prefers-reduced-motion: reduce){.carousel-dots__dot,.carousel-dots__dot-inner{transition:none}}";
5
6
 
@@ -73,12 +74,15 @@ const SekiCarouselDots$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarouselDo
73
74
  async subscribeToCarousel() {
74
75
  if (!this.parentCarousel)
75
76
  return;
76
- // Initial state
77
+ // Subscribe first so a context change can never be missed, then wait for
78
+ // <seki-carousel> to be *defined* — in the per-tag custom-elements build its
79
+ // @Methods do not exist until then (#314).
80
+ this.unsubscribe = subscribeToContextChange(this.el, 'seki-carousel', this.handleContextChange).unsubscribe;
81
+ await whenDefined('seki-carousel');
77
82
  await this.updateState();
78
83
  // Re-sync on every carousel context change — including embla's async init
79
84
  // and reInit, not just user navigation — so the dots reflect the real slide
80
85
  // count/position instead of freezing at their premature mount-time state (#274).
81
- this.unsubscribe = subscribeToContextChange(this.el, 'seki-carousel', this.handleContextChange).unsubscribe;
82
86
  }
83
87
  async updateState() {
84
88
  if (!this.parentCarousel)
@@ -89,7 +93,7 @@ const SekiCarouselDots$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarouselDo
89
93
  }
90
94
  render() {
91
95
  const dots = Array.from({ length: this.scrollSnapCount }, (_, i) => i);
92
- return (h(Host, { key: '26e61e1799d34e8d750c02c1287f85461d8e99a6', class: "carousel-dots" }, h("div", { key: '8fea8befb4cfc3859da4c5f1ee1c6b8c1485e8da', class: "carousel-dots__container", role: "tablist", "aria-label": "Carousel pagination" }, dots.map((index) => (h("button", { key: index, type: "button", class: {
96
+ return (h(Host, { key: '3bc07e8ad34358f497c99b4a4a51d84efe3f0f5b', class: "carousel-dots" }, h("div", { key: 'b779622f331bb7899737f51eea87469980269f52', class: "carousel-dots__container", role: "tablist", "aria-label": "Carousel pagination" }, dots.map((index) => (h("button", { key: index, type: "button", class: {
93
97
  'carousel-dots__dot': true,
94
98
  'carousel-dots__dot--active': index === this.selectedIndex,
95
99
  }, role: "tab", "aria-selected": index === this.selectedIndex ? 'true' : 'false', "aria-label": `Go to slide ${index + 1}`, tabindex: index === this.selectedIndex ? '0' : '-1', onClick: () => this.handleDotClick(index), onKeyDown: (e) => this.handleKeyDown(e, index) }, h("span", { class: "carousel-dots__dot-inner" })))))));
@@ -1,5 +1,6 @@
1
1
  import { p as proxyCustomElement, H, d as syncTheme, h, e as Host } from './p-BGFP3hxa.js';
2
2
  import { s as subscribeToContextChange } from './p-DJMgrCw3.js';
3
+ import { w as whenDefined } from './p-C9-yH6MD.js';
3
4
 
4
5
  const sekiCarouselNavigationCss = ":host{display:flex;align-items:center;justify-content:center;position:absolute;top:50%;transform:translateY(-50%);z-index:10}:host(.carousel-nav--prev){left:0.5rem}:host(.carousel-nav--next){right:0.5rem}.carousel-nav__button{display:flex;align-items:center;justify-content:center;width:var(--seki-carousel-arrow-size, 2.5rem);height:var(--seki-carousel-arrow-size, 2.5rem);padding:0;border:none;border-radius:50%;background:var(--seki-carousel-arrow-bg, var(--seki-background, hsl(0, 0%, 100%)));color:var(--seki-carousel-arrow-color, var(--seki-foreground, hsl(0, 0%, 3.9%)));cursor:pointer;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);transition:background-color 0.2s ease, opacity 0.2s ease, transform 0.2s ease;box-shadow:0 2px 8px rgba(0, 0, 0, 0.1)}.carousel-nav__button:hover:not(:disabled){background:var(--seki-carousel-arrow-bg-hover, var(--seki-accent, hsl(0, 0%, 96.1%)));transform:scale(1.05)}.carousel-nav__button:focus-visible{outline:2px solid var(--seki-ring, hsl(0, 0%, 3.9%));outline-offset:2px}.carousel-nav__button:disabled{opacity:0.5;cursor:not-allowed;pointer-events:none}.carousel-nav__icon{width:1.25rem;height:1.25rem;flex-shrink:0}@media (max-width: 480px){:host(.carousel-nav--prev){left:0.25rem}:host(.carousel-nav--next){right:0.25rem}.carousel-nav__button{width:2rem;height:2rem}.carousel-nav__icon{width:1rem;height:1rem}}@media (prefers-reduced-motion: reduce){.carousel-nav__button{transition:none}.carousel-nav__button:hover:not(:disabled){transform:none}}";
5
6
 
@@ -19,6 +20,7 @@ const SekiCarouselNext$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarouselNe
19
20
  this.handleClick = async () => {
20
21
  if (this.disabled || !this.parentCarousel)
21
22
  return;
23
+ await whenDefined('seki-carousel');
22
24
  await this.parentCarousel.scrollNext();
23
25
  };
24
26
  }
@@ -41,12 +43,12 @@ const SekiCarouselNext$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarouselNe
41
43
  async subscribeToCarousel() {
42
44
  if (!this.parentCarousel)
43
45
  return;
44
- // Initial state
45
- await this.updateState();
46
- // Re-sync on every carousel context change — including embla's async init
47
- // and reInit, not just user navigation — so the button never freezes at its
48
- // premature mount-time disabled state (#274).
46
+ // Subscribe first so a context change can never be missed, then wait for
47
+ // <seki-carousel> to be *defined* — in the per-tag custom-elements build its
48
+ // @Methods do not exist until then (#314).
49
49
  this.unsubscribe = subscribeToContextChange(this.el, 'seki-carousel', this.handleContextChange).unsubscribe;
50
+ await whenDefined('seki-carousel');
51
+ await this.updateState();
50
52
  }
51
53
  async updateState() {
52
54
  if (!this.parentCarousel)
@@ -55,7 +57,7 @@ const SekiCarouselNext$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarouselNe
55
57
  this.disabled = !context.canScrollNext;
56
58
  }
57
59
  render() {
58
- return (h(Host, { key: 'cda7dd0b081d69e07d6500d8b6830368f5770e3a', class: { 'carousel-nav': true, 'carousel-nav--next': true } }, h("button", { key: 'ab3ddbdf211f90841ceef622701911554cd1c401', type: "button", class: "carousel-nav__button", disabled: this.disabled, "aria-label": "Next slide", onClick: this.handleClick }, h("svg", { key: 'a296c67e267f504ac3d7cecd996130b9b95c8523', class: "carousel-nav__icon", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { key: '1fb366e06a5412c87c30c340ed95959f498ea9f3', points: "9 18 15 12 9 6" })))));
60
+ return (h(Host, { key: 'ec0cc2d2aee02283fb71b03ae501f7150adc4fd6', class: { 'carousel-nav': true, 'carousel-nav--next': true } }, h("button", { key: '2716d69d315b40127449d4d7979fec4ad418598d', type: "button", class: "carousel-nav__button", disabled: this.disabled, "aria-label": "Next slide", onClick: this.handleClick }, h("svg", { key: '820491a74df7479bcb96c4da9e4366bee6cce26b', class: "carousel-nav__icon", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { key: '4d3220a8f9369961e1af6ede4921b1ae4b433908', points: "9 18 15 12 9 6" })))));
59
61
  }
60
62
  get el() { return this; }
61
63
  static get style() { return sekiCarouselNavigationCss; }
@@ -1,5 +1,6 @@
1
1
  import { p as proxyCustomElement, H, d as syncTheme, h, e as Host } from './p-BGFP3hxa.js';
2
2
  import { s as subscribeToContextChange } from './p-DJMgrCw3.js';
3
+ import { w as whenDefined } from './p-C9-yH6MD.js';
3
4
 
4
5
  const sekiCarouselNavigationCss = ":host{display:flex;align-items:center;justify-content:center;position:absolute;top:50%;transform:translateY(-50%);z-index:10}:host(.carousel-nav--prev){left:0.5rem}:host(.carousel-nav--next){right:0.5rem}.carousel-nav__button{display:flex;align-items:center;justify-content:center;width:var(--seki-carousel-arrow-size, 2.5rem);height:var(--seki-carousel-arrow-size, 2.5rem);padding:0;border:none;border-radius:50%;background:var(--seki-carousel-arrow-bg, var(--seki-background, hsl(0, 0%, 100%)));color:var(--seki-carousel-arrow-color, var(--seki-foreground, hsl(0, 0%, 3.9%)));cursor:pointer;backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);transition:background-color 0.2s ease, opacity 0.2s ease, transform 0.2s ease;box-shadow:0 2px 8px rgba(0, 0, 0, 0.1)}.carousel-nav__button:hover:not(:disabled){background:var(--seki-carousel-arrow-bg-hover, var(--seki-accent, hsl(0, 0%, 96.1%)));transform:scale(1.05)}.carousel-nav__button:focus-visible{outline:2px solid var(--seki-ring, hsl(0, 0%, 3.9%));outline-offset:2px}.carousel-nav__button:disabled{opacity:0.5;cursor:not-allowed;pointer-events:none}.carousel-nav__icon{width:1.25rem;height:1.25rem;flex-shrink:0}@media (max-width: 480px){:host(.carousel-nav--prev){left:0.25rem}:host(.carousel-nav--next){right:0.25rem}.carousel-nav__button{width:2rem;height:2rem}.carousel-nav__icon{width:1rem;height:1rem}}@media (prefers-reduced-motion: reduce){.carousel-nav__button{transition:none}.carousel-nav__button:hover:not(:disabled){transform:none}}";
5
6
 
@@ -19,6 +20,7 @@ const SekiCarouselPrevious$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarous
19
20
  this.handleClick = async () => {
20
21
  if (this.disabled || !this.parentCarousel)
21
22
  return;
23
+ await whenDefined('seki-carousel');
22
24
  await this.parentCarousel.scrollPrev();
23
25
  };
24
26
  }
@@ -41,12 +43,12 @@ const SekiCarouselPrevious$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarous
41
43
  async subscribeToCarousel() {
42
44
  if (!this.parentCarousel)
43
45
  return;
44
- // Initial state
45
- await this.updateState();
46
- // Re-sync on every carousel context change — including embla's async init
47
- // and reInit, not just user navigation — so the button never freezes at its
48
- // premature mount-time disabled state (#274).
46
+ // Subscribe first so a context change can never be missed, then wait for
47
+ // <seki-carousel> to be *defined* — in the per-tag custom-elements build its
48
+ // @Methods do not exist until then (#314).
49
49
  this.unsubscribe = subscribeToContextChange(this.el, 'seki-carousel', this.handleContextChange).unsubscribe;
50
+ await whenDefined('seki-carousel');
51
+ await this.updateState();
50
52
  }
51
53
  async updateState() {
52
54
  if (!this.parentCarousel)
@@ -55,7 +57,7 @@ const SekiCarouselPrevious$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarous
55
57
  this.disabled = !context.canScrollPrev;
56
58
  }
57
59
  render() {
58
- return (h(Host, { key: '90cf829ea5c684141c0014b3b1388aabe15f3852', class: { 'carousel-nav': true, 'carousel-nav--prev': true } }, h("button", { key: '80dcc7bf4cb81588e1cc2f570165af98c7263295', type: "button", class: "carousel-nav__button", disabled: this.disabled, "aria-label": "Previous slide", onClick: this.handleClick }, h("svg", { key: '0dd255a633d1fc835a9fbbfcefa967373fc8975c', class: "carousel-nav__icon", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { key: '6e1b90ac947f0949bc4a2f34e1b7972ddde631bd', points: "15 18 9 12 15 6" })))));
60
+ return (h(Host, { key: '8ab6f4c404f5cf04e7256c3e4d364a8377121280', class: { 'carousel-nav': true, 'carousel-nav--prev': true } }, h("button", { key: '9048cad871a4f793b3cc3ec1ba45543c9b137652', type: "button", class: "carousel-nav__button", disabled: this.disabled, "aria-label": "Previous slide", onClick: this.handleClick }, h("svg", { key: '14c6000381fbb99e71ce69ae5627d82d7ec8c8ee', class: "carousel-nav__icon", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("polyline", { key: '7d65b0ee40aeb412642ce27e2c0e46e90bd5d985', points: "15 18 9 12 15 6" })))));
59
61
  }
60
62
  get el() { return this; }
61
63
  static get style() { return sekiCarouselNavigationCss; }
@@ -1,4 +1,5 @@
1
1
  import { p as proxyCustomElement, H, c as createEvent, d as syncTheme, h, e as Host } from './p-BGFP3hxa.js';
2
+ import { i as isDefined, w as whenDefined } from './p-C9-yH6MD.js';
2
3
 
3
4
  const sekiCarouselCss = ":host{--seki-carousel-gap:1rem;--seki-carousel-arrow-size:2.5rem;--seki-carousel-arrow-bg:rgba(255, 255, 255, 0.8);--seki-carousel-arrow-bg-hover:rgba(255, 255, 255, 0.95);--seki-carousel-arrow-color:var(--seki-foreground, #0f172a);--seki-carousel-dot-size:0.5rem;--seki-carousel-dot-active-size:0.625rem;--seki-carousel-dot-gap:0.5rem;--seki-carousel-dot-color:var(--seki-muted, #94a3b8);--seki-carousel-dot-active-color:var(--seki-primary, #0f172a);display:block;position:relative;width:100%}:host(:focus){outline:none}:host(:focus-visible){outline:2px solid var(--seki-ring, #3b82f6);outline-offset:2px;border-radius:var(--seki-radius-md, 0.375rem)}.carousel__container{position:relative;width:100%}.carousel__live-region{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}:host([data-theme='dark']){--seki-carousel-arrow-bg:rgba(30, 41, 59, 0.8);--seki-carousel-arrow-bg-hover:rgba(30, 41, 59, 0.95);--seki-carousel-dot-color:var(--seki-muted-foreground, hsl(0, 0%, 63.9%));--seki-carousel-dot-active-color:var(--seki-foreground, hsl(0, 0%, 98%))}@media (prefers-reduced-motion: reduce){:host *{transition:none !important;animation:none !important}}";
4
5
 
@@ -62,6 +63,7 @@ const SekiCarousel$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarousel exten
62
63
  this.viewportEl = null;
63
64
  this.initRafId = null;
64
65
  this.initRetries = 0;
66
+ this.waitedForContentDefinition = false;
65
67
  this.handleSelect = () => {
66
68
  this.updateState();
67
69
  this.slideChange.emit({
@@ -209,6 +211,18 @@ const SekiCarousel$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarousel exten
209
211
  // Get the inner container (seki-carousel-content uses shadow: false)
210
212
  const containerEl = this.viewportEl.querySelector('.carousel-content');
211
213
  if (!containerEl) {
214
+ // In the per-tag custom-elements build <seki-carousel-content> may not be
215
+ // *defined* yet, let alone rendered — over a CDN that can take longer than
216
+ // the whole rAF budget below. Wait for its definition once, then retry.
217
+ if (!this.waitedForContentDefinition && !isDefined('seki-carousel-content')) {
218
+ this.waitedForContentDefinition = true;
219
+ await whenDefined('seki-carousel-content');
220
+ if (!this.el.isConnected)
221
+ return;
222
+ this.initRetries = 0;
223
+ this.initRafId = requestAnimationFrame(() => this.initEmbla());
224
+ return;
225
+ }
212
226
  // Content child hasn't rendered yet. Retry next frame, but bail if the
213
227
  // carousel was disconnected or we've exhausted the retry budget so this
214
228
  // can never become an unbounded, uncancellable rAF loop.
@@ -301,7 +315,7 @@ const SekiCarousel$1 = /*@__PURE__*/ proxyCustomElement(class SekiCarousel exten
301
315
  // Render
302
316
  // =========================================================================
303
317
  render() {
304
- return (h(Host, { key: 'f11290fbc2f9803384306bcf1e6dd9d4fef6b77c', class: "carousel", role: "region", "aria-roledescription": "carousel", "aria-label": this.ariaLabel, tabindex: "0", onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, onFocusIn: this.handleFocusIn, onFocusOut: this.handleFocusOut, onKeyDown: this.handleKeyDown }, h("div", { key: 'edba4db0fc620ee679748b57b3feb106c4ed6bb9', class: "carousel__container" }, h("slot", { key: '0af58b5565e27ca1f6f91075eee9d6d0fbddecac' })), h("div", { key: 'b20a2c430bfbe43a4c819a6de49b9e0cdf6b6271', class: "carousel__live-region", "aria-live": "polite", "aria-atomic": "true" }, `Slide ${this.selectedIndex + 1} of ${this.scrollSnapCount}`)));
318
+ return (h(Host, { key: '383dfb248902b441e188b071e501a69684ac794d', class: "carousel", role: "region", "aria-roledescription": "carousel", "aria-label": this.ariaLabel, tabindex: "0", onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, onFocusIn: this.handleFocusIn, onFocusOut: this.handleFocusOut, onKeyDown: this.handleKeyDown }, h("div", { key: '2ea52063f017b1ae57d67ed53d38b3c8df35970d', class: "carousel__container" }, h("slot", { key: '280467c5fcf61258eed5aa42982757ce1a6f8e99' })), h("div", { key: '8a4286587ba79dcdbf453403f96ab293908359f4', class: "carousel__live-region", "aria-live": "polite", "aria-atomic": "true" }, `Slide ${this.selectedIndex + 1} of ${this.scrollSnapCount}`)));
305
319
  }
306
320
  get el() { return this; }
307
321
  static get watchers() { return {
@@ -13,6 +13,7 @@ const SekiDatePicker$1 = /*@__PURE__*/ proxyCustomElement(class SekiDatePicker e
13
13
  this.sekiChange = createEvent(this, "sekiChange");
14
14
  this.sekiOpen = createEvent(this, "sekiOpen");
15
15
  this.sekiClose = createEvent(this, "sekiClose");
16
+ this.sekiOpenChange = createEvent(this, "sekiOpenChange");
16
17
  /**
17
18
  * Selection mode: single date or date range
18
19
  * @default 'single'
@@ -36,27 +37,25 @@ const SekiDatePicker$1 = /*@__PURE__*/ proxyCustomElement(class SekiDatePicker e
36
37
  */
37
38
  this.required = false;
38
39
  /**
39
- * Whether the popover is open
40
+ * Controlled open state of the popover. Also readable/writable as the `open`
41
+ * attribute, so `<seki-date-picker open>` renders open with no script involved.
40
42
  */
41
- this.isOpen = false;
43
+ this.open = false;
44
+ /**
45
+ * Initial open state for uncontrolled usage
46
+ */
47
+ this.defaultOpen = false;
48
+ /**
49
+ * Internal state for whether the popover is open
50
+ */
51
+ this._isOpen = false;
42
52
  this.handleTriggerClick = () => {
43
- if (this.disabled)
44
- return;
45
- this.isOpen = !this.isOpen;
46
- if (this.isOpen) {
47
- this.sekiOpen.emit();
48
- requestAnimationFrame(() => {
49
- this.positionPopover();
50
- });
51
- }
52
- else {
53
- this.sekiClose.emit();
54
- }
53
+ this.toggleDatePicker();
55
54
  };
56
55
  this.handleDateSelect = (e) => {
57
56
  this.value = e.detail;
58
57
  this.sekiChange.emit(e.detail);
59
- this.close();
58
+ this.closeDatePicker();
60
59
  };
61
60
  this.handleRangeSelect = (e) => {
62
61
  var _a, _b;
@@ -64,16 +63,37 @@ const SekiDatePicker$1 = /*@__PURE__*/ proxyCustomElement(class SekiDatePicker e
64
63
  this.rangeTo = (_b = e.detail.to) !== null && _b !== void 0 ? _b : undefined;
65
64
  if (e.detail.from && e.detail.to) {
66
65
  this.sekiChange.emit(e.detail);
67
- this.close();
66
+ this.closeDatePicker();
68
67
  }
69
68
  };
70
69
  }
71
70
  componentWillLoad() {
71
+ this._isOpen = (this.open || this.defaultOpen) && !this.disabled;
72
+ this.open = this._isOpen;
72
73
  if ('attachInternals' in H.prototype) {
73
74
  this.internals = this.el.attachInternals();
74
75
  }
75
76
  this.updateFormValue();
76
77
  }
78
+ componentDidLoad() {
79
+ if (this._isOpen) {
80
+ requestAnimationFrame(() => {
81
+ this.positionPopover();
82
+ });
83
+ }
84
+ }
85
+ handleOpenPropChange(newValue) {
86
+ // An outside assignment (`picker.open = true`) has to win after first render;
87
+ // `open` is only read once in componentWillLoad otherwise.
88
+ if (newValue === this._isOpen)
89
+ return;
90
+ if (newValue) {
91
+ this.openDatePicker();
92
+ }
93
+ else {
94
+ this.closeDatePicker();
95
+ }
96
+ }
77
97
  updateFormValue() {
78
98
  if (this.internals && typeof this.internals.setFormValue === 'function') {
79
99
  const value = this.parseDate(this.value);
@@ -138,28 +158,35 @@ const SekiDatePicker$1 = /*@__PURE__*/ proxyCustomElement(class SekiDatePicker e
138
158
  }
139
159
  handleKeyDown(event) {
140
160
  var _a;
141
- if (event.key === 'Escape' && this.isOpen) {
161
+ if (event.key === 'Escape' && this._isOpen) {
142
162
  event.preventDefault();
143
- this.close();
163
+ this.closeDatePicker();
144
164
  (_a = this.triggerRef) === null || _a === void 0 ? void 0 : _a.focus();
145
165
  }
146
166
  }
147
167
  handleDocumentClick(event) {
148
- if (!this.isOpen)
168
+ if (!this._isOpen)
149
169
  return;
150
170
  const target = event.target;
151
171
  if (!this.el.contains(target)) {
152
- this.close();
172
+ this.closeDatePicker();
153
173
  }
154
174
  }
155
175
  /**
156
176
  * Open the date picker popover
157
177
  */
158
- async open() {
159
- if (this.disabled)
178
+ async openDatePicker() {
179
+ if (this.disabled) {
180
+ // Keep the reflected prop honest when an open request is refused.
181
+ this.open = false;
182
+ return;
183
+ }
184
+ if (this._isOpen)
160
185
  return;
161
- this.isOpen = true;
186
+ this._isOpen = true;
187
+ this.open = true;
162
188
  this.sekiOpen.emit();
189
+ this.sekiOpenChange.emit(true);
163
190
  requestAnimationFrame(() => {
164
191
  this.positionPopover();
165
192
  });
@@ -167,19 +194,23 @@ const SekiDatePicker$1 = /*@__PURE__*/ proxyCustomElement(class SekiDatePicker e
167
194
  /**
168
195
  * Close the date picker popover
169
196
  */
170
- async close() {
171
- this.isOpen = false;
197
+ async closeDatePicker() {
198
+ if (!this._isOpen)
199
+ return;
200
+ this._isOpen = false;
201
+ this.open = false;
172
202
  this.sekiClose.emit();
203
+ this.sekiOpenChange.emit(false);
173
204
  }
174
205
  /**
175
206
  * Toggle the date picker popover
176
207
  */
177
- async toggle() {
178
- if (this.isOpen) {
179
- await this.close();
208
+ async toggleDatePicker() {
209
+ if (this._isOpen) {
210
+ await this.closeDatePicker();
180
211
  }
181
212
  else {
182
- await this.open();
213
+ await this.openDatePicker();
183
214
  }
184
215
  }
185
216
  connectedCallback() {
@@ -191,16 +222,17 @@ const SekiDatePicker$1 = /*@__PURE__*/ proxyCustomElement(class SekiDatePicker e
191
222
  const selectedDate = this.parseDate(this.value);
192
223
  const rangeFrom = this.parseDate(this.rangeFrom);
193
224
  const rangeTo = this.parseDate(this.rangeTo);
194
- return (h("div", { key: 'a3d95b5462a9acf744d73e4572b42ad0d64372a0', class: "seki-date-picker" }, h("button", { key: '75df88046597e51a5c1126d2c2a24575fb94bd80', type: "button", ref: el => (this.triggerRef = el), class: {
225
+ return (h("div", { key: '79b9eec6c71d77d2af7f006ee03f6a836f5405df', class: "seki-date-picker" }, h("button", { key: '54460e6603c806d24eb0c36baa1b5dbdd7aeb90d', type: "button", ref: el => (this.triggerRef = el), class: {
195
226
  'seki-date-picker__trigger': true,
196
- 'seki-date-picker__trigger--open': this.isOpen,
227
+ 'seki-date-picker__trigger--open': this._isOpen,
197
228
  'seki-date-picker__trigger--disabled': this.disabled,
198
229
  'seki-date-picker__trigger--has-value': hasValue,
199
- }, disabled: this.disabled, "aria-haspopup": "dialog", "aria-expanded": this.isOpen ? 'true' : 'false', "aria-label": this.ariaLabel || this.placeholder, onClick: this.handleTriggerClick }, h("svg", { key: '51d3e52e4ff4fe0ff6607f1accddb3b2307e3ad9', class: "seki-date-picker__icon", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("rect", { key: 'a0682b1fe6eb713698f34f0af5faff55e2f53191', x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), h("line", { key: 'f18a51a0b1f98743dab69923ee12e6565716e141', x1: "16", y1: "2", x2: "16", y2: "6" }), h("line", { key: 'd3488713bec1c91106d9a5987788cc1d49548275', x1: "8", y1: "2", x2: "8", y2: "6" }), h("line", { key: 'e6275d8fd1a8fd664771f908735b62d8a8278ca9', x1: "3", y1: "10", x2: "21", y2: "10" })), h("span", { key: 'b7f5ddea3a0332f29aac7cfe9fcb6a895a3e1226', class: "seki-date-picker__value" }, hasValue ? displayValue : this.placeholder)), this.isOpen && (h("div", { key: 'eded3f27883fd65ac76e860d23e3009693fea06f', ref: el => (this.popoverRef = el), class: "seki-date-picker__popover", role: "dialog", "aria-modal": "true", "aria-label": "Choose date" }, h("seki-calendar", { key: '5013ae98d89933c8051d3699981a38817fc0e49e', mode: this.mode, selected: selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.toISOString(), "range-from": rangeFrom === null || rangeFrom === void 0 ? void 0 : rangeFrom.toISOString(), "range-to": rangeTo === null || rangeTo === void 0 ? void 0 : rangeTo.toISOString(), "min-date": this.minDate, "max-date": this.maxDate, onSekiSelect: this.handleDateSelect, onSekiRangeSelect: this.handleRangeSelect })))));
230
+ }, disabled: this.disabled, "aria-haspopup": "dialog", "aria-expanded": this._isOpen ? 'true' : 'false', "aria-label": this.ariaLabel || this.placeholder, onClick: this.handleTriggerClick }, h("svg", { key: 'b65b7e82e5ad5485f5f2dd5934fb00fe7a2df0e4', class: "seki-date-picker__icon", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("rect", { key: 'be93574c133eb04d61d765fa0d4d893dfd18de5b', x: "3", y: "4", width: "18", height: "18", rx: "2", ry: "2" }), h("line", { key: 'f60deabd7d2c3061b08b8245650935a85068937a', x1: "16", y1: "2", x2: "16", y2: "6" }), h("line", { key: 'e6dba2b6b7501a6e2de21a29edcafe1927f1ad4d', x1: "8", y1: "2", x2: "8", y2: "6" }), h("line", { key: '4ca41a9af0155298fcaf2f1273f3833ba1df379a', x1: "3", y1: "10", x2: "21", y2: "10" })), h("span", { key: 'f9ef3166165413282928920a7a1b726b1edc4d54', class: "seki-date-picker__value" }, hasValue ? displayValue : this.placeholder)), this._isOpen && (h("div", { key: '561b160f14e86b0a7c043a30ed6e315465d6160b', ref: el => (this.popoverRef = el), class: "seki-date-picker__popover", role: "dialog", "aria-modal": "true", "aria-label": "Choose date" }, h("seki-calendar", { key: '96688e161b3a3814ed27135905de95df437c8bbc', mode: this.mode, selected: selectedDate === null || selectedDate === void 0 ? void 0 : selectedDate.toISOString(), "range-from": rangeFrom === null || rangeFrom === void 0 ? void 0 : rangeFrom.toISOString(), "range-to": rangeTo === null || rangeTo === void 0 ? void 0 : rangeTo.toISOString(), "min-date": this.minDate, "max-date": this.maxDate, onSekiSelect: this.handleDateSelect, onSekiRangeSelect: this.handleRangeSelect })))));
200
231
  }
201
232
  static get formAssociated() { return true; }
202
233
  get el() { return this; }
203
234
  static get watchers() { return {
235
+ "open": ["handleOpenPropChange"],
204
236
  "value": ["updateFormValue"],
205
237
  "rangeFrom": ["updateFormValue"],
206
238
  "rangeTo": ["updateFormValue"]
@@ -219,11 +251,14 @@ const SekiDatePicker$1 = /*@__PURE__*/ proxyCustomElement(class SekiDatePicker e
219
251
  "name": [1],
220
252
  "required": [4],
221
253
  "ariaLabel": [1, "aria-label"],
222
- "isOpen": [32],
223
- "open": [64],
224
- "close": [64],
225
- "toggle": [64]
254
+ "open": [1540],
255
+ "defaultOpen": [4, "default-open"],
256
+ "_isOpen": [32],
257
+ "openDatePicker": [64],
258
+ "closeDatePicker": [64],
259
+ "toggleDatePicker": [64]
226
260
  }, [[0, "keydown", "handleKeyDown"], [4, "click", "handleDocumentClick"]], {
261
+ "open": ["handleOpenPropChange"],
227
262
  "value": ["updateFormValue"],
228
263
  "rangeFrom": ["updateFormValue"],
229
264
  "rangeTo": ["updateFormValue"]