@sekiui/elements 0.1.6 → 0.1.7

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 (213) hide show
  1. package/dist/cjs/accordion-ids-Cjq6aIVd.js +42 -0
  2. package/dist/cjs/direction-Dt-r6_ec.js +14 -0
  3. package/dist/cjs/host-id-C3XieWsk.js +32 -0
  4. package/dist/cjs/layout-DR0fTNAb.js +109 -0
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/cjs/seki-accordion-content.cjs.entry.js +27 -25
  7. package/dist/cjs/seki-accordion-item.cjs.entry.js +13 -29
  8. package/dist/cjs/seki-accordion-trigger.cjs.entry.js +36 -28
  9. package/dist/cjs/seki-accordion.cjs.entry.js +18 -12
  10. package/dist/cjs/seki-carousel-dots.cjs.entry.js +15 -7
  11. package/dist/cjs/seki-carousel-next.cjs.entry.js +1 -1
  12. package/dist/cjs/seki-carousel-previous.cjs.entry.js +1 -1
  13. package/dist/cjs/seki-carousel.cjs.entry.js +51 -6
  14. package/dist/cjs/seki-combobox.cjs.entry.js +80 -1
  15. package/dist/cjs/seki-context-menu-content.cjs.entry.js +13 -16
  16. package/dist/cjs/seki-context-menu.cjs.entry.js +14 -9
  17. package/dist/cjs/seki-dropdown-menu-content.cjs.entry.js +13 -16
  18. package/dist/cjs/seki-dropdown-menu-trigger.cjs.entry.js +7 -15
  19. package/dist/cjs/seki-dropdown-menu.cjs.entry.js +14 -9
  20. package/dist/cjs/seki-hover-card-content.cjs.entry.js +27 -33
  21. package/dist/cjs/seki-hover-card-trigger.cjs.entry.js +10 -25
  22. package/dist/cjs/seki-hover-card.cjs.entry.js +7 -6
  23. package/dist/cjs/seki-radio-group-item.cjs.entry.js +18 -1
  24. package/dist/cjs/seki-radio-group.cjs.entry.js +8 -1
  25. package/dist/cjs/seki-resizable-handle.cjs.entry.js +72 -15
  26. package/dist/cjs/seki-resizable-panel-group.cjs.entry.js +11 -107
  27. package/dist/cjs/seki-resizable-panel.cjs.entry.js +5 -3
  28. package/dist/cjs/seki-tabs-content.cjs.entry.js +21 -19
  29. package/dist/cjs/seki-tabs-list.cjs.entry.js +8 -24
  30. package/dist/cjs/seki-tabs-trigger.cjs.entry.js +23 -31
  31. package/dist/cjs/seki-tabs.cjs.entry.js +15 -18
  32. package/dist/cjs/sekiui.cjs.js +1 -1
  33. package/dist/cjs/{tab-ids-BzpIZnUS.js → tab-ids-BOdn1Fu2.js} +14 -0
  34. package/dist/collection/collection-manifest.json +2 -2
  35. package/dist/collection/components/accordion/accordion-ids.js +36 -0
  36. package/dist/collection/components/accordion/seki-accordion-content.js +27 -25
  37. package/dist/collection/components/accordion/seki-accordion-item.js +12 -29
  38. package/dist/collection/components/accordion/seki-accordion-trigger.css +6 -2
  39. package/dist/collection/components/accordion/seki-accordion-trigger.js +37 -28
  40. package/dist/collection/components/accordion/seki-accordion.js +40 -11
  41. package/dist/collection/components/carousel/seki-carousel-dots.js +15 -7
  42. package/dist/collection/components/carousel/seki-carousel-navigation.css +9 -4
  43. package/dist/collection/components/carousel/seki-carousel.js +51 -6
  44. package/dist/collection/components/combobox/seki-combobox.js +103 -1
  45. package/dist/collection/components/context-menu/seki-context-menu-content.js +13 -16
  46. package/dist/collection/components/context-menu/seki-context-menu.js +31 -9
  47. package/dist/collection/components/dropdown-menu/seki-dropdown-menu-content.js +13 -16
  48. package/dist/collection/components/dropdown-menu/seki-dropdown-menu-trigger.js +7 -15
  49. package/dist/collection/components/dropdown-menu/seki-dropdown-menu.js +31 -9
  50. package/dist/collection/components/hover-card/seki-hover-card-content.js +27 -33
  51. package/dist/collection/components/hover-card/seki-hover-card-trigger.js +10 -25
  52. package/dist/collection/components/hover-card/seki-hover-card.js +24 -6
  53. package/dist/collection/components/radio-group/seki-radio-group-item.js +18 -1
  54. package/dist/collection/components/radio-group/seki-radio-group.js +25 -1
  55. package/dist/collection/components/resizable/layout.js +2 -0
  56. package/dist/collection/components/resizable/seki-resizable-handle.css +6 -2
  57. package/dist/collection/components/resizable/seki-resizable-handle.js +71 -14
  58. package/dist/collection/components/resizable/seki-resizable-panel-group.js +5 -2
  59. package/dist/collection/components/resizable/seki-resizable-panel.js +5 -3
  60. package/dist/collection/components/tabs/seki-tabs-content.js +24 -19
  61. package/dist/collection/components/tabs/seki-tabs-list.js +8 -24
  62. package/dist/collection/components/tabs/seki-tabs-trigger.js +24 -19
  63. package/dist/collection/components/tabs/seki-tabs.js +34 -18
  64. package/dist/collection/components/tabs/tab-ids.js +13 -0
  65. package/dist/collection/utils/host-id.js +27 -0
  66. package/dist/components/p-BD28aG2U.js +12 -0
  67. package/dist/components/p-BuvZJ6_r.js +39 -0
  68. package/dist/components/p-DmN32Mrm.js +103 -0
  69. package/dist/components/{p-CmuSriLz.js → p-bxPJJ6k4.js} +14 -1
  70. package/dist/components/p-ppXRAghy.js +29 -0
  71. package/dist/components/seki-accordion-content.js +27 -25
  72. package/dist/components/seki-accordion-item.js +12 -29
  73. package/dist/components/seki-accordion-trigger.js +38 -29
  74. package/dist/components/seki-accordion.js +22 -13
  75. package/dist/components/seki-carousel-dots.js +15 -7
  76. package/dist/components/seki-carousel-next.js +1 -1
  77. package/dist/components/seki-carousel-previous.js +1 -1
  78. package/dist/components/seki-carousel.js +51 -6
  79. package/dist/components/seki-combobox.js +81 -2
  80. package/dist/components/seki-context-menu-content.js +13 -16
  81. package/dist/components/seki-context-menu.js +14 -9
  82. package/dist/components/seki-dropdown-menu-content.js +13 -16
  83. package/dist/components/seki-dropdown-menu-trigger.js +7 -15
  84. package/dist/components/seki-dropdown-menu.js +14 -9
  85. package/dist/components/seki-hover-card-content.js +27 -33
  86. package/dist/components/seki-hover-card-trigger.js +10 -25
  87. package/dist/components/seki-hover-card.js +7 -6
  88. package/dist/components/seki-radio-group-item.js +18 -1
  89. package/dist/components/seki-radio-group.js +8 -1
  90. package/dist/components/seki-resizable-handle.js +72 -15
  91. package/dist/components/seki-resizable-panel-group.js +6 -102
  92. package/dist/components/seki-resizable-panel.js +5 -3
  93. package/dist/components/seki-tabs-content.js +23 -19
  94. package/dist/components/seki-tabs-list.js +8 -24
  95. package/dist/components/seki-tabs-trigger.js +25 -31
  96. package/dist/components/seki-tabs.js +16 -18
  97. package/dist/esm/accordion-ids-D58tRFZv.js +39 -0
  98. package/dist/esm/direction-BD28aG2U.js +12 -0
  99. package/dist/esm/host-id-ppXRAghy.js +29 -0
  100. package/dist/esm/layout-DmN32Mrm.js +103 -0
  101. package/dist/esm/loader.js +1 -1
  102. package/dist/esm/seki-accordion-content.entry.js +27 -25
  103. package/dist/esm/seki-accordion-item.entry.js +13 -29
  104. package/dist/esm/seki-accordion-trigger.entry.js +36 -28
  105. package/dist/esm/seki-accordion.entry.js +18 -12
  106. package/dist/esm/seki-carousel-dots.entry.js +15 -7
  107. package/dist/esm/seki-carousel-next.entry.js +1 -1
  108. package/dist/esm/seki-carousel-previous.entry.js +1 -1
  109. package/dist/esm/seki-carousel.entry.js +51 -6
  110. package/dist/esm/seki-combobox.entry.js +80 -1
  111. package/dist/esm/seki-context-menu-content.entry.js +13 -16
  112. package/dist/esm/seki-context-menu.entry.js +14 -9
  113. package/dist/esm/seki-dropdown-menu-content.entry.js +13 -16
  114. package/dist/esm/seki-dropdown-menu-trigger.entry.js +7 -15
  115. package/dist/esm/seki-dropdown-menu.entry.js +14 -9
  116. package/dist/esm/seki-hover-card-content.entry.js +27 -33
  117. package/dist/esm/seki-hover-card-trigger.entry.js +10 -25
  118. package/dist/esm/seki-hover-card.entry.js +7 -6
  119. package/dist/esm/seki-radio-group-item.entry.js +18 -1
  120. package/dist/esm/seki-radio-group.entry.js +8 -1
  121. package/dist/esm/seki-resizable-handle.entry.js +72 -15
  122. package/dist/esm/seki-resizable-panel-group.entry.js +6 -102
  123. package/dist/esm/seki-resizable-panel.entry.js +5 -3
  124. package/dist/esm/seki-tabs-content.entry.js +21 -19
  125. package/dist/esm/seki-tabs-list.entry.js +8 -24
  126. package/dist/esm/seki-tabs-trigger.entry.js +22 -30
  127. package/dist/esm/seki-tabs.entry.js +15 -18
  128. package/dist/esm/sekiui.js +1 -1
  129. package/dist/esm/{tab-ids-CmuSriLz.js → tab-ids-bxPJJ6k4.js} +14 -1
  130. package/dist/sekiui/p-05646b3d.entry.js +1 -0
  131. package/dist/sekiui/p-06307251.entry.js +1 -0
  132. package/dist/sekiui/p-13206751.entry.js +1 -0
  133. package/dist/sekiui/p-2681547f.entry.js +1 -0
  134. package/dist/sekiui/p-34880473.entry.js +1 -0
  135. package/dist/sekiui/{p-3a950a93.entry.js → p-44c4e0ca.entry.js} +1 -1
  136. package/dist/sekiui/p-45d3e21b.entry.js +1 -0
  137. package/dist/sekiui/p-5a222bfa.entry.js +1 -0
  138. package/dist/sekiui/p-68d2ef55.entry.js +1 -0
  139. package/dist/sekiui/p-78df4dc1.entry.js +1 -0
  140. package/dist/sekiui/p-81e180e1.entry.js +1 -0
  141. package/dist/sekiui/{p-5cb2a9fc.entry.js → p-99aba093.entry.js} +1 -1
  142. package/dist/sekiui/p-BD28aG2U.js +1 -0
  143. package/dist/sekiui/p-BuvZJ6_r.js +1 -0
  144. package/dist/sekiui/p-DmN32Mrm.js +1 -0
  145. package/dist/sekiui/p-ad26ccd9.entry.js +1 -0
  146. package/dist/sekiui/p-b3260d62.entry.js +1 -0
  147. package/dist/sekiui/p-bxPJJ6k4.js +1 -0
  148. package/dist/sekiui/{p-d26b63d0.entry.js → p-c906ad1e.entry.js} +1 -1
  149. package/dist/sekiui/p-cb621f86.entry.js +1 -0
  150. package/dist/sekiui/p-d4863b02.entry.js +1 -0
  151. package/dist/sekiui/p-d81d442f.entry.js +1 -0
  152. package/dist/sekiui/p-d9a625f4.entry.js +1 -0
  153. package/dist/sekiui/p-db922f6f.entry.js +1 -0
  154. package/dist/sekiui/p-e1fbadc1.entry.js +1 -0
  155. package/dist/sekiui/p-e3dc7f49.entry.js +1 -0
  156. package/dist/sekiui/{p-8a96f54c.entry.js → p-ea8654dc.entry.js} +1 -1
  157. package/dist/sekiui/p-eb76021c.entry.js +1 -0
  158. package/dist/sekiui/p-f049f47a.entry.js +1 -0
  159. package/dist/sekiui/p-f0650660.entry.js +1 -0
  160. package/dist/sekiui/p-ppXRAghy.js +1 -0
  161. package/dist/sekiui/sekiui.esm.js +1 -1
  162. package/dist/types/components/accordion/accordion-ids.d.ts +17 -0
  163. package/dist/types/components/accordion/seki-accordion-content.d.ts +3 -3
  164. package/dist/types/components/accordion/seki-accordion-item.d.ts +2 -9
  165. package/dist/types/components/accordion/seki-accordion-trigger.d.ts +4 -4
  166. package/dist/types/components/accordion/seki-accordion.d.ts +7 -2
  167. package/dist/types/components/carousel/seki-carousel.d.ts +10 -0
  168. package/dist/types/components/combobox/seki-combobox.d.ts +13 -0
  169. package/dist/types/components/context-menu/seki-context-menu-content.d.ts +3 -3
  170. package/dist/types/components/context-menu/seki-context-menu.d.ts +6 -0
  171. package/dist/types/components/dropdown-menu/seki-dropdown-menu-content.d.ts +3 -3
  172. package/dist/types/components/dropdown-menu/seki-dropdown-menu-trigger.d.ts +2 -4
  173. package/dist/types/components/dropdown-menu/seki-dropdown-menu.d.ts +6 -0
  174. package/dist/types/components/hover-card/seki-hover-card-content.d.ts +3 -1
  175. package/dist/types/components/hover-card/seki-hover-card-trigger.d.ts +2 -2
  176. package/dist/types/components/hover-card/seki-hover-card.d.ts +5 -1
  177. package/dist/types/components/radio-group/seki-radio-group-item.d.ts +3 -0
  178. package/dist/types/components/radio-group/seki-radio-group.d.ts +14 -0
  179. package/dist/types/components/resizable/layout.d.ts +2 -0
  180. package/dist/types/components/resizable/seki-resizable-handle.d.ts +13 -0
  181. package/dist/types/components/resizable/seki-resizable-panel-group.d.ts +1 -0
  182. package/dist/types/components/resizable/types.d.ts +2 -0
  183. package/dist/types/components/tabs/seki-tabs-content.d.ts +3 -4
  184. package/dist/types/components/tabs/seki-tabs-list.d.ts +2 -5
  185. package/dist/types/components/tabs/seki-tabs-trigger.d.ts +3 -4
  186. package/dist/types/components/tabs/seki-tabs.d.ts +8 -2
  187. package/dist/types/components/tabs/tab-ids.d.ts +5 -0
  188. package/dist/types/components.d.ts +14 -0
  189. package/dist/types/utils/host-id.d.ts +7 -0
  190. package/package.json +1 -1
  191. package/dist/sekiui/p-00ed0a52.entry.js +0 -1
  192. package/dist/sekiui/p-02fe58f7.entry.js +0 -1
  193. package/dist/sekiui/p-044e875d.entry.js +0 -1
  194. package/dist/sekiui/p-1971d77d.entry.js +0 -1
  195. package/dist/sekiui/p-233a4393.entry.js +0 -1
  196. package/dist/sekiui/p-2622ca4c.entry.js +0 -1
  197. package/dist/sekiui/p-28c64e07.entry.js +0 -1
  198. package/dist/sekiui/p-2bd22398.entry.js +0 -1
  199. package/dist/sekiui/p-368d2d15.entry.js +0 -1
  200. package/dist/sekiui/p-49742de9.entry.js +0 -1
  201. package/dist/sekiui/p-5bfb96fd.entry.js +0 -1
  202. package/dist/sekiui/p-5e596590.entry.js +0 -1
  203. package/dist/sekiui/p-78c8c4bf.entry.js +0 -1
  204. package/dist/sekiui/p-88ba7051.entry.js +0 -1
  205. package/dist/sekiui/p-90387022.entry.js +0 -1
  206. package/dist/sekiui/p-CmuSriLz.js +0 -1
  207. package/dist/sekiui/p-af71afe5.entry.js +0 -1
  208. package/dist/sekiui/p-b26b3102.entry.js +0 -1
  209. package/dist/sekiui/p-b43f6733.entry.js +0 -1
  210. package/dist/sekiui/p-bf687983.entry.js +0 -1
  211. package/dist/sekiui/p-eafe8a84.entry.js +0 -1
  212. package/dist/sekiui/p-ec0d8978.entry.js +0 -1
  213. package/dist/sekiui/p-f418ba3a.entry.js +0 -1
@@ -801,11 +801,15 @@
801
801
  }
802
802
 
803
803
  .resizable-handle:hover:not(.resizable-handle--disabled),
804
- .resizable-handle:focus-visible:not(.resizable-handle--disabled) {
804
+ :host(:focus-visible) .resizable-handle:not(.resizable-handle--disabled) {
805
805
  background: var(--seki-primary, hsl(240 5.9% 10%));
806
806
  }
807
807
 
808
- .resizable-handle:focus-visible {
808
+ :host {
809
+ outline: none;
810
+ }
811
+
812
+ :host(:focus-visible) .resizable-handle {
809
813
  outline: 2px solid var(--seki-ring, hsl(240 5% 64.9%));
810
814
  outline-offset: 2px;
811
815
  }
@@ -1,6 +1,9 @@
1
1
  // src/components/resizable/seki-resizable-handle.tsx
2
2
  import { h, Host } from "@stencil/core";
3
3
  import { subscribeToContextChange } from "../../utils/context-bridge";
4
+ import { isRtl } from "../../utils/direction";
5
+ import { effectiveHostId } from "../../utils/host-id";
6
+ import { panelHostId } from "./layout";
4
7
  /**
5
8
  * Resizable handle - draggable divider between panels
6
9
  *
@@ -23,6 +26,9 @@ export class SekiResizableHandle {
23
26
  this._direction = 'horizontal';
24
27
  this.startPosition = 0;
25
28
  this.groupElement = null;
29
+ this.loaded = false;
30
+ // The aria-label we generated on the host; any other value is the author's.
31
+ this.ownLabel = null;
26
32
  this.contextSubscription = null;
27
33
  this.handleDirectionChange = () => {
28
34
  const context = this.getContext();
@@ -52,7 +58,10 @@ export class SekiResizableHandle {
52
58
  if (!context || !this.groupElement)
53
59
  return;
54
60
  const currentPosition = this._direction === 'horizontal' ? event.clientX : event.clientY;
55
- const deltaPixels = currentPosition - this.startPosition;
61
+ // A horizontal group lays its panels out right-to-left under dir="rtl", so
62
+ // moving the pointer right shrinks the panel before the handle.
63
+ const flip = this._direction === 'horizontal' && isRtl(this.el) ? -1 : 1;
64
+ const deltaPixels = (currentPosition - this.startPosition) * flip;
56
65
  // Convert to percentage
57
66
  const groupRect = this.groupElement.getBoundingClientRect();
58
67
  const groupSize = this._direction === 'horizontal' ? groupRect.width : groupRect.height;
@@ -82,13 +91,34 @@ export class SekiResizableHandle {
82
91
  this._direction = context.direction;
83
92
  }
84
93
  }
85
- componentDidLoad() {
94
+ /** (Re)bind to the enclosing group; also runs after the handle is moved. */
95
+ attach() {
86
96
  const group = this.el.closest('seki-resizable-panel-group');
87
- if (group) {
88
- this.groupElement = group;
89
- group.addEventListener('sekiDirectionChange', this.handleDirectionChange);
90
- group.addEventListener('sekiLayoutChange', this.handleLayoutChange);
97
+ if (!group || group === this.groupElement)
98
+ return;
99
+ this.detach();
100
+ this.groupElement = group;
101
+ group.addEventListener('sekiDirectionChange', this.handleDirectionChange);
102
+ group.addEventListener('sekiLayoutChange', this.handleLayoutChange);
103
+ }
104
+ detach() {
105
+ if (this.groupElement) {
106
+ this.groupElement.removeEventListener('sekiDirectionChange', this.handleDirectionChange);
107
+ this.groupElement.removeEventListener('sekiLayoutChange', this.handleLayoutChange);
91
108
  }
109
+ this.groupElement = null;
110
+ }
111
+ connectedCallback() {
112
+ // Re-wire after a DOM move; componentDidLoad only fires once.
113
+ if (this.loaded) {
114
+ this.attach();
115
+ this.handleDirectionChange();
116
+ this.handleLayoutChange();
117
+ }
118
+ }
119
+ componentDidLoad() {
120
+ this.loaded = true;
121
+ this.attach();
92
122
  // Pick up the direction once the group publishes its context, which may be
93
123
  // after this handle loaded in the per-tag custom-elements build.
94
124
  this.contextSubscription = subscribeToContextChange(this.el, 'seki-resizable-panel-group', this.handleDirectionChange);
@@ -96,10 +126,7 @@ export class SekiResizableHandle {
96
126
  }
97
127
  disconnectedCallback() {
98
128
  var _a;
99
- if (this.groupElement) {
100
- this.groupElement.removeEventListener('sekiDirectionChange', this.handleDirectionChange);
101
- this.groupElement.removeEventListener('sekiLayoutChange', this.handleLayoutChange);
102
- }
129
+ this.detach();
103
130
  (_a = this.contextSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
104
131
  this.contextSubscription = null;
105
132
  }
@@ -113,20 +140,22 @@ export class SekiResizableHandle {
113
140
  if (handleIndex === -1)
114
141
  return;
115
142
  const isHorizontal = this._direction === 'horizontal';
143
+ // Arrow keys are visual; in RTL the panel before the handle is on the right.
144
+ const flip = isHorizontal && isRtl(this.el) ? -1 : 1;
116
145
  const smallStep = 1;
117
146
  const largeStep = 10;
118
147
  switch (event.key) {
119
148
  case 'ArrowLeft':
120
149
  if (isHorizontal) {
121
150
  event.preventDefault();
122
- const step = event.shiftKey ? -largeStep : -smallStep;
151
+ const step = (event.shiftKey ? -largeStep : -smallStep) * flip;
123
152
  context.resizePanels(handleIndex, step);
124
153
  }
125
154
  break;
126
155
  case 'ArrowRight':
127
156
  if (isHorizontal) {
128
157
  event.preventDefault();
129
- const step = event.shiftKey ? largeStep : smallStep;
158
+ const step = (event.shiftKey ? largeStep : smallStep) * flip;
130
159
  context.resizePanels(handleIndex, step);
131
160
  }
132
161
  break;
@@ -163,16 +192,44 @@ export class SekiResizableHandle {
163
192
  return { now: 50, min: 0, max: 100 };
164
193
  return { now: Math.round(range.now), min: Math.round(range.min), max: Math.round(range.max) };
165
194
  }
195
+ /**
196
+ * WAI-ARIA window splitter: the separator controls the primary pane (the one
197
+ * before it). IDREFs cannot cross shadow roots, so everything lives on this
198
+ * light-DOM host and points at the panel host in the same tree scope.
199
+ */
200
+ getControlled() {
201
+ const context = this.getContext();
202
+ if (!context)
203
+ return { id: null, label: null };
204
+ const panelId = context.getPanelOrder()[context.getHandleIndex(this.el)];
205
+ const panel = panelId ? context.getPanelElement(panelId) : null;
206
+ if (!panelId || !panel)
207
+ return { id: null, label: null };
208
+ return {
209
+ id: effectiveHostId(panel, panelHostId(panelId)),
210
+ label: panel.getAttribute('aria-label'),
211
+ };
212
+ }
213
+ resolveLabel(controlledLabel) {
214
+ const current = this.el.getAttribute('aria-label');
215
+ if (current !== null && current !== this.ownLabel)
216
+ return current; // author-provided
217
+ this.ownLabel = controlledLabel || 'Resize handle';
218
+ return this.ownLabel;
219
+ }
166
220
  render() {
221
+ var _a, _b;
167
222
  const isHorizontal = this._direction === 'horizontal';
168
223
  const range = this.getAriaRange();
169
- return (h(Host, { key: '83f479c54a4b9bd6774df281ed0586b9113e72a0' }, h("div", { key: '64d97bd8e72cdc18185b0bfc927b1cba5daff71f', part: "handle", role: "separator", tabindex: this.disabled ? -1 : 0, "aria-valuenow": range.now, "aria-valuemin": range.min, "aria-valuemax": range.max, "aria-orientation": isHorizontal ? 'vertical' : 'horizontal', "aria-label": "Resize handle", class: {
224
+ const controlled = this.getControlled();
225
+ const isDisabled = this.disabled || !!((_a = this.getContext()) === null || _a === void 0 ? void 0 : _a.disabled);
226
+ return (h(Host, { key: 'd5d598d73db57d447393e478c4bcbad036cabc21', role: "separator", tabindex: isDisabled ? -1 : 0, "aria-valuenow": range.now, "aria-valuemin": range.min, "aria-valuemax": range.max, "aria-orientation": isHorizontal ? 'vertical' : 'horizontal', "aria-label": this.resolveLabel(controlled.label), "aria-controls": (_b = controlled.id) !== null && _b !== void 0 ? _b : undefined, "aria-disabled": isDisabled ? 'true' : undefined }, h("div", { key: '29f8a250bf62aadc3ad5a436935367f9b26cd7da', part: "handle", class: {
170
227
  'resizable-handle': true,
171
228
  'resizable-handle--horizontal': isHorizontal,
172
229
  'resizable-handle--vertical': !isHorizontal,
173
230
  'resizable-handle--disabled': this.disabled,
174
231
  'resizable-handle--dragging': this._isDragging,
175
- }, onPointerDown: this.handlePointerDown, onPointerMove: this.handlePointerMove, onPointerUp: this.handlePointerUp }, this.withHandle && (h("div", { key: 'c09507c1b067f00ccb447e443ff4d9da948475cb', part: "grip", class: "resizable-handle__grip" }, h("svg", { key: 'ad6ee321e91f3b8c4221b826000e46cec442176b', class: "resizable-handle__grip-icon", viewBox: "0 0 6 16", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("circle", { key: '8e716a1255b4d80cc14f3c745fc4d179fffd4e10', cx: "1.5", cy: "2", r: "1", fill: "currentColor" }), h("circle", { key: '38040394e39767cba8a758f67dc1c314ba6e44e5', cx: "4.5", cy: "2", r: "1", fill: "currentColor" }), h("circle", { key: 'ffc2c4fc89216b8722cf137ed8642a15dc071987', cx: "1.5", cy: "6", r: "1", fill: "currentColor" }), h("circle", { key: 'c4937f77a7819dddca6fdf51d4214974d2fab3ae', cx: "4.5", cy: "6", r: "1", fill: "currentColor" }), h("circle", { key: 'e431a62885cd25a462b8b5e22bd972b3ad988653', cx: "1.5", cy: "10", r: "1", fill: "currentColor" }), h("circle", { key: 'afba75fbb974a55a05e5822140eba759e87c141e', cx: "4.5", cy: "10", r: "1", fill: "currentColor" }), h("circle", { key: '88cb3bb8a1c088aa5589c737b79af46fd0215d22', cx: "1.5", cy: "14", r: "1", fill: "currentColor" }), h("circle", { key: '1eeb0515522cd4859385914a6fa5ff1a7b57691d', cx: "4.5", cy: "14", r: "1", fill: "currentColor" })))))));
232
+ }, onPointerDown: this.handlePointerDown, onPointerMove: this.handlePointerMove, onPointerUp: this.handlePointerUp }, this.withHandle && (h("div", { key: '65c10331e9f97979b272b1dc83c9a122939fc437', part: "grip", class: "resizable-handle__grip" }, h("svg", { key: '3c02d5f8bd72bc7e9549f251168dc6a6de081dad', class: "resizable-handle__grip-icon", viewBox: "0 0 6 16", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("circle", { key: '380a11b2cf250b6190734083e5f05ba0c00b4dde', cx: "1.5", cy: "2", r: "1", fill: "currentColor" }), h("circle", { key: 'bc169db3f5d287264797dd56da8374ea35663327', cx: "4.5", cy: "2", r: "1", fill: "currentColor" }), h("circle", { key: '626d7dfa182d9f1f1248e7cea476378e645fbc5b', cx: "1.5", cy: "6", r: "1", fill: "currentColor" }), h("circle", { key: 'd95b05917be3964f1c3c1d5abf8969aa667dab65', cx: "4.5", cy: "6", r: "1", fill: "currentColor" }), h("circle", { key: 'f98ecea62129e2af13ff87f59407f7c150384357', cx: "1.5", cy: "10", r: "1", fill: "currentColor" }), h("circle", { key: '5f7f37ed7a8d8afe81444cfe7a412719ed9f0b7f', cx: "4.5", cy: "10", r: "1", fill: "currentColor" }), h("circle", { key: '06941c191e2bb1273dffd15d956dd43faf4fadb6', cx: "1.5", cy: "14", r: "1", fill: "currentColor" }), h("circle", { key: '7e96b8f034b59242f98f5e4b5b97578301a5e35e', cx: "4.5", cy: "14", r: "1", fill: "currentColor" })))))));
176
233
  }
177
234
  static get is() { return "seki-resizable-handle"; }
178
235
  static get encapsulation() { return "shadow"; }
@@ -44,6 +44,7 @@ export class SekiResizablePanelGroup {
44
44
  collapsePanel: () => { },
45
45
  expandPanel: () => { },
46
46
  isCollapsed: () => false,
47
+ getPanelElement: () => null,
47
48
  getHandleIndex: () => -1,
48
49
  };
49
50
  this.registerPanel = (id, constraints, element) => {
@@ -92,6 +93,7 @@ export class SekiResizablePanelGroup {
92
93
  var _a, _b;
93
94
  return (_b = (_a = this._panels.get(id)) === null || _a === void 0 ? void 0 : _a.isCollapsed) !== null && _b !== void 0 ? _b : false;
94
95
  };
96
+ this.getPanelElement = (id) => { var _a; return (_a = this.panelElements.get(id)) !== null && _a !== void 0 ? _a : null; };
95
97
  this.getHandleIndex = (handleElement) => {
96
98
  const handles = Array.from(this.el.querySelectorAll('seki-resizable-handle'));
97
99
  return handles.indexOf(handleElement);
@@ -267,6 +269,7 @@ export class SekiResizablePanelGroup {
267
269
  collapsePanel: this.collapsePanel,
268
270
  expandPanel: this.expandPanel,
269
271
  isCollapsed: this.isCollapsed,
272
+ getPanelElement: this.getPanelElement,
270
273
  getHandleIndex: this.getHandleIndex,
271
274
  };
272
275
  this._resizableContext = context;
@@ -332,11 +335,11 @@ export class SekiResizablePanelGroup {
332
335
  }
333
336
  }
334
337
  render() {
335
- return (h(Host, { key: '5fe1c6125506aee9cae6d412c33846986004f04c' }, h("div", { key: '04e52a26b3cb5cef717e4b7cffa76b9f198875db', part: "group", role: "group", "aria-label": "Resizable panel group", class: {
338
+ return (h(Host, { key: 'e921bd4bf9566022d1b1df8b15e65fbe446a8eaf' }, h("div", { key: 'e54ea8623bba0ec7c7a4b8d2666ebcc4d2071859', part: "group", role: "group", "aria-label": "Resizable panel group", class: {
336
339
  'resizable-panel-group': true,
337
340
  'resizable-panel-group--horizontal': this.direction === 'horizontal',
338
341
  'resizable-panel-group--vertical': this.direction === 'vertical',
339
- } }, h("slot", { key: '86ace975a70a0c3fcdf4acd2e98cebfee9812c98' }))));
342
+ } }, h("slot", { key: '3c289f22bccadb3d1fe418b221619f2dc60791fe' }))));
340
343
  }
341
344
  static get is() { return "seki-resizable-panel-group"; }
342
345
  static get encapsulation() { return "shadow"; }
@@ -1,6 +1,8 @@
1
1
  // src/components/resizable/seki-resizable-panel.tsx
2
2
  import { h, Host } from "@stencil/core";
3
3
  import { subscribeToContextChange } from "../../utils/context-bridge";
4
+ import { claimHostId } from "../../utils/host-id";
5
+ import { panelHostId } from "./layout";
4
6
  let panelIdCounter = 0;
5
7
  /**
6
8
  * Resizable panel - individual content panel with size constraints
@@ -168,14 +170,14 @@ export class SekiResizablePanel {
168
170
  return this.panelId;
169
171
  }
170
172
  render() {
171
- return (h(Host, { key: '7131acc444ff314abcecdefea6d50a7d35b0994e', style: {
173
+ return (h(Host, { key: '315770a2c0d1a43476a411d128bba7a1e0c8340d', id: claimHostId(this.el, panelHostId(this.panelId)), style: {
172
174
  flexBasis: `${this._size}%`,
173
175
  flexGrow: '0',
174
176
  flexShrink: '0',
175
- } }, h("div", { key: '2b75e0fe753750cf3f3dba471c51b75d23b44356', part: "panel", role: "region", class: {
177
+ } }, h("div", { key: '966dc30c32d38089963cd8509524abd099458115', part: "panel", role: "region", class: {
176
178
  'resizable-panel': true,
177
179
  'resizable-panel--collapsed': this._isCollapsed,
178
- } }, h("slot", { key: '295aa48096e5188fd40dda5e52f180eb4512a193' }))));
180
+ } }, h("slot", { key: '37cc25bf4a11a1b9a8d537092762a38be729f16a' }))));
179
181
  }
180
182
  static get is() { return "seki-resizable-panel"; }
181
183
  static get encapsulation() { return "shadow"; }
@@ -1,5 +1,7 @@
1
1
  import { h, Host } from "@stencil/core";
2
- import { getTabIds } from "./tab-ids";
2
+ import { ContextConsumer } from "../../utils/context-bridge";
3
+ import { getTabIds, findTabPeer } from "./tab-ids";
4
+ import { claimHostId, effectiveHostId } from "../../utils/host-id";
3
5
  /**
4
6
  * Tab content panel
5
7
  *
@@ -10,42 +12,39 @@ import { getTabIds } from "./tab-ids";
10
12
  export class SekiTabsContent {
11
13
  constructor() {
12
14
  this._isSelected = false;
13
- this.onTabsValueChange = () => {
15
+ this.tabs = new ContextConsumer('seki-tabs', '_tabsContext', (context) => {
14
16
  var _a;
15
- const context = this.getContext();
16
17
  this._isSelected = (_a = context === null || context === void 0 ? void 0 : context.isSelected(this.value)) !== null && _a !== void 0 ? _a : false;
17
- };
18
+ });
18
19
  }
19
20
  getContext() {
20
- const tabs = this.el.closest('seki-tabs');
21
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
- return tabs ? tabs._tabsContext : null;
21
+ return this.tabs.context;
23
22
  }
24
23
  get ids() {
25
24
  return getTabIds(this.el.closest('seki-tabs'), this.value);
26
25
  }
27
- componentWillRender() {
28
- var _a;
29
- const context = this.getContext();
30
- this._isSelected = (_a = context === null || context === void 0 ? void 0 : context.isSelected(this.value)) !== null && _a !== void 0 ? _a : false;
26
+ connectedCallback() {
27
+ this.tabs.connect(this.el);
31
28
  }
32
- componentDidLoad() {
29
+ valueChanged() {
33
30
  var _a, _b;
34
- // Listen for value changes from parent tabs
35
- this.tabsEl = (_a = this.el.closest('seki-tabs')) !== null && _a !== void 0 ? _a : undefined;
36
- (_b = this.tabsEl) === null || _b === void 0 ? void 0 : _b.addEventListener('sekiValueChange', this.onTabsValueChange);
31
+ // The part's own value changed: re-evaluate against the current context.
32
+ this._isSelected = (_b = (_a = this.getContext()) === null || _a === void 0 ? void 0 : _a.isSelected(this.value)) !== null && _b !== void 0 ? _b : false;
37
33
  }
38
34
  disconnectedCallback() {
39
- var _a;
40
- (_a = this.tabsEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('sekiValueChange', this.onTabsValueChange);
35
+ this.tabs.disconnect();
41
36
  }
42
37
  render() {
43
38
  const isSelected = this._isSelected;
44
39
  const { triggerId, panelId } = this.ids;
45
- return (h(Host, { key: '358f26f62be13d99c2d8e2f0920d83be6850ad73', "data-state": isSelected ? 'active' : 'inactive', role: "tabpanel", id: panelId, "aria-labelledby": triggerId, hidden: !isSelected, tabindex: isSelected ? 0 : -1 }, h("div", { key: 'c8cc92104ad3c64cade8801917eb9bbd01b79952', part: "content", class: {
40
+ // Keep an author-set id on either host; IDREFs use whatever id each host has.
41
+ const hostId = claimHostId(this.el, panelId);
42
+ const trigger = findTabPeer(this.el.closest('seki-tabs'), 'seki-tabs-trigger', this.value);
43
+ const labelledById = effectiveHostId(trigger, triggerId);
44
+ return (h(Host, { key: '8bbe15f6616031c9c6b75fb7028b98d5a95487f6', "data-state": isSelected ? 'active' : 'inactive', role: "tabpanel", id: hostId, "aria-labelledby": labelledById, hidden: !isSelected, tabindex: isSelected ? 0 : -1 }, h("div", { key: '6a9277868adafa201ab23fc015d87ddc4f3c0344', part: "content", class: {
46
45
  'tabs-content': true,
47
46
  'tabs-content--active': isSelected,
48
- } }, h("slot", { key: 'e55305721b99f69cec73544236fd036601f618e4' }))));
47
+ } }, h("slot", { key: '4de0e63849e10e70990aca111e4ed85dfedad52e' }))));
49
48
  }
50
49
  static get is() { return "seki-tabs-content"; }
51
50
  static get encapsulation() { return "shadow"; }
@@ -88,4 +87,10 @@ export class SekiTabsContent {
88
87
  };
89
88
  }
90
89
  static get elementRef() { return "el"; }
90
+ static get watchers() {
91
+ return [{
92
+ "propName": "value",
93
+ "methodName": "valueChanged"
94
+ }];
95
+ }
91
96
  }
@@ -1,4 +1,5 @@
1
1
  import { h, Host } from "@stencil/core";
2
+ import { ContextConsumer } from "../../utils/context-bridge";
2
3
  /**
3
4
  * Container for tab triggers
4
5
  *
@@ -9,40 +10,23 @@ import { h, Host } from "@stencil/core";
9
10
  export class SekiTabsList {
10
11
  constructor() {
11
12
  this._orientation = 'horizontal';
12
- this.onTabsValueChange = () => {
13
+ this.tabs = new ContextConsumer('seki-tabs', '_tabsContext', (context) => {
13
14
  var _a;
14
- const context = this.getContext();
15
15
  this._orientation = (_a = context === null || context === void 0 ? void 0 : context.orientation) !== null && _a !== void 0 ? _a : 'horizontal';
16
- };
17
- }
18
- getContext() {
19
- const tabs = this.el.closest('seki-tabs');
20
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
- return tabs ? tabs._tabsContext : null;
22
- }
23
- componentWillRender() {
24
- var _a;
25
- const context = this.getContext();
26
- this._orientation = (_a = context === null || context === void 0 ? void 0 : context.orientation) !== null && _a !== void 0 ? _a : 'horizontal';
16
+ });
27
17
  }
28
- componentDidLoad() {
29
- var _a, _b;
30
- // Listen for the parent's only notification event so this list re-checks
31
- // orientation after mount — without this, orientation freezes at whatever
32
- // it was when the list first rendered (found during the #261 audit).
33
- this.tabsEl = (_a = this.el.closest('seki-tabs')) !== null && _a !== void 0 ? _a : undefined;
34
- (_b = this.tabsEl) === null || _b === void 0 ? void 0 : _b.addEventListener('sekiValueChange', this.onTabsValueChange);
18
+ connectedCallback() {
19
+ this.tabs.connect(this.el);
35
20
  }
36
21
  disconnectedCallback() {
37
- var _a;
38
- (_a = this.tabsEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('sekiValueChange', this.onTabsValueChange);
22
+ this.tabs.disconnect();
39
23
  }
40
24
  render() {
41
25
  const orientation = this._orientation;
42
- return (h(Host, { key: 'fe9b44507284c1b0b9ce1ebcf8b37e143ac971ce', "data-orientation": orientation }, h("div", { key: '33aec6c7f47545ca3fa448288aaea07cb2e6fd5f', part: "list", role: "tablist", "aria-orientation": orientation, class: {
26
+ return (h(Host, { key: '3a9b098b96f1a1b6e639a78a71c66d9d7c0ac614', "data-orientation": orientation }, h("div", { key: 'd72c6d73977ef9daee3c70d539653df83bacec9a', part: "list", role: "tablist", "aria-orientation": orientation, class: {
43
27
  'tabs-list': true,
44
28
  [`tabs-list--${orientation}`]: true,
45
- } }, h("slot", { key: '11b4a3e8dd650963f08cf5b61e0e36f7d2119d5e' }))));
29
+ } }, h("slot", { key: '9f80bf08dfd995468a89e7e561a97eadd59d3183' }))));
46
30
  }
47
31
  static get is() { return "seki-tabs-list"; }
48
32
  static get encapsulation() { return "shadow"; }
@@ -1,5 +1,7 @@
1
1
  import { h, Host } from "@stencil/core";
2
- import { getTabIds } from "./tab-ids";
2
+ import { ContextConsumer } from "../../utils/context-bridge";
3
+ import { getTabIds, findTabPeer } from "./tab-ids";
4
+ import { claimHostId, effectiveHostId } from "../../utils/host-id";
3
5
  import { isRtl } from "../../utils/direction";
4
6
  /**
5
7
  * Tab trigger button
@@ -15,30 +17,24 @@ export class SekiTabsTrigger {
15
17
  */
16
18
  this.disabled = false;
17
19
  this._isSelected = false;
18
- this.onTabsValueChange = () => {
20
+ this.tabs = new ContextConsumer('seki-tabs', '_tabsContext', (context) => {
19
21
  var _a;
20
- const context = this.getContext();
21
22
  this._isSelected = (_a = context === null || context === void 0 ? void 0 : context.isSelected(this.value)) !== null && _a !== void 0 ? _a : false;
22
- };
23
+ });
23
24
  }
24
25
  getContext() {
25
- const tabs = this.el.closest('seki-tabs');
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
- return tabs ? tabs._tabsContext : null;
26
+ return this.tabs.context;
28
27
  }
29
28
  get ids() {
30
29
  return getTabIds(this.el.closest('seki-tabs'), this.value);
31
30
  }
32
- componentWillRender() {
33
- var _a;
34
- const context = this.getContext();
35
- this._isSelected = (_a = context === null || context === void 0 ? void 0 : context.isSelected(this.value)) !== null && _a !== void 0 ? _a : false;
31
+ connectedCallback() {
32
+ this.tabs.connect(this.el);
36
33
  }
37
- componentDidLoad() {
34
+ valueChanged() {
38
35
  var _a, _b;
39
- // Listen for value changes from parent tabs
40
- this.tabsEl = (_a = this.el.closest('seki-tabs')) !== null && _a !== void 0 ? _a : undefined;
41
- (_b = this.tabsEl) === null || _b === void 0 ? void 0 : _b.addEventListener('sekiValueChange', this.onTabsValueChange);
36
+ // The part's own value changed: re-evaluate against the current context.
37
+ this._isSelected = (_b = (_a = this.getContext()) === null || _a === void 0 ? void 0 : _a.isSelected(this.value)) !== null && _b !== void 0 ? _b : false;
42
38
  }
43
39
  handleClick() {
44
40
  if (this.disabled)
@@ -159,16 +155,19 @@ export class SekiTabsTrigger {
159
155
  }
160
156
  }
161
157
  disconnectedCallback() {
162
- var _a;
163
- (_a = this.tabsEl) === null || _a === void 0 ? void 0 : _a.removeEventListener('sekiValueChange', this.onTabsValueChange);
158
+ this.tabs.disconnect();
164
159
  }
165
160
  render() {
166
161
  const isSelected = this._isSelected;
167
162
  const { triggerId, panelId } = this.ids;
168
- return (h(Host, { key: 'c8b584c8f281d46e015d507f61f6d6aecbcafb30', id: triggerId, "data-state": isSelected ? 'active' : 'inactive', "data-disabled": this.disabled ? '' : undefined, tabindex: this.disabled ? -1 : 0, role: "tab", "aria-selected": isSelected ? 'true' : 'false', "aria-controls": panelId }, h("button", { key: 'd635ec5ab25d34ccfa3db861e1ff946cd9964703', part: "trigger", type: "button", class: {
163
+ // Keep an author-set id on either host; IDREFs use whatever id each host has.
164
+ const hostId = claimHostId(this.el, triggerId);
165
+ const panel = findTabPeer(this.el.closest('seki-tabs'), 'seki-tabs-content', this.value);
166
+ const controlsId = effectiveHostId(panel, panelId);
167
+ return (h(Host, { key: '12d3ad61a2abcec3839d92baee7eb245514fbb52', id: hostId, "data-state": isSelected ? 'active' : 'inactive', "data-disabled": this.disabled ? '' : undefined, tabindex: this.disabled ? -1 : 0, role: "tab", "aria-selected": isSelected ? 'true' : 'false', "aria-controls": controlsId }, h("button", { key: '5ac3ffd4c1581e596ab18ce99e3aa91421ae9a4c', part: "trigger", type: "button", class: {
169
168
  'tabs-trigger': true,
170
169
  'tabs-trigger--active': isSelected,
171
- }, disabled: this.disabled, tabindex: -1 }, h("slot", { key: '6a3e0516bc5c865c997b2d974b93b441dc8a5467' }))));
170
+ }, disabled: this.disabled, tabindex: -1 }, h("slot", { key: '1e5440b27cd8a7e71f8a55c303c2331c76e2583b' }))));
172
171
  }
173
172
  static get is() { return "seki-tabs-trigger"; }
174
173
  static get encapsulation() { return "shadow"; }
@@ -231,6 +230,12 @@ export class SekiTabsTrigger {
231
230
  };
232
231
  }
233
232
  static get elementRef() { return "el"; }
233
+ static get watchers() {
234
+ return [{
235
+ "propName": "value",
236
+ "methodName": "valueChanged"
237
+ }];
238
+ }
234
239
  static get listeners() {
235
240
  return [{
236
241
  "name": "click",
@@ -1,4 +1,5 @@
1
1
  import { h, Host } from "@stencil/core";
2
+ import { publishContext } from "../../utils/context-bridge";
2
3
  /**
3
4
  * Tabs root component that manages selected tab state
4
5
  *
@@ -22,15 +23,17 @@ export class SekiTabs {
22
23
  // Initialize from value or defaultValue
23
24
  const initialValue = (_b = (_a = this.value) !== null && _a !== void 0 ? _a : this.defaultValue) !== null && _b !== void 0 ? _b : '';
24
25
  this._selectedValue = initialValue;
25
- // Publish before children load: they read the context in their first
26
- // render, and componentDidLoad (parent-last) would be too late, leaving
27
- // the initially selected panel hidden.
28
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
- this.el._tabsContext = this.getContext();
26
+ // Publish before children load: parts that are already upgraded pick it up
27
+ // from the event, parts that upgrade later read it when they connect (#384).
28
+ this.publish();
29
+ }
30
+ orientationChanged() {
31
+ this.publish();
30
32
  }
31
33
  valueChanged(newValue) {
32
34
  if (newValue !== undefined) {
33
35
  this._selectedValue = newValue;
36
+ this.publish();
34
37
  // Programmatic `tabsEl.value = x` must notify already-mounted children
35
38
  // the same way selectTab() does, or seki-tabs-trigger/seki-tabs-list
36
39
  // silently stay stale (found during the #261 audit).
@@ -48,9 +51,9 @@ export class SekiTabs {
48
51
  // sekiValueChange — no separate emit needed here (found during #268;
49
52
  // #261 originally left both, causing a double-emit on every click).
50
53
  this.value = tabValue;
51
- // Update context for child components
52
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
53
- this.el._tabsContext = this.getContext();
54
+ }
55
+ publish() {
56
+ publishContext(this.el, '_tabsContext', this.getContext(), this.contextChange);
54
57
  }
55
58
  isSelected(tabValue) {
56
59
  return this._selectedValue === tabValue;
@@ -63,19 +66,11 @@ export class SekiTabs {
63
66
  isSelected: (value) => this.isSelected(value),
64
67
  };
65
68
  }
66
- componentDidLoad() {
67
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
- this.el._tabsContext = this.getContext();
69
- }
70
- componentDidUpdate() {
71
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
- this.el._tabsContext = this.getContext();
73
- }
74
69
  render() {
75
- return (h(Host, { key: '6dabe970a9d7129184acdd2be17fbccf8e4bc7e7', "data-orientation": this.orientation }, h("div", { key: 'a5d5f6ddb4f8f81c3934a6493da102bfd920f578', part: "tabs", class: {
70
+ return (h(Host, { key: '3e4cf3afc38da559d0f6f3558b5e56f3e994bcc0', "data-orientation": this.orientation }, h("div", { key: 'd7a04a38c27904ba02224e97574393dfb0fa18bc', part: "tabs", class: {
76
71
  'tabs': true,
77
72
  [`tabs--${this.orientation}`]: true,
78
- } }, h("slot", { key: '19cab6ce422e33ff2d64d44d50fdea8acbd88577' }))));
73
+ } }, h("slot", { key: '6cb943c282fe0e538dd7d6fa2ef453204c3eb0b0' }))));
79
74
  }
80
75
  static get is() { return "seki-tabs"; }
81
76
  static get encapsulation() { return "shadow"; }
@@ -172,6 +167,24 @@ export class SekiTabs {
172
167
  "resolved": "string",
173
168
  "references": {}
174
169
  }
170
+ }, {
171
+ "method": "contextChange",
172
+ "name": "sekiContextChange",
173
+ "bubbles": true,
174
+ "cancelable": true,
175
+ "composed": true,
176
+ "docs": {
177
+ "tags": [{
178
+ "name": "internal",
179
+ "text": undefined
180
+ }],
181
+ "text": "Internal: notifies tab parts that the published context changed. Not part\nof the public API (sekiValueChange is)."
182
+ },
183
+ "complexType": {
184
+ "original": "void",
185
+ "resolved": "void",
186
+ "references": {}
187
+ }
175
188
  }];
176
189
  }
177
190
  static get methods() {
@@ -202,6 +215,9 @@ export class SekiTabs {
202
215
  static get elementRef() { return "el"; }
203
216
  static get watchers() {
204
217
  return [{
218
+ "propName": "orientation",
219
+ "methodName": "orientationChanged"
220
+ }, {
205
221
  "propName": "value",
206
222
  "methodName": "valueChanged"
207
223
  }];
@@ -20,3 +20,16 @@ export function getTabIds(tabsEl, value) {
20
20
  const v = sanitize(value !== null && value !== void 0 ? value : '');
21
21
  return { triggerId: `${base}-trigger-${v}`, panelId: `${base}-panel-${v}` };
22
22
  }
23
+ /**
24
+ * The trigger/panel host with the given `value` that belongs to `tabsEl` (not
25
+ * to a nested `seki-tabs`), or null when the tree has no such peer.
26
+ */
27
+ export function findTabPeer(tabsEl, tag, value) {
28
+ if (!tabsEl)
29
+ return null;
30
+ for (const el of Array.from(tabsEl.querySelectorAll(tag))) {
31
+ if (el.closest('seki-tabs') === tabsEl && el.getAttribute('value') === value)
32
+ return el;
33
+ }
34
+ return null;
35
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Host ids for cross-shadow ARIA wiring (trigger host <-> content host).
3
+ *
4
+ * IDREFs cannot cross shadow roots, so components put their ids on the
5
+ * light-DOM hosts. An id the author wrote on the host must never be
6
+ * overwritten: `effectiveHostId` returns it when present and falls back to the
7
+ * generated id otherwise. We remember which id we generated per element so a
8
+ * generated id that changes later (e.g. the tab `value` changes) is replaced,
9
+ * while an author id (anything else on the element) is kept.
10
+ */
11
+ const generated = new WeakMap();
12
+ /** The id `el` actually has (author id, else `fallback`). Does not mutate. */
13
+ export function effectiveHostId(el, fallback) {
14
+ if (el && el.id && el.id !== generated.get(el))
15
+ return el.id;
16
+ return fallback;
17
+ }
18
+ /**
19
+ * Resolve the id to render on `el`: keeps an author-set id, otherwise records
20
+ * and returns `fallback`.
21
+ */
22
+ export function claimHostId(el, fallback) {
23
+ const id = effectiveHostId(el, fallback);
24
+ if (id === fallback)
25
+ generated.set(el, fallback);
26
+ return id;
27
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Text direction helpers for keyboard handling.
3
+ *
4
+ * `getComputedStyle().direction` already folds in the `dir` attribute on any
5
+ * ancestor (including across shadow boundaries via inheritance) and CSS
6
+ * `direction`, so it is the single source of truth.
7
+ */
8
+ function isRtl(el) {
9
+ return getComputedStyle(el).direction === 'rtl';
10
+ }
11
+
12
+ export { isRtl as i };