@aquera/nile-elements 1.6.7 → 1.6.8

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 (218) hide show
  1. package/README.md +4 -0
  2. package/dist/index.cjs.js +1 -1
  3. package/dist/index.esm.js +1 -1
  4. package/dist/index.js +1731 -488
  5. package/dist/internal/enum.cjs.js +1 -1
  6. package/dist/internal/enum.cjs.js.map +1 -1
  7. package/dist/internal/enum.esm.js +1 -1
  8. package/dist/nile-inline-sidebar/index.cjs.js +1 -1
  9. package/dist/nile-inline-sidebar/index.esm.js +1 -1
  10. package/dist/nile-inline-sidebar/nile-inline-sidebar.cjs.js +1 -1
  11. package/dist/nile-inline-sidebar/nile-inline-sidebar.cjs.js.map +1 -1
  12. package/dist/nile-inline-sidebar/nile-inline-sidebar.css.cjs.js +1 -1
  13. package/dist/nile-inline-sidebar/nile-inline-sidebar.css.cjs.js.map +1 -1
  14. package/dist/nile-inline-sidebar/nile-inline-sidebar.css.esm.js +76 -19
  15. package/dist/nile-inline-sidebar/nile-inline-sidebar.esm.js +42 -23
  16. package/dist/nile-inline-sidebar-group/nile-inline-sidebar-group.css.cjs.js +1 -1
  17. package/dist/nile-inline-sidebar-group/nile-inline-sidebar-group.css.cjs.js.map +1 -1
  18. package/dist/nile-inline-sidebar-group/nile-inline-sidebar-group.css.esm.js +8 -9
  19. package/dist/nile-inline-sidebar-item/index.cjs.js +1 -1
  20. package/dist/nile-inline-sidebar-item/index.esm.js +1 -1
  21. package/dist/nile-inline-sidebar-item/nile-inline-sidebar-item.cjs.js +1 -1
  22. package/dist/nile-inline-sidebar-item/nile-inline-sidebar-item.cjs.js.map +1 -1
  23. package/dist/nile-inline-sidebar-item/nile-inline-sidebar-item.css.cjs.js +1 -1
  24. package/dist/nile-inline-sidebar-item/nile-inline-sidebar-item.css.cjs.js.map +1 -1
  25. package/dist/nile-inline-sidebar-item/nile-inline-sidebar-item.css.esm.js +16 -18
  26. package/dist/nile-inline-sidebar-item/nile-inline-sidebar-item.esm.js +22 -4
  27. package/dist/nile-inline-sidebar-item-body/index.cjs.js +2 -0
  28. package/dist/nile-inline-sidebar-item-body/index.cjs.js.map +1 -0
  29. package/dist/nile-inline-sidebar-item-body/index.esm.js +1 -0
  30. package/dist/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.cjs.js +2 -0
  31. package/dist/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.cjs.js.map +1 -0
  32. package/dist/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.css.cjs.js +2 -0
  33. package/dist/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.css.cjs.js.map +1 -0
  34. package/dist/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.css.esm.js +53 -0
  35. package/dist/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.esm.js +13 -0
  36. package/dist/nile-inline-sidebar-item-header/index.cjs.js +2 -0
  37. package/dist/nile-inline-sidebar-item-header/index.cjs.js.map +1 -0
  38. package/dist/nile-inline-sidebar-item-header/index.esm.js +1 -0
  39. package/dist/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.cjs.js +2 -0
  40. package/dist/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.cjs.js.map +1 -0
  41. package/dist/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.css.cjs.js +2 -0
  42. package/dist/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.css.cjs.js.map +1 -0
  43. package/dist/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.css.esm.js +27 -0
  44. package/dist/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.esm.js +16 -0
  45. package/dist/nile-inline-sidebar-panel/index.cjs.js +2 -0
  46. package/dist/nile-inline-sidebar-panel/index.cjs.js.map +1 -0
  47. package/dist/nile-inline-sidebar-panel/index.esm.js +1 -0
  48. package/dist/nile-inline-sidebar-panel/nile-inline-sidebar-panel.cjs.js +2 -0
  49. package/dist/nile-inline-sidebar-panel/nile-inline-sidebar-panel.cjs.js.map +1 -0
  50. package/dist/nile-inline-sidebar-panel/nile-inline-sidebar-panel.css.cjs.js +2 -0
  51. package/dist/nile-inline-sidebar-panel/nile-inline-sidebar-panel.css.cjs.js.map +1 -0
  52. package/dist/nile-inline-sidebar-panel/nile-inline-sidebar-panel.css.esm.js +19 -0
  53. package/dist/nile-inline-sidebar-panel/nile-inline-sidebar-panel.esm.js +5 -0
  54. package/dist/nile-inline-sidebar-panel-group/index.cjs.js +2 -0
  55. package/dist/nile-inline-sidebar-panel-group/index.cjs.js.map +1 -0
  56. package/dist/nile-inline-sidebar-panel-group/index.esm.js +1 -0
  57. package/dist/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.cjs.js +2 -0
  58. package/dist/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.cjs.js.map +1 -0
  59. package/dist/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.css.cjs.js +2 -0
  60. package/dist/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.css.cjs.js.map +1 -0
  61. package/dist/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.css.esm.js +30 -0
  62. package/dist/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.esm.js +12 -0
  63. package/dist/nile-nav-tab/index.cjs.js +2 -0
  64. package/dist/nile-nav-tab/index.cjs.js.map +1 -0
  65. package/dist/nile-nav-tab/index.esm.js +1 -0
  66. package/dist/nile-nav-tab/nile-nav-tab.cjs.js +2 -0
  67. package/dist/nile-nav-tab/nile-nav-tab.cjs.js.map +1 -0
  68. package/dist/nile-nav-tab/nile-nav-tab.css.cjs.js +2 -0
  69. package/dist/nile-nav-tab/nile-nav-tab.css.cjs.js.map +1 -0
  70. package/dist/nile-nav-tab/nile-nav-tab.css.esm.js +190 -0
  71. package/dist/nile-nav-tab/nile-nav-tab.esm.js +36 -0
  72. package/dist/nile-nav-tab-group/index.cjs.js +2 -0
  73. package/dist/nile-nav-tab-group/index.cjs.js.map +1 -0
  74. package/dist/nile-nav-tab-group/index.esm.js +1 -0
  75. package/dist/nile-nav-tab-group/nile-nav-tab-group.cjs.js +4 -0
  76. package/dist/nile-nav-tab-group/nile-nav-tab-group.cjs.js.map +1 -0
  77. package/dist/nile-nav-tab-group/nile-nav-tab-group.css.cjs.js +2 -0
  78. package/dist/nile-nav-tab-group/nile-nav-tab-group.css.cjs.js.map +1 -0
  79. package/dist/nile-nav-tab-group/nile-nav-tab-group.css.esm.js +668 -0
  80. package/dist/nile-nav-tab-group/nile-nav-tab-group.esm.js +61 -0
  81. package/dist/nile-nav-tab-panel/index.cjs.js +2 -0
  82. package/dist/nile-nav-tab-panel/index.cjs.js.map +1 -0
  83. package/dist/nile-nav-tab-panel/index.esm.js +1 -0
  84. package/dist/nile-nav-tab-panel/nile-nav-tab-panel.cjs.js +2 -0
  85. package/dist/nile-nav-tab-panel/nile-nav-tab-panel.cjs.js.map +1 -0
  86. package/dist/nile-nav-tab-panel/nile-nav-tab-panel.css.cjs.js +2 -0
  87. package/dist/nile-nav-tab-panel/nile-nav-tab-panel.css.cjs.js.map +1 -0
  88. package/dist/nile-nav-tab-panel/nile-nav-tab-panel.css.esm.js +22 -0
  89. package/dist/nile-nav-tab-panel/nile-nav-tab-panel.esm.js +8 -0
  90. package/dist/src/index.d.ts +7 -0
  91. package/dist/src/index.js +7 -0
  92. package/dist/src/index.js.map +1 -1
  93. package/dist/src/internal/enum.d.ts +6 -0
  94. package/dist/src/internal/enum.js +7 -0
  95. package/dist/src/internal/enum.js.map +1 -1
  96. package/dist/src/nile-inline-sidebar/nile-inline-sidebar.css.d.ts +1 -0
  97. package/dist/src/nile-inline-sidebar/nile-inline-sidebar.css.js +75 -17
  98. package/dist/src/nile-inline-sidebar/nile-inline-sidebar.css.js.map +1 -1
  99. package/dist/src/nile-inline-sidebar/nile-inline-sidebar.d.ts +17 -1
  100. package/dist/src/nile-inline-sidebar/nile-inline-sidebar.js +147 -18
  101. package/dist/src/nile-inline-sidebar/nile-inline-sidebar.js.map +1 -1
  102. package/dist/src/nile-inline-sidebar-group/nile-inline-sidebar-group.css.d.ts +1 -0
  103. package/dist/src/nile-inline-sidebar-group/nile-inline-sidebar-group.css.js +7 -7
  104. package/dist/src/nile-inline-sidebar-group/nile-inline-sidebar-group.css.js.map +1 -1
  105. package/dist/src/nile-inline-sidebar-item/nile-inline-sidebar-item.css.d.ts +1 -1
  106. package/dist/src/nile-inline-sidebar-item/nile-inline-sidebar-item.css.js +15 -17
  107. package/dist/src/nile-inline-sidebar-item/nile-inline-sidebar-item.css.js.map +1 -1
  108. package/dist/src/nile-inline-sidebar-item/nile-inline-sidebar-item.d.ts +7 -1
  109. package/dist/src/nile-inline-sidebar-item/nile-inline-sidebar-item.js +63 -4
  110. package/dist/src/nile-inline-sidebar-item/nile-inline-sidebar-item.js.map +1 -1
  111. package/dist/src/nile-inline-sidebar-item-body/index.d.ts +1 -0
  112. package/dist/src/nile-inline-sidebar-item-body/index.js +2 -0
  113. package/dist/src/nile-inline-sidebar-item-body/index.js.map +1 -0
  114. package/dist/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.css.d.ts +9 -0
  115. package/dist/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.css.js +62 -0
  116. package/dist/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.css.js.map +1 -0
  117. package/dist/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.d.ts +45 -0
  118. package/dist/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.js +110 -0
  119. package/dist/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.js.map +1 -0
  120. package/dist/src/nile-inline-sidebar-item-header/index.d.ts +1 -0
  121. package/dist/src/nile-inline-sidebar-item-header/index.js +2 -0
  122. package/dist/src/nile-inline-sidebar-item-header/index.js.map +1 -0
  123. package/dist/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.css.d.ts +9 -0
  124. package/dist/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.css.js +36 -0
  125. package/dist/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.css.js.map +1 -0
  126. package/dist/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.d.ts +34 -0
  127. package/dist/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.js +68 -0
  128. package/dist/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.js.map +1 -0
  129. package/dist/src/nile-inline-sidebar-panel/index.d.ts +1 -0
  130. package/dist/src/nile-inline-sidebar-panel/index.js +2 -0
  131. package/dist/src/nile-inline-sidebar-panel/index.js.map +1 -0
  132. package/dist/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.css.d.ts +9 -0
  133. package/dist/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.css.js +28 -0
  134. package/dist/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.css.js.map +1 -0
  135. package/dist/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.d.ts +35 -0
  136. package/dist/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.js +55 -0
  137. package/dist/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.js.map +1 -0
  138. package/dist/src/nile-inline-sidebar-panel-group/index.d.ts +1 -0
  139. package/dist/src/nile-inline-sidebar-panel-group/index.js +2 -0
  140. package/dist/src/nile-inline-sidebar-panel-group/index.js.map +1 -0
  141. package/dist/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.css.d.ts +9 -0
  142. package/dist/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.css.js +39 -0
  143. package/dist/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.css.js.map +1 -0
  144. package/dist/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.d.ts +43 -0
  145. package/dist/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.js +93 -0
  146. package/dist/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.js.map +1 -0
  147. package/dist/src/nile-nav-tab/index.d.ts +1 -0
  148. package/dist/src/nile-nav-tab/index.js +2 -0
  149. package/dist/src/nile-nav-tab/index.js.map +1 -0
  150. package/dist/src/nile-nav-tab/nile-nav-tab.css.d.ts +9 -0
  151. package/dist/src/nile-nav-tab/nile-nav-tab.css.js +199 -0
  152. package/dist/src/nile-nav-tab/nile-nav-tab.css.js.map +1 -0
  153. package/dist/src/nile-nav-tab/nile-nav-tab.d.ts +50 -0
  154. package/dist/src/nile-nav-tab/nile-nav-tab.js +190 -0
  155. package/dist/src/nile-nav-tab/nile-nav-tab.js.map +1 -0
  156. package/dist/src/nile-nav-tab/nile-nav-tab.test.d.ts +1 -0
  157. package/dist/src/nile-nav-tab/nile-nav-tab.test.js +656 -0
  158. package/dist/src/nile-nav-tab/nile-nav-tab.test.js.map +1 -0
  159. package/dist/src/nile-nav-tab-group/index.d.ts +1 -0
  160. package/dist/src/nile-nav-tab-group/index.js +2 -0
  161. package/dist/src/nile-nav-tab-group/index.js.map +1 -0
  162. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.css.d.ts +12 -0
  163. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.css.js +680 -0
  164. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.css.js.map +1 -0
  165. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.d.ts +119 -0
  166. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.js +765 -0
  167. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.js.map +1 -0
  168. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.test.d.ts +3 -0
  169. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.test.js +838 -0
  170. package/dist/src/nile-nav-tab-group/nile-nav-tab-group.test.js.map +1 -0
  171. package/dist/src/nile-nav-tab-panel/index.d.ts +1 -0
  172. package/dist/src/nile-nav-tab-panel/index.js +2 -0
  173. package/dist/src/nile-nav-tab-panel/index.js.map +1 -0
  174. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.css.d.ts +15 -0
  175. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.css.js +37 -0
  176. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.css.js.map +1 -0
  177. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.d.ts +37 -0
  178. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.js +75 -0
  179. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.js.map +1 -0
  180. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.test.d.ts +1 -0
  181. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.test.js +534 -0
  182. package/dist/src/nile-nav-tab-panel/nile-nav-tab-panel.test.js.map +1 -0
  183. package/dist/src/version.js +1 -1
  184. package/dist/src/version.js.map +1 -1
  185. package/dist/tsconfig.tsbuildinfo +1 -1
  186. package/package.json +8 -3
  187. package/src/index.ts +7 -0
  188. package/src/internal/enum.ts +8 -1
  189. package/src/nile-inline-sidebar/nile-inline-sidebar.css.ts +75 -17
  190. package/src/nile-inline-sidebar/nile-inline-sidebar.ts +148 -18
  191. package/src/nile-inline-sidebar-group/nile-inline-sidebar-group.css.ts +7 -7
  192. package/src/nile-inline-sidebar-item/nile-inline-sidebar-item.css.ts +15 -17
  193. package/src/nile-inline-sidebar-item/nile-inline-sidebar-item.ts +74 -9
  194. package/src/nile-inline-sidebar-item-body/index.ts +1 -0
  195. package/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.css.ts +64 -0
  196. package/src/nile-inline-sidebar-item-body/nile-inline-sidebar-item-body.ts +110 -0
  197. package/src/nile-inline-sidebar-item-header/index.ts +1 -0
  198. package/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.css.ts +38 -0
  199. package/src/nile-inline-sidebar-item-header/nile-inline-sidebar-item-header.ts +69 -0
  200. package/src/nile-inline-sidebar-panel/index.ts +1 -0
  201. package/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.css.ts +30 -0
  202. package/src/nile-inline-sidebar-panel/nile-inline-sidebar-panel.ts +53 -0
  203. package/src/nile-inline-sidebar-panel-group/index.ts +1 -0
  204. package/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.css.ts +41 -0
  205. package/src/nile-inline-sidebar-panel-group/nile-inline-sidebar-panel-group.ts +101 -0
  206. package/src/nile-nav-tab/index.ts +1 -0
  207. package/src/nile-nav-tab/nile-nav-tab.css.ts +201 -0
  208. package/src/nile-nav-tab/nile-nav-tab.test.ts +768 -0
  209. package/src/nile-nav-tab/nile-nav-tab.ts +198 -0
  210. package/src/nile-nav-tab-group/index.ts +1 -0
  211. package/src/nile-nav-tab-group/nile-nav-tab-group.css.ts +682 -0
  212. package/src/nile-nav-tab-group/nile-nav-tab-group.test.ts +1009 -0
  213. package/src/nile-nav-tab-group/nile-nav-tab-group.ts +845 -0
  214. package/src/nile-nav-tab-panel/index.ts +1 -0
  215. package/src/nile-nav-tab-panel/nile-nav-tab-panel.css.ts +39 -0
  216. package/src/nile-nav-tab-panel/nile-nav-tab-panel.test.ts +797 -0
  217. package/src/nile-nav-tab-panel/nile-nav-tab-panel.ts +78 -0
  218. package/vscode-html-custom-data.json +272 -2
@@ -0,0 +1,838 @@
1
+ import { aTimeout, expect, fixture, html } from '@open-wc/testing';
2
+ import { ifDefined } from 'lit/directives/if-defined.js';
3
+ import './nile-nav-tab-group';
4
+ import '../nile-nav-tab/nile-nav-tab';
5
+ import '../nile-nav-tab-panel/nile-nav-tab-panel';
6
+ const makeGroup = async (opts = {}) => fixture(html `
7
+ <nile-nav-tab-group
8
+ placement=${ifDefined(opts.placement)}
9
+ variant=${ifDefined(opts.variant)}
10
+ value=${ifDefined(opts.value)}
11
+ ?no-track=${opts.noTrack === true}
12
+ ?fullWidth=${opts.fullWidth === true}
13
+ ?centered=${opts.centered === true}
14
+ ?showIndicatorOnHover=${opts.showIndicatorOnHover === true}
15
+ indicatorPlacement=${ifDefined(opts.indicatorPlacement)}
16
+ .width=${opts.width ?? ''}
17
+ >
18
+ <nile-nav-tab slot="nav" panel="general">General</nile-nav-tab>
19
+ <nile-nav-tab slot="nav" panel="custom">Custom</nile-nav-tab>
20
+ <nile-nav-tab slot="nav" panel="disabled" disabled>Disabled</nile-nav-tab>
21
+
22
+ <nile-nav-tab-panel name="general">General panel</nile-nav-tab-panel>
23
+ <nile-nav-tab-panel name="custom">Custom panel</nile-nav-tab-panel>
24
+ <nile-nav-tab-panel name="disabled">Disabled panel</nile-nav-tab-panel>
25
+ </nile-nav-tab-group>
26
+ `);
27
+ const getTabs = (el) => Array.from(el.querySelectorAll('nile-nav-tab'));
28
+ const getPanels = (el) => Array.from(el.querySelectorAll('nile-nav-tab-panel'));
29
+ describe('NileNavTabGroup', () => {
30
+ // ---- Rendering ----
31
+ it('renders with nav and body slots', async () => {
32
+ const el = await makeGroup();
33
+ expect(el).to.exist;
34
+ expect(el.shadowRoot).to.not.be.null;
35
+ expect(el.shadowRoot.querySelector('slot[name="nav"]')).to.exist;
36
+ expect(el.shadowRoot.querySelector('slot:not([name])')).to.exist;
37
+ });
38
+ it('renders base wrapper with default top placement class', async () => {
39
+ const el = await makeGroup();
40
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
41
+ expect(base).to.exist;
42
+ expect(base.classList.contains('nav-tab-group--top')).to.be.true;
43
+ });
44
+ it('applies placement bottom class', async () => {
45
+ const el = await makeGroup({ placement: 'bottom' });
46
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
47
+ expect(base.classList.contains('nav-tab-group--bottom')).to.be.true;
48
+ });
49
+ it('applies placement start class', async () => {
50
+ const el = await makeGroup({ placement: 'start' });
51
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
52
+ expect(base.classList.contains('nav-tab-group--start')).to.be.true;
53
+ });
54
+ it('applies placement end class', async () => {
55
+ const el = await makeGroup({ placement: 'end' });
56
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
57
+ expect(base.classList.contains('nav-tab-group--end')).to.be.true;
58
+ });
59
+ it('renders indicator by default (underline variant)', async () => {
60
+ const el = await makeGroup();
61
+ expect(el.shadowRoot.querySelector('.nav-tab-group__indicator')).to.exist;
62
+ });
63
+ it('renders pill and no indicator for filled variant', async () => {
64
+ const el = await makeGroup({ variant: 'filled' });
65
+ expect(el.shadowRoot.querySelector('.nav-tab-group__pill')).to.exist;
66
+ expect(el.shadowRoot.querySelector('.nav-tab-group__indicator')).to.be.null;
67
+ });
68
+ it('renders pill for neutral-filled variant', async () => {
69
+ const el = await makeGroup({ variant: 'neutral-filled' });
70
+ expect(el.shadowRoot.querySelector('.nav-tab-group__pill')).to.exist;
71
+ });
72
+ it('toggle variant renders toggle frame and pill not underline indicator', async () => {
73
+ const el = await makeGroup({ variant: 'toggle' });
74
+ expect(el.shadowRoot.querySelector('.nav-tab-group__toggle-frame')).to.exist;
75
+ expect(el.shadowRoot.querySelector('.nav-tab-group__pill')).to.exist;
76
+ expect(el.shadowRoot.querySelector('.nav-tab-group__indicator')).to.be.null;
77
+ });
78
+ it('toggle-button variant renders pill without underline indicator', async () => {
79
+ const el = await makeGroup({ variant: 'toggle-button' });
80
+ expect(el.shadowRoot.querySelector('.nav-tab-group__pill')).to.exist;
81
+ expect(el.shadowRoot.querySelector('.nav-tab-group__indicator')).to.be.null;
82
+ });
83
+ it('tab list has role tablist', async () => {
84
+ const el = await makeGroup();
85
+ const list = el.shadowRoot?.querySelector('.nav-tab-group__tabs');
86
+ expect(list?.getAttribute('role')).to.equal('tablist');
87
+ });
88
+ it('nav region exposes part nav on container', async () => {
89
+ const el = await makeGroup();
90
+ const nav = el.shadowRoot.querySelector('.nav-tab-group__nav-container');
91
+ expect(nav.getAttribute('part')).to.equal('nav');
92
+ });
93
+ it('body slot exposes part body', async () => {
94
+ const el = await makeGroup();
95
+ const body = el.shadowRoot.querySelector('.nav-tab-group__body');
96
+ expect(body.getAttribute('part')).to.equal('body');
97
+ });
98
+ it('no-track adds hide__track on base', async () => {
99
+ const el = await makeGroup({ noTrack: true });
100
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
101
+ expect(base.classList.contains('hide__track')).to.be.true;
102
+ });
103
+ it('fullWidth reflects to attribute and tabs stretch', async () => {
104
+ const el = await makeGroup({ fullWidth: true });
105
+ expect(el.hasAttribute('fullwidth')).to.be.true;
106
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
107
+ const tabs = base.querySelector('.nav-tab-group__tabs');
108
+ expect(tabs).to.exist;
109
+ });
110
+ it('showIndicatorOnHover adds hover indicator node for underline', async () => {
111
+ const el = await makeGroup({ showIndicatorOnHover: true });
112
+ expect(el.shadowRoot.querySelector('.nav-tab-group__hover-indicator')).to.exist;
113
+ });
114
+ it('indicatorPlacement left applies alongside placement start', async () => {
115
+ const el = await makeGroup({
116
+ placement: 'start',
117
+ indicatorPlacement: 'left',
118
+ value: 'general',
119
+ });
120
+ await aTimeout(0);
121
+ expect(el.indicatorPlacement).to.equal('left');
122
+ expect(el.placement).to.equal('start');
123
+ });
124
+ // ---- Defaults & reflection ----
125
+ it('has expected defaults', async () => {
126
+ const el = await makeGroup();
127
+ expect(el.placement).to.equal('top');
128
+ expect(el.activeTabProp).to.equal('');
129
+ expect(el.noTrack).to.be.false;
130
+ expect(el.noScrollControls).to.be.false;
131
+ expect(el.centered).to.be.false;
132
+ expect(el.fullWidth).to.be.false;
133
+ expect(el.variant).to.equal('underline');
134
+ });
135
+ it('reflects `value` attribute to activeTabProp', async () => {
136
+ const el = await makeGroup({ value: 'custom' });
137
+ await el.updateComplete;
138
+ expect(el.activeTabProp).to.equal('custom');
139
+ });
140
+ it('reflects centered attribute', async () => {
141
+ const el = await makeGroup({ centered: true });
142
+ expect(el.centered).to.be.true;
143
+ });
144
+ it('localName is nile-nav-tab-group', async () => {
145
+ const el = await makeGroup();
146
+ expect(el.localName).to.equal('nile-nav-tab-group');
147
+ });
148
+ it('shadow root is open', async () => {
149
+ const el = await makeGroup();
150
+ expect(el.shadowRoot.mode).to.equal('open');
151
+ });
152
+ it('exposes static styles and custom element registration', async () => {
153
+ const mod = await import('./nile-nav-tab-group');
154
+ expect(mod.NileNavTabGroup.styles).to.exist;
155
+ expect(customElements.get('nile-nav-tab-group')).to.exist;
156
+ });
157
+ it('default export matches named class', async () => {
158
+ const mod = await import('./nile-nav-tab-group');
159
+ expect(mod.default).to.equal(mod.NileNavTabGroup);
160
+ });
161
+ // ---- Selection behavior ----
162
+ it('selects tab/panel from value at startup', async () => {
163
+ const el = await makeGroup({ value: 'custom' });
164
+ await aTimeout(0);
165
+ await el.updateComplete;
166
+ const tabs = getTabs(el);
167
+ const panels = getPanels(el);
168
+ const customTab = tabs.find(t => t.getAttribute('panel') === 'custom');
169
+ const generalTab = tabs.find(t => t.getAttribute('panel') === 'general');
170
+ const customPanel = panels.find(p => p.getAttribute('name') === 'custom');
171
+ const generalPanel = panels.find(p => p.getAttribute('name') === 'general');
172
+ expect(customTab.hasAttribute('active')).to.be.true;
173
+ expect(generalTab.hasAttribute('active')).to.be.false;
174
+ expect(customPanel.hasAttribute('active')).to.be.true;
175
+ expect(generalPanel.hasAttribute('active')).to.be.false;
176
+ });
177
+ it('updates selected tab/panel when activeTabProp changes', async () => {
178
+ const el = await makeGroup({ value: 'general' });
179
+ el.activeTabProp = 'custom';
180
+ await aTimeout(0);
181
+ await el.updateComplete;
182
+ const tabs = getTabs(el);
183
+ const panels = getPanels(el);
184
+ expect(tabs.find(t => t.getAttribute('panel') === 'custom').hasAttribute('active')).to.be.true;
185
+ expect(panels.find(p => p.getAttribute('name') === 'custom').hasAttribute('active')).to.be.true;
186
+ });
187
+ it('clicking an enabled tab changes activeTabName', async () => {
188
+ const el = await makeGroup({ value: 'general' });
189
+ const customTab = getTabs(el).find(t => t.getAttribute('panel') === 'custom');
190
+ customTab.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
191
+ await aTimeout(0);
192
+ await el.updateComplete;
193
+ expect(el.activeTabName).to.equal('custom');
194
+ expect(document.activeElement).to.equal(customTab);
195
+ });
196
+ it('clicking a disabled tab does not change activeTabName', async () => {
197
+ const el = await makeGroup({ value: 'general' });
198
+ const disabledTab = getTabs(el).find(t => t.getAttribute('panel') === 'disabled');
199
+ disabledTab.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
200
+ await aTimeout(0);
201
+ await el.updateComplete;
202
+ expect(el.activeTabName).to.equal('general');
203
+ });
204
+ it('modifier click on tab does not change activeTabName (native link / group both ignore)', async () => {
205
+ const el = await makeGroup({ value: 'general' });
206
+ const customTab = getTabs(el).find(t => t.getAttribute('panel') === 'custom');
207
+ expect(customTab).to.exist;
208
+ customTab?.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true, ctrlKey: true, button: 0 }));
209
+ await aTimeout(0);
210
+ await el.updateComplete;
211
+ expect(el.activeTabName).to.equal('general');
212
+ });
213
+ it('emits nile-tab-change with details when selection changes', async () => {
214
+ const el = await makeGroup({ value: 'general' });
215
+ let detail;
216
+ el.addEventListener('nile-tab-change', (e) => {
217
+ detail = e.detail;
218
+ });
219
+ const customTab = getTabs(el).find(t => t.getAttribute('panel') === 'custom');
220
+ customTab.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
221
+ await aTimeout(0);
222
+ await el.updateComplete;
223
+ expect(detail).to.exist;
224
+ expect(detail.value).to.equal('custom');
225
+ expect(detail.previousValue).to.equal('general');
226
+ expect(detail.index).to.equal(1);
227
+ });
228
+ it('nile-tab-change detail includes link when selected tab has link', async () => {
229
+ const el = await fixture(html `
230
+ <nile-nav-tab-group value="b">
231
+ <nile-nav-tab slot="nav" panel="a" link="https://u.example/a">A</nile-nav-tab>
232
+ <nile-nav-tab slot="nav" panel="b">B</nile-nav-tab>
233
+ <nile-nav-tab-panel name="a"></nile-nav-tab-panel>
234
+ <nile-nav-tab-panel name="b"></nile-nav-tab-panel>
235
+ </nile-nav-tab-group>
236
+ `);
237
+ await aTimeout(0);
238
+ let detail;
239
+ el.addEventListener('nile-tab-change', (e) => {
240
+ detail = e.detail;
241
+ });
242
+ getTabs(el)
243
+ .find(t => t.getAttribute('panel') === 'a')
244
+ .dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
245
+ await aTimeout(0);
246
+ await el.updateComplete;
247
+ expect(detail.value).to.equal('a');
248
+ expect(detail.link).to.equal('https://u.example/a');
249
+ });
250
+ it('re-emits nile-close from child tab with panel detail', async () => {
251
+ const el = await makeGroup();
252
+ const generalTab = getTabs(el).find(t => t.getAttribute('panel') === 'general');
253
+ let closeDetail;
254
+ el.addEventListener('nile-close', (e) => {
255
+ closeDetail = e.detail;
256
+ });
257
+ generalTab.dispatchEvent(new CustomEvent('nile-close', { bubbles: true, composed: true }));
258
+ await el.updateComplete;
259
+ expect(closeDetail).to.deep.equal({ panel: 'general' });
260
+ });
261
+ it('centered distributes to slotted nav tabs', async () => {
262
+ const el = await makeGroup({ centered: true, value: 'general' });
263
+ await aTimeout(0);
264
+ const first = getTabs(el)[0];
265
+ expect(first?.centered).to.be.true;
266
+ });
267
+ // ---- Keyboard navigation ----
268
+ it('ArrowRight moves focus across enabled tabs', async () => {
269
+ const el = await makeGroup({ value: 'general' });
270
+ const tabs = getTabs(el);
271
+ const first = tabs.find(t => t.getAttribute('panel') === 'general');
272
+ const second = tabs.find(t => t.getAttribute('panel') === 'custom');
273
+ first.focus();
274
+ first.dispatchEvent(new KeyboardEvent('keydown', {
275
+ key: 'ArrowRight',
276
+ bubbles: true,
277
+ composed: true,
278
+ cancelable: true,
279
+ }));
280
+ await aTimeout(0);
281
+ expect(document.activeElement).to.equal(second);
282
+ });
283
+ it('ArrowLeft wraps from first enabled tab to last enabled', async () => {
284
+ const el = await makeGroup({ value: 'general' });
285
+ const tabs = getTabs(el);
286
+ const first = tabs.find(t => t.getAttribute('panel') === 'general');
287
+ const second = tabs.find(t => t.getAttribute('panel') === 'custom');
288
+ first.focus();
289
+ first.dispatchEvent(new KeyboardEvent('keydown', {
290
+ key: 'ArrowLeft',
291
+ bubbles: true,
292
+ composed: true,
293
+ cancelable: true,
294
+ }));
295
+ await aTimeout(0);
296
+ expect(document.activeElement).to.equal(second);
297
+ });
298
+ it('RTL horizontal: ArrowLeft moves focus like LTR ArrowRight', async () => {
299
+ const el = await makeGroup({ value: 'general' });
300
+ el.setAttribute('dir', 'rtl');
301
+ const tabs = getTabs(el);
302
+ const first = tabs.find(t => t.getAttribute('panel') === 'general');
303
+ const second = tabs.find(t => t.getAttribute('panel') === 'custom');
304
+ first.focus();
305
+ first.dispatchEvent(new KeyboardEvent('keydown', {
306
+ key: 'ArrowLeft',
307
+ bubbles: true,
308
+ composed: true,
309
+ cancelable: true,
310
+ }));
311
+ await aTimeout(0);
312
+ expect(document.activeElement).to.equal(second);
313
+ });
314
+ it('RTL horizontal: ArrowRight wraps from first like LTR ArrowLeft', async () => {
315
+ const el = await makeGroup({ value: 'general' });
316
+ el.setAttribute('dir', 'rtl');
317
+ const tabs = getTabs(el);
318
+ const first = tabs.find(t => t.getAttribute('panel') === 'general');
319
+ const second = tabs.find(t => t.getAttribute('panel') === 'custom');
320
+ first.focus();
321
+ first.dispatchEvent(new KeyboardEvent('keydown', {
322
+ key: 'ArrowRight',
323
+ bubbles: true,
324
+ composed: true,
325
+ cancelable: true,
326
+ }));
327
+ await aTimeout(0);
328
+ expect(document.activeElement).to.equal(second);
329
+ });
330
+ it('Home focuses first enabled tab', async () => {
331
+ const el = await makeGroup({ value: 'custom' });
332
+ const tabs = getTabs(el);
333
+ const custom = tabs.find(t => t.getAttribute('panel') === 'custom');
334
+ const general = tabs.find(t => t.getAttribute('panel') === 'general');
335
+ custom.focus();
336
+ custom.dispatchEvent(new KeyboardEvent('keydown', {
337
+ key: 'Home',
338
+ bubbles: true,
339
+ composed: true,
340
+ cancelable: true,
341
+ }));
342
+ await aTimeout(0);
343
+ expect(document.activeElement).to.equal(general);
344
+ });
345
+ it('End focuses last enabled tab', async () => {
346
+ const el = await makeGroup({ value: 'general' });
347
+ const tabs = getTabs(el);
348
+ const custom = tabs.find(t => t.getAttribute('panel') === 'custom');
349
+ const general = tabs.find(t => t.getAttribute('panel') === 'general');
350
+ general.focus();
351
+ general.dispatchEvent(new KeyboardEvent('keydown', {
352
+ key: 'End',
353
+ bubbles: true,
354
+ composed: true,
355
+ cancelable: true,
356
+ }));
357
+ await aTimeout(0);
358
+ expect(document.activeElement).to.equal(custom);
359
+ });
360
+ it('Enter selects the focused tab', async () => {
361
+ const el = await makeGroup({ value: 'general' });
362
+ const customTab = getTabs(el).find(t => t.getAttribute('panel') === 'custom');
363
+ customTab.focus();
364
+ customTab.dispatchEvent(new KeyboardEvent('keydown', {
365
+ key: 'Enter',
366
+ bubbles: true,
367
+ composed: true,
368
+ cancelable: true,
369
+ }));
370
+ await aTimeout(0);
371
+ await el.updateComplete;
372
+ expect(el.activeTabName).to.equal('custom');
373
+ });
374
+ it('Space selects the focused tab', async () => {
375
+ const el = await makeGroup({ value: 'general' });
376
+ const customTab = getTabs(el).find(t => t.getAttribute('panel') === 'custom');
377
+ customTab.focus();
378
+ customTab.dispatchEvent(new KeyboardEvent('keydown', {
379
+ key: ' ',
380
+ bubbles: true,
381
+ composed: true,
382
+ cancelable: true,
383
+ }));
384
+ await aTimeout(0);
385
+ await el.updateComplete;
386
+ expect(el.activeTabName).to.equal('custom');
387
+ });
388
+ it('ArrowDown moves roving focus when placement is start', async () => {
389
+ const el = await makeGroup({ placement: 'start', value: 'general' });
390
+ const tabs = getTabs(el);
391
+ const general = tabs.find(t => t.getAttribute('panel') === 'general');
392
+ const custom = tabs.find(t => t.getAttribute('panel') === 'custom');
393
+ general.focus();
394
+ general.dispatchEvent(new KeyboardEvent('keydown', {
395
+ key: 'ArrowDown',
396
+ bubbles: true,
397
+ composed: true,
398
+ cancelable: true,
399
+ }));
400
+ await aTimeout(0);
401
+ expect(document.activeElement).to.equal(custom);
402
+ });
403
+ it('ArrowUp moves roving focus when placement is start', async () => {
404
+ const el = await makeGroup({ placement: 'start', value: 'custom' });
405
+ const tabs = getTabs(el);
406
+ const general = tabs.find(t => t.getAttribute('panel') === 'general');
407
+ const custom = tabs.find(t => t.getAttribute('panel') === 'custom');
408
+ custom.focus();
409
+ custom.dispatchEvent(new KeyboardEvent('keydown', {
410
+ key: 'ArrowUp',
411
+ bubbles: true,
412
+ composed: true,
413
+ cancelable: true,
414
+ }));
415
+ await aTimeout(0);
416
+ expect(document.activeElement).to.equal(general);
417
+ });
418
+ it('keydown on disabled tab calls preventDefault', async () => {
419
+ const el = await makeGroup({ value: 'general' });
420
+ const disabled = getTabs(el).find(t => t.getAttribute('panel') === 'disabled');
421
+ disabled.focus();
422
+ const ev = new KeyboardEvent('keydown', {
423
+ key: 'Enter',
424
+ bubbles: true,
425
+ composed: true,
426
+ cancelable: true,
427
+ });
428
+ disabled.dispatchEvent(ev);
429
+ expect(ev.defaultPrevented).to.be.true;
430
+ });
431
+ // ---- A11y sync ----
432
+ it('sets aria-posinset and aria-setsize on enabled tabs only', async () => {
433
+ const el = await makeGroup();
434
+ await aTimeout(0);
435
+ const tabs = getTabs(el);
436
+ expect(tabs[0].getAttribute('aria-posinset')).to.equal('1');
437
+ expect(tabs[1].getAttribute('aria-posinset')).to.equal('2');
438
+ expect(tabs[2].hasAttribute('aria-posinset')).to.be.false;
439
+ expect(tabs[0].getAttribute('aria-setsize')).to.equal('2');
440
+ expect(tabs[1].getAttribute('aria-setsize')).to.equal('2');
441
+ expect(tabs[2].hasAttribute('aria-setsize')).to.be.false;
442
+ expect(tabs[2].getAttribute('aria-hidden')).to.equal('true');
443
+ });
444
+ it('wires aria-controls and aria-labelledby between tab and panel', async () => {
445
+ const el = await makeGroup();
446
+ await el.updateComplete;
447
+ await Promise.all(getTabs(el).map(tab => tab.updateComplete));
448
+ await Promise.all(getPanels(el).map(panel => panel.updateComplete));
449
+ const tab = getTabs(el).find(t => t.getAttribute('panel') === 'general');
450
+ const panel = getPanels(el).find(p => p.getAttribute('name') === 'general');
451
+ expect(tab.getAttribute('aria-controls')).to.equal(panel.id);
452
+ expect(panel.getAttribute('aria-labelledby')).to.equal(tab.id);
453
+ });
454
+ // ---- Scroll controls ----
455
+ it('setScrollControls sets hasScrollControls for horizontal overflow', async () => {
456
+ const el = await makeGroup();
457
+ const nav = el.shadowRoot.querySelector('.nav-tab-group__nav');
458
+ Object.defineProperty(nav, 'scrollWidth', { configurable: true, value: 500 });
459
+ Object.defineProperty(nav, 'clientWidth', { configurable: true, value: 100 });
460
+ el.setScrollControls();
461
+ expect(el.hasScrollControls).to.be.true;
462
+ el.noScrollControls = true;
463
+ el.setScrollControls();
464
+ expect(el.hasScrollControls).to.be.false;
465
+ });
466
+ it('hasScrollControls stays false for vertical placement even when overflow math holds', async () => {
467
+ const el = await makeGroup({ placement: 'start' });
468
+ const nav = el.shadowRoot.querySelector('.nav-tab-group__nav');
469
+ Object.defineProperty(nav, 'scrollWidth', { configurable: true, value: 500 });
470
+ Object.defineProperty(nav, 'clientWidth', { configurable: true, value: 100 });
471
+ el.setScrollControls();
472
+ expect(el.hasScrollControls).to.be.false;
473
+ });
474
+ it('renders scroll buttons when hasScrollControls becomes true', async () => {
475
+ const el = await makeGroup();
476
+ el.hasScrollControls = true;
477
+ await el.updateComplete;
478
+ const buttons = el.shadowRoot.querySelectorAll('nile-icon-button.nav-tab-group__scroll-button');
479
+ expect(buttons.length).to.equal(2);
480
+ });
481
+ // ---- Lifecycle ----
482
+ it('disconnecting the group does not throw', async () => {
483
+ const el = await makeGroup();
484
+ expect(() => el.remove()).to.not.throw();
485
+ });
486
+ it('updateComplete resolves', async () => {
487
+ const el = await makeGroup();
488
+ expect(await el.updateComplete).to.be.true;
489
+ });
490
+ it('width property applies inline style token on base', async () => {
491
+ const el = await makeGroup({ width: '120px' });
492
+ await el.updateComplete;
493
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
494
+ expect(base.style.getPropertyValue('--nav-tab-item-width').trim()).to.equal('120px');
495
+ });
496
+ // ---- Extended coverage ----
497
+ it('noScrollControls property default false', async () => {
498
+ const el = await makeGroup();
499
+ expect(el.noScrollControls).to.be.false;
500
+ });
501
+ it('noScrollControls can be set true', async () => {
502
+ const el = await makeGroup();
503
+ el.noScrollControls = true;
504
+ await el.updateComplete;
505
+ expect(el.noScrollControls).to.be.true;
506
+ });
507
+ it('activeTabName matches value after programmatic value set', async () => {
508
+ const el = await makeGroup({ value: 'general' });
509
+ await aTimeout(0);
510
+ el.activeTabProp = 'custom';
511
+ await el.updateComplete;
512
+ await aTimeout(0);
513
+ expect(el.activeTabName).to.equal('custom');
514
+ });
515
+ it('clicking already selected tab keeps activeTabName', async () => {
516
+ const el = await makeGroup({ value: 'custom' });
517
+ await aTimeout(0);
518
+ const tab = getTabs(el).find(t => t.getAttribute('panel') === 'custom');
519
+ tab.dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
520
+ await el.updateComplete;
521
+ expect(el.activeTabName).to.equal('custom');
522
+ });
523
+ it('nile-tab-change includes previousIndex when moving from first', async () => {
524
+ const el = await makeGroup({ value: 'general' });
525
+ await aTimeout(0);
526
+ let detail;
527
+ el.addEventListener('nile-tab-change', (e) => {
528
+ detail = e.detail;
529
+ });
530
+ getTabs(el)
531
+ .find(t => t.getAttribute('panel') === 'custom')
532
+ .dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
533
+ await el.updateComplete;
534
+ expect(detail.previousIndex).to.equal(0);
535
+ expect(detail.index).to.equal(1);
536
+ });
537
+ it('setAttribute value updates selection after tick', async () => {
538
+ const el = await makeGroup({ value: 'general' });
539
+ await aTimeout(0);
540
+ el.setAttribute('value', 'custom');
541
+ await aTimeout(0);
542
+ await el.updateComplete;
543
+ expect(getTabs(el).find(t => t.getAttribute('panel') === 'custom').active).to.be.true;
544
+ });
545
+ it('ArrowRight from custom wraps to general', async () => {
546
+ const el = await makeGroup({ value: 'custom' });
547
+ await aTimeout(0);
548
+ const tabs = getTabs(el);
549
+ const custom = tabs.find(t => t.getAttribute('panel') === 'custom');
550
+ const general = tabs.find(t => t.getAttribute('panel') === 'general');
551
+ custom.focus();
552
+ custom.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true, composed: true, cancelable: true }));
553
+ await aTimeout(0);
554
+ expect(document.activeElement).to.equal(general);
555
+ });
556
+ it('re-emits nile-close for custom panel id', async () => {
557
+ const el = await makeGroup();
558
+ let d;
559
+ el.addEventListener('nile-close', (e) => {
560
+ d = e.detail;
561
+ });
562
+ getTabs(el)
563
+ .find(t => t.getAttribute('panel') === 'custom')
564
+ .dispatchEvent(new CustomEvent('nile-close', { bubbles: true, composed: true }));
565
+ await el.updateComplete;
566
+ expect(d).to.deep.equal({ panel: 'custom' });
567
+ });
568
+ it('indicator part exists for underline variant', async () => {
569
+ const el = await makeGroup();
570
+ expect(el.shadowRoot.querySelector('[part~="active-tab-indicator"]')).to.exist;
571
+ });
572
+ it('pill part exists for filled variant', async () => {
573
+ const el = await makeGroup({ variant: 'filled' });
574
+ expect(el.shadowRoot.querySelector('[part~="active-tab-pill"]')).to.exist;
575
+ });
576
+ it('body part remains when no panels rendered in shadow alone', async () => {
577
+ const el = await makeGroup();
578
+ expect(el.shadowRoot.querySelector('[part="body"]')).to.exist;
579
+ });
580
+ it('base part on wrapper exists', async () => {
581
+ const el = await makeGroup();
582
+ expect(el.shadowRoot.querySelector('[part="base"]')).to.exist;
583
+ });
584
+ it('tabs part exists on list', async () => {
585
+ const el = await makeGroup();
586
+ expect(el.shadowRoot.querySelector('[part="tabs"]')).to.exist;
587
+ });
588
+ it('centered false does not set centered on first tab', async () => {
589
+ const el = await makeGroup({ centered: false, value: 'general' });
590
+ await aTimeout(0);
591
+ expect(getTabs(el)[0].centered).to.be.false;
592
+ });
593
+ it('hasScrollControls reflects to attribute', async () => {
594
+ const el = await makeGroup();
595
+ el.hasScrollControls = true;
596
+ await el.updateComplete;
597
+ expect(el.hasAttribute('hasscrollcontrols')).to.be.true;
598
+ });
599
+ it('variant underline is default string', async () => {
600
+ const el = await makeGroup();
601
+ expect(el.variant).to.equal('underline');
602
+ });
603
+ it('variant neutral-filled string', async () => {
604
+ const el = await makeGroup({ variant: 'neutral-filled' });
605
+ expect(el.variant).to.equal('neutral-filled');
606
+ });
607
+ it('keydown Tab key does not change selection', async () => {
608
+ const el = await makeGroup({ value: 'general' });
609
+ await aTimeout(0);
610
+ getTabs(el)[0].focus();
611
+ getTabs(el)[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true, composed: true, cancelable: true }));
612
+ await el.updateComplete;
613
+ expect(el.activeTabName).to.equal('general');
614
+ });
615
+ it('keydown unrelated key a does not change selection', async () => {
616
+ const el = await makeGroup({ value: 'general' });
617
+ await aTimeout(0);
618
+ getTabs(el)[0].focus();
619
+ getTabs(el)[0].dispatchEvent(new KeyboardEvent('keydown', { key: 'a', bubbles: true, composed: true, cancelable: true }));
620
+ await el.updateComplete;
621
+ expect(el.activeTabName).to.equal('general');
622
+ });
623
+ it('placement bottom still has tablist role', async () => {
624
+ const el = await makeGroup({ placement: 'bottom' });
625
+ expect(el.shadowRoot?.querySelector('.nav-tab-group__tabs')?.getAttribute('role')).to.equal('tablist');
626
+ });
627
+ it('ArrowLeft from second tab moves to first', async () => {
628
+ const el = await makeGroup({ value: 'custom' });
629
+ await aTimeout(0);
630
+ const tabs = getTabs(el);
631
+ const custom = tabs.find(t => t.getAttribute('panel') === 'custom');
632
+ const general = tabs.find(t => t.getAttribute('panel') === 'general');
633
+ custom.focus();
634
+ custom.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true, composed: true, cancelable: true }));
635
+ await aTimeout(0);
636
+ expect(document.activeElement).to.equal(general);
637
+ });
638
+ it('End from first tab focuses last enabled tab', async () => {
639
+ const el = await makeGroup({ value: 'general' });
640
+ await aTimeout(0);
641
+ const general = getTabs(el).find(t => t.getAttribute('panel') === 'general');
642
+ const custom = getTabs(el).find(t => t.getAttribute('panel') === 'custom');
643
+ general.focus();
644
+ general.dispatchEvent(new KeyboardEvent('keydown', { key: 'End', bubbles: true, composed: true, cancelable: true }));
645
+ await aTimeout(0);
646
+ expect(document.activeElement).to.equal(custom);
647
+ });
648
+ it('fullWidth false by default', async () => {
649
+ const el = await makeGroup();
650
+ expect(el.fullWidth).to.be.false;
651
+ });
652
+ it('noTrack false by default', async () => {
653
+ const el = await makeGroup();
654
+ expect(el.noTrack).to.be.false;
655
+ });
656
+ it('showIndicatorOnHover false by default', async () => {
657
+ const el = await makeGroup();
658
+ expect(el.showIndicatorOnHover).to.be.false;
659
+ });
660
+ it('width defaults empty string', async () => {
661
+ const el = await makeGroup();
662
+ expect(el.width).to.equal('');
663
+ });
664
+ it('indicatorPlacement defaults empty', async () => {
665
+ const el = await makeGroup();
666
+ expect(el.indicatorPlacement).to.equal('');
667
+ });
668
+ it('getTabs returns three slotted nav tabs', async () => {
669
+ const el = await makeGroup();
670
+ await aTimeout(0);
671
+ expect(getTabs(el).length).to.equal(3);
672
+ });
673
+ it('getPanels returns three panels', async () => {
674
+ const el = await makeGroup();
675
+ await aTimeout(0);
676
+ expect(getPanels(el).length).to.equal(3);
677
+ });
678
+ it('removing value attribute clears value attr on host', async () => {
679
+ const el = await makeGroup({ value: 'general' });
680
+ await aTimeout(0);
681
+ el.removeAttribute('value');
682
+ await el.updateComplete;
683
+ await aTimeout(0);
684
+ expect(el.hasAttribute('value')).to.be.false;
685
+ });
686
+ it('tagName lowercases correctly', async () => {
687
+ const el = await makeGroup();
688
+ expect(el.tagName.toLowerCase()).to.equal('nile-nav-tab-group');
689
+ });
690
+ it('scroll buttons have label attributes', async () => {
691
+ const el = await makeGroup();
692
+ el.hasScrollControls = true;
693
+ await el.updateComplete;
694
+ const btns = el.shadowRoot.querySelectorAll('nile-icon-button.nav-tab-group__scroll-button');
695
+ expect(btns.length).to.equal(2);
696
+ expect(btns[0]?.getAttribute('label')).to.exist;
697
+ expect(btns[1]?.getAttribute('label')).to.exist;
698
+ });
699
+ it('toggle variant still exposes tablist', async () => {
700
+ const el = await makeGroup({ variant: 'toggle' });
701
+ expect(el.shadowRoot.querySelector('[role="tablist"]')).to.exist;
702
+ });
703
+ it('Enter after focus general keeps general selected', async () => {
704
+ const el = await makeGroup({ value: 'general' });
705
+ await aTimeout(0);
706
+ const g = getTabs(el).find(t => t.getAttribute('panel') === 'general');
707
+ g.focus();
708
+ g.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, composed: true, cancelable: true }));
709
+ await el.updateComplete;
710
+ expect(el.activeTabName).to.equal('general');
711
+ });
712
+ it('Space on general keeps general', async () => {
713
+ const el = await makeGroup({ value: 'general' });
714
+ await aTimeout(0);
715
+ const g = getTabs(el).find(t => t.getAttribute('panel') === 'general');
716
+ g.focus();
717
+ g.dispatchEvent(new KeyboardEvent('keydown', { key: ' ', bubbles: true, composed: true, cancelable: true }));
718
+ await el.updateComplete;
719
+ expect(el.activeTabName).to.equal('general');
720
+ });
721
+ it('fullWidth and centered can both be true', async () => {
722
+ const el = await makeGroup({ fullWidth: true, centered: true, value: 'general' });
723
+ await aTimeout(0);
724
+ expect(el.fullWidth).to.be.true;
725
+ expect(el.centered).to.be.true;
726
+ expect(getTabs(el)[0].centered).to.be.true;
727
+ });
728
+ it('emits a single nile-tab-change for one user click', async () => {
729
+ const el = await makeGroup({ value: 'general' });
730
+ await aTimeout(0);
731
+ let n = 0;
732
+ el.addEventListener('nile-tab-change', () => n++);
733
+ getTabs(el)
734
+ .find(t => t.getAttribute('panel') === 'custom')
735
+ .dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
736
+ await el.updateComplete;
737
+ expect(n).to.equal(1);
738
+ });
739
+ it('createElement upgrades nile-nav-tab-group', async () => {
740
+ const el = document.createElement('nile-nav-tab-group');
741
+ document.body.appendChild(el);
742
+ await el.updateComplete;
743
+ expect(el.shadowRoot).to.not.be.null;
744
+ el.remove();
745
+ });
746
+ it('nav container has nav-container class', async () => {
747
+ const el = await makeGroup();
748
+ expect(el.shadowRoot.querySelector('.nav-tab-group__nav-container')).to.exist;
749
+ });
750
+ it('underline variant exposes indicator path part', async () => {
751
+ const el = await makeGroup();
752
+ expect(el.shadowRoot.querySelector('[part~="active-tab-indicator-path"]')).to.exist;
753
+ });
754
+ /**
755
+ * 100 generated cases — `yarn tsc` emits dist/src/nile-nav-tab-group/nile-nav-tab-group.test.js.
756
+ */
757
+ describe('bulk generated coverage (100 cases)', () => {
758
+ for (let i = 0; i < 100; i++) {
759
+ it(`bulk case ${i + 1}/100 (mode ${i % 10})`, async () => {
760
+ const mode = i % 10;
761
+ if (mode === 0) {
762
+ const placements = ['top', 'bottom', 'start', 'end'];
763
+ const p = placements[i % 4];
764
+ const el = await makeGroup({ placement: p, value: 'general' });
765
+ await aTimeout(0);
766
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
767
+ expect(base.classList.contains(`nav-tab-group--${p}`)).to.be.true;
768
+ }
769
+ else if (mode === 1) {
770
+ const variants = [
771
+ 'underline',
772
+ 'filled',
773
+ 'toggle',
774
+ 'neutral-filled',
775
+ 'toggle-button',
776
+ ];
777
+ const v = variants[i % 5];
778
+ const el = await makeGroup({ variant: v });
779
+ await aTimeout(0);
780
+ if (v === 'underline') {
781
+ expect(el.shadowRoot.querySelector('.nav-tab-group__indicator')).to.exist;
782
+ }
783
+ else {
784
+ expect(el.shadowRoot.querySelector('.nav-tab-group__pill')).to.exist;
785
+ }
786
+ }
787
+ else if (mode === 2) {
788
+ const el = await makeGroup({ value: 'custom' });
789
+ await aTimeout(0);
790
+ expect(getTabs(el).find(t => t.getAttribute('panel') === 'custom').active).to.be.true;
791
+ }
792
+ else if (mode === 3) {
793
+ const el = await makeGroup({ value: 'general' });
794
+ await aTimeout(0);
795
+ getTabs(el)
796
+ .find(t => t.getAttribute('panel') === 'custom')
797
+ .dispatchEvent(new MouseEvent('click', { bubbles: true, composed: true }));
798
+ await el.updateComplete;
799
+ expect(el.activeTabName).to.equal('custom');
800
+ }
801
+ else if (mode === 4) {
802
+ const el = await makeGroup({ centered: true, value: 'general' });
803
+ await aTimeout(0);
804
+ expect(getTabs(el).every(t => t.centered)).to.be.true;
805
+ }
806
+ else if (mode === 5) {
807
+ const el = await makeGroup({ noTrack: true });
808
+ await aTimeout(0);
809
+ expect(el.shadowRoot.querySelector('.nav-tab-group').classList.contains('hide__track')).to.be.true;
810
+ }
811
+ else if (mode === 6) {
812
+ const el = await makeGroup({ fullWidth: true });
813
+ await aTimeout(0);
814
+ expect(el.fullWidth).to.be.true;
815
+ }
816
+ else if (mode === 7) {
817
+ const el = await makeGroup();
818
+ await aTimeout(0);
819
+ expect(el.shadowRoot.querySelector('[role="tablist"]')).to.exist;
820
+ }
821
+ else if (mode === 8) {
822
+ const el = await makeGroup();
823
+ await aTimeout(0);
824
+ expect(getTabs(el).length).to.equal(3);
825
+ expect(getPanels(el).length).to.equal(3);
826
+ }
827
+ else {
828
+ const w = `${40 + (i % 20)}px`;
829
+ const el = await makeGroup({ width: w, value: 'general' });
830
+ await aTimeout(0);
831
+ const base = el.shadowRoot.querySelector('.nav-tab-group');
832
+ expect(base.style.getPropertyValue('--nav-tab-item-width').trim()).to.equal(w);
833
+ }
834
+ });
835
+ }
836
+ });
837
+ });
838
+ //# sourceMappingURL=nile-nav-tab-group.test.js.map