@graupl/core 1.0.0-beta.22 → 1.0.0-beta.24

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 (273) hide show
  1. package/dist/css/base/button.css +2 -2
  2. package/dist/css/base/button.css.map +1 -1
  3. package/dist/css/base/form.css +2 -2
  4. package/dist/css/base/form.css.map +1 -1
  5. package/dist/css/base/link.css +2 -2
  6. package/dist/css/base/link.css.map +1 -1
  7. package/dist/css/base/table.css +2 -2
  8. package/dist/css/base/table.css.map +1 -1
  9. package/dist/css/base.css +2 -2
  10. package/dist/css/base.css.map +1 -1
  11. package/dist/css/component/accordion.css +2 -5
  12. package/dist/css/component/accordion.css.map +1 -1
  13. package/dist/css/component/alert.css +2 -2
  14. package/dist/css/component/alert.css.map +1 -1
  15. package/dist/css/component/badge.css +2 -2
  16. package/dist/css/component/badge.css.map +1 -1
  17. package/dist/css/component/card.css +2 -2
  18. package/dist/css/component/card.css.map +1 -1
  19. package/dist/css/component/carousel.css +2 -2
  20. package/dist/css/component/carousel.css.map +1 -1
  21. package/dist/css/component/disclosure.css +2 -2
  22. package/dist/css/component/disclosure.css.map +1 -1
  23. package/dist/css/component/input-group.css +2 -2
  24. package/dist/css/component/input-group.css.map +1 -1
  25. package/dist/css/component/list.css +2 -2
  26. package/dist/css/component/list.css.map +1 -1
  27. package/dist/css/component/menu.css +2 -2
  28. package/dist/css/component/menu.css.map +1 -1
  29. package/dist/css/component/navigation.css +2 -2
  30. package/dist/css/component/navigation.css.map +1 -1
  31. package/dist/css/component.css +2 -5
  32. package/dist/css/component.css.map +1 -1
  33. package/dist/css/graupl.css +2 -5
  34. package/dist/css/graupl.css.map +1 -1
  35. package/dist/css/init.css +2 -2
  36. package/dist/css/init.css.map +1 -1
  37. package/dist/css/layout/columns.css +2 -2
  38. package/dist/css/layout/columns.css.map +1 -1
  39. package/dist/css/layout/container.css +2 -2
  40. package/dist/css/layout/container.css.map +1 -1
  41. package/dist/css/layout/flex-columns.css +2 -2
  42. package/dist/css/layout/flex-columns.css.map +1 -1
  43. package/dist/css/layout.css +2 -5
  44. package/dist/css/layout.css.map +1 -1
  45. package/dist/css/normalize.css +2 -2
  46. package/dist/css/normalize.css.map +1 -1
  47. package/dist/css/state/focus.css +2 -2
  48. package/dist/css/state/focus.css.map +1 -1
  49. package/dist/css/state.css +2 -2
  50. package/dist/css/state.css.map +1 -1
  51. package/dist/css/theme/color.css +2 -2
  52. package/dist/css/theme/color.css.map +1 -1
  53. package/dist/css/theme/typography.css +2 -2
  54. package/dist/css/theme/typography.css.map +1 -1
  55. package/dist/css/theme.css +2 -2
  56. package/dist/css/theme.css.map +1 -1
  57. package/dist/css/utilities/alignment.css +1 -1
  58. package/dist/css/utilities/alignment.css.map +1 -1
  59. package/dist/css/utilities/background.css +2 -2
  60. package/dist/css/utilities/background.css.map +1 -1
  61. package/dist/css/utilities/border.css +2 -2
  62. package/dist/css/utilities/border.css.map +1 -1
  63. package/dist/css/utilities/color.css +2 -2
  64. package/dist/css/utilities/color.css.map +1 -1
  65. package/dist/css/utilities/container.css +1 -1
  66. package/dist/css/utilities/container.css.map +1 -1
  67. package/dist/css/utilities/display.css +2 -2
  68. package/dist/css/utilities/display.css.map +1 -1
  69. package/dist/css/utilities/flex.css +2 -2
  70. package/dist/css/utilities/flex.css.map +1 -1
  71. package/dist/css/utilities/gradient.css +2 -2
  72. package/dist/css/utilities/gradient.css.map +1 -1
  73. package/dist/css/utilities/height.css +2 -2
  74. package/dist/css/utilities/height.css.map +1 -1
  75. package/dist/css/utilities/inset.css +2 -2
  76. package/dist/css/utilities/inset.css.map +1 -1
  77. package/dist/css/utilities/justification.css +1 -1
  78. package/dist/css/utilities/justification.css.map +1 -1
  79. package/dist/css/utilities/list.css +1 -1
  80. package/dist/css/utilities/list.css.map +1 -1
  81. package/dist/css/utilities/order.css +2 -2
  82. package/dist/css/utilities/order.css.map +1 -1
  83. package/dist/css/utilities/position.css +2 -2
  84. package/dist/css/utilities/position.css.map +1 -1
  85. package/dist/css/utilities/ratio.css +2 -2
  86. package/dist/css/utilities/ratio.css.map +1 -1
  87. package/dist/css/utilities/spacing.css +2 -2
  88. package/dist/css/utilities/spacing.css.map +1 -1
  89. package/dist/css/utilities/typography.css +2 -2
  90. package/dist/css/utilities/typography.css.map +1 -1
  91. package/dist/css/utilities/visibility.css +2 -2
  92. package/dist/css/utilities/visibility.css.map +1 -1
  93. package/dist/css/utilities/visually-hidden.css +2 -2
  94. package/dist/css/utilities/visually-hidden.css.map +1 -1
  95. package/dist/css/utilities/width.css +2 -2
  96. package/dist/css/utilities/width.css.map +1 -1
  97. package/dist/css/utilities/z-index.css +1 -1
  98. package/dist/css/utilities/z-index.css.map +1 -1
  99. package/dist/css/utilities.css +2 -2
  100. package/dist/css/utilities.css.map +1 -1
  101. package/dist/js/accordion.js.map +1 -1
  102. package/dist/js/alert.js.map +1 -1
  103. package/dist/js/carousel.js.map +1 -1
  104. package/dist/js/component/accordion.cjs.js.map +1 -1
  105. package/dist/js/component/accordion.es.js.map +1 -1
  106. package/dist/js/component/accordion.iife.js.map +1 -1
  107. package/dist/js/component/alert.cjs.js.map +1 -1
  108. package/dist/js/component/alert.es.js.map +1 -1
  109. package/dist/js/component/alert.iife.js.map +1 -1
  110. package/dist/js/component/carousel.cjs.js.map +1 -1
  111. package/dist/js/component/carousel.es.js.map +1 -1
  112. package/dist/js/component/carousel.iife.js.map +1 -1
  113. package/dist/js/component/disclosure.cjs.js +2 -2
  114. package/dist/js/component/disclosure.cjs.js.map +1 -1
  115. package/dist/js/component/disclosure.es.js +2 -2
  116. package/dist/js/component/disclosure.es.js.map +1 -1
  117. package/dist/js/component/disclosure.iife.js +2 -2
  118. package/dist/js/component/disclosure.iife.js.map +1 -1
  119. package/dist/js/component/tabs.cjs.js +5 -0
  120. package/dist/js/component/tabs.cjs.js.map +1 -0
  121. package/dist/js/component/tabs.es.js +5 -0
  122. package/dist/js/component/tabs.es.js.map +1 -0
  123. package/dist/js/component/tabs.iife.js +5 -0
  124. package/dist/js/component/tabs.iife.js.map +1 -0
  125. package/dist/js/disclosure.js +2 -2
  126. package/dist/js/disclosure.js.map +1 -1
  127. package/dist/js/generator/accordion.cjs.js.map +1 -1
  128. package/dist/js/generator/accordion.es.js.map +1 -1
  129. package/dist/js/generator/accordion.iife.js.map +1 -1
  130. package/dist/js/generator/alert.cjs.js.map +1 -1
  131. package/dist/js/generator/alert.es.js.map +1 -1
  132. package/dist/js/generator/alert.iife.js.map +1 -1
  133. package/dist/js/generator/carousel.cjs.js.map +1 -1
  134. package/dist/js/generator/carousel.es.js.map +1 -1
  135. package/dist/js/generator/carousel.iife.js.map +1 -1
  136. package/dist/js/generator/disclosure.cjs.js +2 -2
  137. package/dist/js/generator/disclosure.cjs.js.map +1 -1
  138. package/dist/js/generator/disclosure.es.js +2 -2
  139. package/dist/js/generator/disclosure.es.js.map +1 -1
  140. package/dist/js/generator/disclosure.iife.js +2 -2
  141. package/dist/js/generator/disclosure.iife.js.map +1 -1
  142. package/dist/js/generator/navigation.cjs.js.map +1 -1
  143. package/dist/js/generator/navigation.es.js.map +1 -1
  144. package/dist/js/generator/navigation.iife.js.map +1 -1
  145. package/dist/js/generator/tabs.cjs.js +5 -0
  146. package/dist/js/generator/tabs.cjs.js.map +1 -0
  147. package/dist/js/generator/tabs.es.js +5 -0
  148. package/dist/js/generator/tabs.es.js.map +1 -0
  149. package/dist/js/generator/tabs.iife.js +5 -0
  150. package/dist/js/generator/tabs.iife.js.map +1 -0
  151. package/dist/js/graupl.js +5 -5
  152. package/dist/js/graupl.js.map +1 -1
  153. package/dist/js/navigation.js.map +1 -1
  154. package/dist/js/tabs.js +5 -0
  155. package/dist/js/tabs.js.map +1 -0
  156. package/package.json +4 -3
  157. package/src/js/disclosure/Disclosure.js +25 -45
  158. package/src/js/domHelpers.js +39 -22
  159. package/src/js/tabs/TabToggle.js +378 -0
  160. package/src/js/tabs/Tabs.js +1091 -0
  161. package/src/js/tabs/generator.js +32 -0
  162. package/src/js/tabs/index.js +5 -0
  163. package/src/scss/_defaults.scss +21 -88
  164. package/src/scss/_variables.scss +70 -0
  165. package/src/scss/base/button/_defaults.scss +2 -24
  166. package/src/scss/base/button/_index.scss +53 -52
  167. package/src/scss/base/button/_mixins.scss +24 -58
  168. package/src/scss/base/button/_variables.scss +139 -0
  169. package/src/scss/base/form/_defaults.scss +72 -2
  170. package/src/scss/base/form/_index.scss +196 -70
  171. package/src/scss/base/form/_variables.scss +166 -0
  172. package/src/scss/base/link/_defaults.scss +31 -0
  173. package/src/scss/base/link/_index.scss +177 -172
  174. package/src/scss/base/link/_variables.scss +215 -0
  175. package/src/scss/base/table/_defaults.scss +1 -11
  176. package/src/scss/base/table/_index.scss +126 -117
  177. package/src/scss/base/table/_variables.scss +214 -3
  178. package/src/scss/component/_index.scss +1 -0
  179. package/src/scss/component/accordion/_defaults.scss +73 -22
  180. package/src/scss/component/accordion/_index.scss +437 -62
  181. package/src/scss/component/accordion/_variables.scss +527 -101
  182. package/src/scss/component/alert/_defaults.scss +23 -32
  183. package/src/scss/component/alert/_index.scss +236 -30
  184. package/src/scss/component/alert/_variables.scss +155 -6
  185. package/src/scss/component/badge/_defaults.scss +1 -0
  186. package/src/scss/component/badge/_index.scss +25 -28
  187. package/src/scss/component/badge/_variables.scss +66 -2
  188. package/src/scss/component/card/_defaults.scss +64 -13
  189. package/src/scss/component/card/_index.scss +276 -30
  190. package/src/scss/component/card/_variables.scss +132 -0
  191. package/src/scss/component/carousel/_defaults.scss +73 -15
  192. package/src/scss/component/carousel/_index.scss +357 -41
  193. package/src/scss/component/carousel/_variables.scss +391 -0
  194. package/src/scss/component/disclosure/_index.scss +4 -4
  195. package/src/scss/component/disclosure/_variables.scss +127 -2
  196. package/src/scss/component/input-group/_defaults.scss +10 -3
  197. package/src/scss/component/input-group/_index.scss +72 -4
  198. package/src/scss/component/input-group/_variables.scss +37 -0
  199. package/src/scss/component/list/_defaults.scss +35 -2
  200. package/src/scss/component/list/_index.scss +159 -5
  201. package/src/scss/component/list/_variables.scss +152 -0
  202. package/src/scss/component/menu/_defaults.scss +49 -7
  203. package/src/scss/component/menu/_index.scss +325 -99
  204. package/src/scss/component/menu/_variables.scss +484 -1
  205. package/src/scss/component/navigation/_defaults.scss +45 -3
  206. package/src/scss/component/navigation/_index.scss +249 -98
  207. package/src/scss/component/navigation/_variables.scss +334 -5
  208. package/src/scss/component/tabs/_defaults.scss +82 -0
  209. package/src/scss/component/tabs/_index.scss +497 -0
  210. package/src/scss/component/tabs/_variables.scss +974 -0
  211. package/src/scss/layout/columns/_defaults.scss +5 -3
  212. package/src/scss/layout/columns/_index.scss +27 -21
  213. package/src/scss/layout/columns/_variables.scss +13 -0
  214. package/src/scss/layout/container/_defaults.scss +28 -11
  215. package/src/scss/layout/container/_index.scss +305 -161
  216. package/src/scss/layout/container/_variables.scss +148 -15
  217. package/src/scss/layout/flex-columns/_defaults.scss +5 -3
  218. package/src/scss/layout/flex-columns/_index.scss +28 -20
  219. package/src/scss/layout/flex-columns/_variables.scss +9 -0
  220. package/src/scss/mixins/_state.scss +37 -0
  221. package/src/scss/mixins/_theme.scss +36 -1
  222. package/src/scss/state/focus/_index.scss +17 -12
  223. package/src/scss/state/focus/_variables.scss +30 -4
  224. package/src/scss/theme/color/_defaults.scss +6 -35
  225. package/src/scss/theme/color/_index.scss +167 -1
  226. package/src/scss/theme/color/_variables.scss +155 -0
  227. package/src/scss/theme/typography/_defaults.scss +26 -19
  228. package/src/scss/theme/typography/_index.scss +176 -20
  229. package/src/scss/theme/typography/_variables.scss +186 -0
  230. package/src/scss/utilities/_template/_index.scss +0 -1
  231. package/src/scss/utilities/alignment/_defaults.scss +0 -33
  232. package/src/scss/utilities/alignment/_index.scss +24 -25
  233. package/src/scss/utilities/background/_defaults.scss +0 -77
  234. package/src/scss/utilities/background/_index.scss +32 -37
  235. package/src/scss/utilities/border/_defaults.scss +0 -33
  236. package/src/scss/utilities/border/_index.scss +25 -26
  237. package/src/scss/utilities/color/_defaults.scss +0 -19
  238. package/src/scss/utilities/color/_index.scss +22 -22
  239. package/src/scss/utilities/container/_defaults.scss +0 -11
  240. package/src/scss/utilities/container/_index.scss +20 -19
  241. package/src/scss/utilities/display/_defaults.scss +0 -11
  242. package/src/scss/utilities/display/_index.scss +20 -19
  243. package/src/scss/utilities/flex/_defaults.scss +0 -55
  244. package/src/scss/utilities/flex/_index.scss +28 -31
  245. package/src/scss/utilities/gradient/_defaults.scss +0 -28
  246. package/src/scss/utilities/gradient/_index.scss +27 -28
  247. package/src/scss/utilities/gradient/_variables.scss +15 -0
  248. package/src/scss/utilities/height/_defaults.scss +0 -8
  249. package/src/scss/utilities/height/_index.scss +22 -21
  250. package/src/scss/utilities/inset/_defaults.scss +0 -16
  251. package/src/scss/utilities/inset/_index.scss +20 -20
  252. package/src/scss/utilities/justification/_defaults.scss +0 -33
  253. package/src/scss/utilities/justification/_index.scss +24 -25
  254. package/src/scss/utilities/list/_defaults.scss +0 -22
  255. package/src/scss/utilities/list/_index.scss +22 -22
  256. package/src/scss/utilities/order/_defaults.scss +0 -8
  257. package/src/scss/utilities/order/_index.scss +20 -19
  258. package/src/scss/utilities/position/_defaults.scss +0 -11
  259. package/src/scss/utilities/position/_index.scss +20 -19
  260. package/src/scss/utilities/ratio/_defaults.scss +0 -8
  261. package/src/scss/utilities/ratio/_index.scss +22 -21
  262. package/src/scss/utilities/ratio/_variables.scss +6 -0
  263. package/src/scss/utilities/spacing/_defaults.scss +0 -11
  264. package/src/scss/utilities/spacing/_index.scss +18 -17
  265. package/src/scss/utilities/typography/_defaults.scss +0 -22
  266. package/src/scss/utilities/typography/_index.scss +27 -26
  267. package/src/scss/utilities/visibility/_defaults.scss +0 -11
  268. package/src/scss/utilities/visibility/_index.scss +19 -18
  269. package/src/scss/utilities/visually-hidden/_index.scss +19 -17
  270. package/src/scss/utilities/width/_defaults.scss +0 -8
  271. package/src/scss/utilities/width/_index.scss +21 -20
  272. package/src/scss/utilities/z-index/_defaults.scss +0 -11
  273. package/src/scss/utilities/z-index/_index.scss +19 -18
@@ -0,0 +1,1091 @@
1
+ /**
2
+ * @file
3
+ * The Tab class.
4
+ */
5
+
6
+ import TabToggle from "./TabToggle.js";
7
+ import {
8
+ isValidInstance,
9
+ isValidType,
10
+ isValidClassList,
11
+ isQuerySelector,
12
+ isValidState,
13
+ isValidEvent,
14
+ } from "../validate.js";
15
+ import { addClass, removeClass } from "../domHelpers.js";
16
+ import { keyPress, preventEvent } from "../eventHandlers.js";
17
+ import storage from "../storage.js";
18
+
19
+ class Tabs {
20
+ /**
21
+ * The DOM elements within the tab.
22
+ *
23
+ * @protected
24
+ *
25
+ * @type {Object<HTMLElement, HTMLElement[]>}
26
+ *
27
+ * @property {HTMLElement} tabs - The tabs element.
28
+ * @property {HTMLElement} tabList - The tab list element.
29
+ * @property {HTMLElement[]} tabToggle - An array of tab item toggles.
30
+ * @property {HTMLElement[]} tabContent - An array of tab item contents.
31
+ */
32
+ _dom = {
33
+ tabs: null,
34
+ tabList: null,
35
+ tabToggle: [],
36
+ tabContent: [],
37
+ };
38
+
39
+ /**
40
+ * The DOM elements within the tab that cannot be reset or generated by the tab.
41
+ *
42
+ * @protected
43
+ *
44
+ * @type {string[]}
45
+ */
46
+ _domLock = ["tab"];
47
+
48
+ /**
49
+ * The query selectors used by the tab.
50
+ *
51
+ * @protected
52
+ *
53
+ * @type {Object<string>}
54
+ *
55
+ * @property {string} tabList - The query selector for the tab list.
56
+ * @property {string} tabToggle - The query selector for tab toggles.
57
+ * @property {string} tabContent - The query selector for tab contents.
58
+ */
59
+ _selectors = {
60
+ tabList: "",
61
+ tabToggle: "",
62
+ tabContent: "",
63
+ };
64
+
65
+ /**
66
+ * The declared elements within the tabs.
67
+ *
68
+ * @protected
69
+ *
70
+ * @type {Object<TabToggle[]>}
71
+ *
72
+ * @property {TabToggle[]} tabToggle - The list of tab items.
73
+ */
74
+ _elements = {
75
+ tabToggle: [],
76
+ };
77
+
78
+ /**
79
+ * The classes to apply when the tabs are in various states.
80
+ *
81
+ * @protected
82
+ *
83
+ * @type {Object<string, string[]>}
84
+ *
85
+ * @property {string|string[]} open - The class(es) to apply when the tab is open.
86
+ * @property {string|string[]} close - The class(es) to apply when the tab is closed.
87
+ * @property {string|string[]} transition - The class(es) to apply when the tab is transitioning between states.
88
+ * @property {string|string[]} initialize - The class(es) to apply when the tab is initializing.
89
+ */
90
+ _classes = {
91
+ open: "show",
92
+ close: "hide",
93
+ transition: "transitioning",
94
+ initialize: "initializing",
95
+ };
96
+
97
+ /**
98
+ * The duration times (in milliseconds) for various things throughout the tabs.
99
+ *
100
+ * @protected
101
+ *
102
+ * @type {Object<number>}
103
+ *
104
+ * @property {number} transition - The duration time (in milliseconds) for the transition between open and closed states.
105
+ * @property {number} open - The duration time (in milliseconds) for the transition from closed to open states.
106
+ * @property {number} close - The duration time (in milliseconds) for the transition from open to closed states.
107
+ */
108
+ _durations = {
109
+ transition: 250,
110
+ open: -1,
111
+ close: -1,
112
+ };
113
+
114
+ /**
115
+ * The current state of the tab's focus.
116
+ *
117
+ * @protected
118
+ *
119
+ * @type {string}
120
+ */
121
+ _focusState = "none";
122
+
123
+ /**
124
+ * This last event triggered on the tab.
125
+ *
126
+ * @protected
127
+ *
128
+ * @type {string}
129
+ */
130
+ _currentEvent = "none";
131
+
132
+ /**
133
+ * A flag to set if focusing a tab item toggle will automatically activate it.
134
+ *
135
+ * @protected
136
+ *
137
+ * @type {boolean}
138
+ */
139
+ _automatic = false;
140
+
141
+ /**
142
+ * The index of the current child node.
143
+ *
144
+ * @protected
145
+ *
146
+ * @type {number}
147
+ */
148
+ _currentChild = 0;
149
+
150
+ /**
151
+ * The prefix to use for CSS custom properties.
152
+ *
153
+ * @protected
154
+ *
155
+ * @type {string}
156
+ */
157
+ _prefix = "graupl-";
158
+
159
+ /**
160
+ * The key used to generate IDs throughout the tab.
161
+ *
162
+ * @protected
163
+ *
164
+ * @type {string}
165
+ */
166
+ _key = "";
167
+
168
+ /**
169
+ * errors - The list of errors found during validation.
170
+ *
171
+ * @protected
172
+ *
173
+ * @type {string[]}
174
+ */
175
+ _errors = [];
176
+
177
+ /**
178
+ * Constructs a new `Tab`.
179
+ *
180
+ * @param {object} options - The options for generating the tab.
181
+ * @param {HTMLElement} [options.tabsElement] - The tab element in the DOM.
182
+ * @param {string} [options.tabListSelector = .tab-list] - The query selector string for the tab list.
183
+ * @param {string} [options.tabToggleSelector = .tab-toggle] - The query selector string for tab toggle.
184
+ * @param {string} [options.tabContentSelector = .tab-content] - The query selector string for tab content.
185
+ * @param {?(string|string[])} [options.openClass = show] - The class to apply when a tab is "open".
186
+ * @param {?(string|string[])} [options.closeClass = hide] - The class to apply when a tab is "closed".
187
+ * @param {?(string|string[])} [options.transitionClass = null] - The class to apply when a tab is transitioning between "open" and "closed" states.
188
+ * @param {number} [options.transitionDuration = 300] - The duration of the transition between "open" and "closed" states (in milliseconds).
189
+ * @param {number} [options.openDuration = -1] - The duration of the transition from "closed" to "open" states (in milliseconds).
190
+ * @param {number} [options.closeDuration = -1] - The duration of the transition from "open" to "closed" states (in milliseconds).
191
+ * @param {boolean} [options.automaticActivation = false] - A flag to set if focusing a tab item toggle will automatically activate it.
192
+ * @param {?string} [options.prefix = graupl-] - The prefix to use for CSS custom properties.
193
+ * @param {?string} [options.key = null] - The key used to generate IDs throughout the tab.
194
+ * @param {?(string|string[])} [options.initializeClass = initializing] - The class to apply when a tabs are initialzing.
195
+ * @param {boolean} [options.initialize = false] - A flag to initialize the tab immediately upon creation.
196
+ */
197
+ constructor({
198
+ tabsElement,
199
+ tabListSelector = ".tab-list",
200
+ tabToggleSelector = ".tab-toggle",
201
+ tabContentSelector = ".tab-content",
202
+ openClass = "show",
203
+ closeClass = "hide",
204
+ transitionClass = null,
205
+ transitionDuration = 300,
206
+ openDuration = -1,
207
+ closeDuration = -1,
208
+ automaticActivation = false,
209
+ prefix = "graupl-",
210
+ key = null,
211
+ initializeClass = "initializing",
212
+ initialize = false,
213
+ }) {
214
+ // Set DOM elements.
215
+ this._dom.tabs = tabsElement;
216
+
217
+ // Set DOM selectors.
218
+ this._selectors.tabList = tabListSelector;
219
+ this._selectors.tabToggle = tabToggleSelector;
220
+ this._selectors.tabContent = tabContentSelector;
221
+
222
+ // Set open/close classes.
223
+ this._classes.open = openClass || "";
224
+ this._classes.close = closeClass || "";
225
+ this._classes.transition = transitionClass || "";
226
+ this._classes.initialize = initializeClass || "";
227
+
228
+ // Set transition duration.
229
+ this._durations.transition = transitionDuration;
230
+ this._durations.open = openDuration;
231
+ this._durations.close = closeDuration;
232
+
233
+ // Set automatic activation.
234
+ this._automatic = automaticActivation;
235
+
236
+ // Set prefix.
237
+ this._prefix = prefix || "";
238
+
239
+ // Set the key.
240
+ this._key = key || "";
241
+
242
+ if (initialize) {
243
+ this.initialize();
244
+ }
245
+ }
246
+
247
+ /**
248
+ * Initializes the tabs.
249
+ */
250
+ initialize() {
251
+ try {
252
+ if (!this._validate()) {
253
+ throw new Error(
254
+ `Graupl Tab: cannot initialize tab. The following errors have been found:\n - ${this.errors.join(
255
+ "\n - "
256
+ )}`
257
+ );
258
+ }
259
+
260
+ addClass(this._classes.initialize, this.dom.tabs);
261
+
262
+ // Set up the DOM.
263
+ this._generateKey();
264
+ this._setDOMElements();
265
+ this._setIds();
266
+ this._setAriaAttributes();
267
+
268
+ // Create the child elements.
269
+ this._createChildElements();
270
+
271
+ // Handle events.
272
+ this._handleFocus();
273
+ this._handleClick();
274
+ this._handleKeydown();
275
+ this._handleKeyup();
276
+
277
+ // // Set the custom props.
278
+ this._setTransitionDurations();
279
+
280
+ // Set up the storage.
281
+ storage.initializeStorage("tabs");
282
+ storage.pushToStorage("tabs", this.dom.tabs.id, this);
283
+
284
+ if (
285
+ this.elements.tabToggle.filter((toggle) => toggle.isActive).length === 0
286
+ ) {
287
+ this.elements.tabToggle[0].show();
288
+ }
289
+
290
+ requestAnimationFrame(() => {
291
+ removeClass(this._classes.initialize, this.dom.tabs);
292
+ });
293
+ } catch (error) {
294
+ console.error(error);
295
+ }
296
+ }
297
+
298
+ /**
299
+ * The DOM elements of the tab.
300
+ *
301
+ * @readonly
302
+ *
303
+ * @type {object}
304
+ *
305
+ * @see _dom
306
+ */
307
+ get dom() {
308
+ return this._dom;
309
+ }
310
+
311
+ /**
312
+ * The declared elements of the tabs.
313
+ *
314
+ * @readonly
315
+ *
316
+ * @type {object}
317
+ *
318
+ * @see _elements
319
+ */
320
+ get elements() {
321
+ return this._elements;
322
+ }
323
+
324
+ /**
325
+ * The selectors used for the tab and tab items.
326
+ *
327
+ * @readonly
328
+ *
329
+ * @type {boolean}
330
+ *
331
+ * @see _selectors
332
+ */
333
+ get selectors() {
334
+ return this._selectors;
335
+ }
336
+
337
+ /**
338
+ * The class(es) to apply when the tab is open.
339
+ *
340
+ * @type {string|string[]}
341
+ *
342
+ * @see _classes.open
343
+ */
344
+ get openClass() {
345
+ return this._classes.open;
346
+ }
347
+
348
+ set openClass(value) {
349
+ isValidClassList({ openClass: value });
350
+
351
+ if (this._classes.open !== value) {
352
+ this._classes.open = value;
353
+ }
354
+ }
355
+
356
+ /**
357
+ * The class(es) to apply when the tab is closed.
358
+ *
359
+ * @type {string|string[]}
360
+ *
361
+ * @see _classes.close
362
+ */
363
+ get closeClass() {
364
+ return this._classes.close;
365
+ }
366
+
367
+ set closeClass(value) {
368
+ isValidClassList({ closeClass: value });
369
+
370
+ if (this._classes.close !== value) {
371
+ this._classes.close = value;
372
+ }
373
+ }
374
+
375
+ /**
376
+ * The class(es) to apply when the tab is transitioning between open and closed.
377
+ *
378
+ * @type {string|string[]}
379
+ *
380
+ * @see _classes.transition
381
+ */
382
+ get transitionClass() {
383
+ return this._classes.transition;
384
+ }
385
+
386
+ set transitionClass(value) {
387
+ isValidClassList({ transitionClass: value });
388
+
389
+ if (this._classes.transition !== value) {
390
+ this._classes.transition = value;
391
+ }
392
+ }
393
+
394
+ /**
395
+ * The duration time (in milliseconds) for the transition between open and closed states.
396
+ *
397
+ * @type {number}
398
+ *
399
+ * @see _durations.transition
400
+ */
401
+ get transitionDuration() {
402
+ return this._durations.transition;
403
+ }
404
+
405
+ set transitionDuration(value) {
406
+ isValidType("number", { value });
407
+
408
+ if (this._durations.transition !== value) {
409
+ this._durations.transition = value;
410
+ this._setTransitionDurations();
411
+ }
412
+ }
413
+
414
+ /**
415
+ * The duration time (in milliseconds) for the transition from closed to open states.
416
+ *
417
+ * If openDuration is set to -1, the transitionDuration will be used instead.
418
+ *
419
+ * @type {number}
420
+ *
421
+ * @see _durations.open
422
+ */
423
+ get openDuration() {
424
+ return this._durations.open === -1
425
+ ? this.transitionDuration
426
+ : this._durations.open;
427
+ }
428
+
429
+ set openDuration(value) {
430
+ isValidType("number", { value });
431
+
432
+ if (this._durations.open !== value) {
433
+ this._durations.open = value;
434
+ this._setTransitionDurations();
435
+ }
436
+ }
437
+
438
+ /**
439
+ * The duration time (in milliseconds) for the transition from open to closed states.
440
+ *
441
+ * If closeDuration is set to -1, the transitionDuration will be used instead.
442
+ *
443
+ * @type {number}
444
+ *
445
+ * @see _durations.close
446
+ */
447
+ get closeDuration() {
448
+ return this._durations.close === -1
449
+ ? this.transitionDuration
450
+ : this._durations.close;
451
+ }
452
+
453
+ set closeDuration(value) {
454
+ isValidType("number", { value });
455
+
456
+ if (this._durations.close !== value) {
457
+ this._durations.close = value;
458
+ this._setTransitionDurations();
459
+ }
460
+ }
461
+
462
+ /**
463
+ * A flag to set if focusing a tab item toggle will automatically activate it.
464
+ *
465
+ * @type {boolean}
466
+ *
467
+ * @see _automatic
468
+ */
469
+ get isAutomatic() {
470
+ return this._automatic;
471
+ }
472
+
473
+ set isAutomatic(value) {
474
+ isValidType("boolean", { value });
475
+
476
+ if (this._automatic !== value) {
477
+ this._automatic = value;
478
+ }
479
+ }
480
+
481
+ /**
482
+ * The current index of the tab item.
483
+ *
484
+ * @readonly
485
+ *
486
+ * @type {number}
487
+ *
488
+ * @see _currentChild
489
+ */
490
+ get currentChild() {
491
+ return this._currentChild;
492
+ }
493
+
494
+ set currentChild(value) {
495
+ isValidType("number", { value });
496
+
497
+ if (
498
+ this._currentChild !== value &&
499
+ value >= 0 &&
500
+ value < this.elements.tabToggle.length
501
+ ) {
502
+ this._currentChild = value;
503
+ }
504
+ }
505
+ /**
506
+ * The currently selected tab item.
507
+ *
508
+ * @readonly
509
+ *
510
+ * @type {TabToggle}
511
+ */
512
+ get currentTabToggle() {
513
+ return this.elements.tabToggle[this.currentChild];
514
+ }
515
+
516
+ /**
517
+ * The current state of the tab's focus.
518
+ *
519
+ * @type {string}
520
+ *
521
+ * @see _focusState
522
+ */
523
+ get focusState() {
524
+ return this._focusState;
525
+ }
526
+
527
+ set focusState(value) {
528
+ isValidState({ value });
529
+
530
+ if (this._focusState !== value) {
531
+ this._focusState = value;
532
+ }
533
+ }
534
+
535
+ /**
536
+ * The last event triggered on the tabs.
537
+ *
538
+ * @type {string}
539
+ *
540
+ * @see _currentEvent
541
+ */
542
+ get currentEvent() {
543
+ return this._currentEvent;
544
+ }
545
+
546
+ set currentEvent(value) {
547
+ isValidEvent({ value });
548
+
549
+ if (this._currentEvent !== value) {
550
+ this._currentEvent = value;
551
+ }
552
+ }
553
+
554
+ /**
555
+ * The prefix to use for CSS custom properties.
556
+ *
557
+ * @type {string}
558
+ *
559
+ * @see _prefix
560
+ */
561
+ get prefix() {
562
+ return this._prefix;
563
+ }
564
+
565
+ set prefix(value) {
566
+ isValidType("string", { value });
567
+
568
+ if (this._prefix !== value) {
569
+ this._prefix = value;
570
+ }
571
+ }
572
+
573
+ /**
574
+ * The key used to generate IDs throughout the tab.
575
+ *
576
+ * @readonly
577
+ *
578
+ * @type {string}
579
+ *
580
+ * @see _key
581
+ */
582
+ get key() {
583
+ return this._key;
584
+ }
585
+
586
+ /**
587
+ * An array to hold error messages.
588
+ *
589
+ * @readonly
590
+ *
591
+ * @type {string[]}
592
+ *
593
+ * @see _errors
594
+ */
595
+ get errors() {
596
+ return this._errors;
597
+ }
598
+
599
+ /**
600
+ * Validates all aspects of the tabs to ensure proper functionality.
601
+ *
602
+ * @protected
603
+ *
604
+ * @return {boolean} - The result of the validation.
605
+ */
606
+ _validate() {
607
+ let check = true;
608
+
609
+ // HTML element checks.
610
+ const htmlElementChecks = isValidInstance(HTMLElement, {
611
+ tabsElement: this.dom.tabs,
612
+ });
613
+
614
+ if (!htmlElementChecks) {
615
+ this._errors.push(htmlElementChecks.message);
616
+ check = false;
617
+ }
618
+
619
+ // Query selector checks.
620
+ const querySelectors = {};
621
+
622
+ for (const querySelector of Object.keys(this._selectors)) {
623
+ querySelectors[`${querySelector}Selector`] =
624
+ this._selectors[querySelector];
625
+ }
626
+
627
+ const querySelectorChecks = isQuerySelector(querySelectors);
628
+
629
+ if (!querySelectorChecks) {
630
+ this._errors.push(querySelectorChecks.message);
631
+ check = false;
632
+ }
633
+
634
+ // Class list checks.
635
+ const classes = {};
636
+
637
+ for (const className of Object.keys(this._classes)) {
638
+ if (this._classes[className] === "") {
639
+ continue;
640
+ }
641
+
642
+ classes[`${className}Class`] = this._classes[className];
643
+ }
644
+
645
+ const classListChecks = isValidClassList(classes);
646
+
647
+ if (!classListChecks.status) {
648
+ this._errors.push(classListChecks.error.message);
649
+ check = false;
650
+ }
651
+
652
+ // Duration checks.
653
+ const durations = {};
654
+
655
+ for (const durationName of Object.keys(this._durations)) {
656
+ durations[`${durationName}Duration`] = this._durations[durationName];
657
+ }
658
+
659
+ const durationChecks = isValidType("number", durations);
660
+
661
+ if (!durationChecks.status) {
662
+ this._errors.push(durationChecks.error.message);
663
+ check = false;
664
+ }
665
+
666
+ // Boolean checks.
667
+ const booleanCheck = isValidType("boolean", {
668
+ automaticActivation: this._automatic,
669
+ });
670
+
671
+ if (!booleanCheck.status) {
672
+ this._errors.push(booleanCheck.error.message);
673
+ check = false;
674
+ }
675
+
676
+ // Key check.
677
+ if (this._key !== "") {
678
+ const keyCheck = isValidType("string", { key: this._key });
679
+
680
+ if (!keyCheck.status) {
681
+ this._errors.push(keyCheck.error.message);
682
+ check = false;
683
+ }
684
+ }
685
+
686
+ // Prefix check.
687
+ const prefixCheck = isValidType("string", { prefix: this._prefix });
688
+
689
+ if (!prefixCheck.status) {
690
+ this._errors.push(prefixCheck.error.message);
691
+ check = false;
692
+ }
693
+
694
+ return check;
695
+ }
696
+
697
+ /**
698
+ * Generates a key for the tabs.
699
+ *
700
+ * @param {Object<boolean>} [options = {}] - Options for generating the key.
701
+ * @param {boolean} [options.regenerate = false] - A flag to determine if the key should be regenerated.
702
+ */
703
+ _generateKey({ regenerate = false } = {}) {
704
+ if (this.key === "" || regenerate) {
705
+ this._key = Math.random()
706
+ .toString(36)
707
+ .replace(/[^a-z]+/g, "")
708
+ .substring(0, 10);
709
+ }
710
+ }
711
+
712
+ /**
713
+ * Sets the IDs of the tab and it's children if they do not already exist.
714
+ *
715
+ * The generated IDs use the key and follow the format:
716
+ * - tabs: `tabs-${key}`
717
+ * - tab-list: `tab-list-${key}`
718
+ *
719
+ * @protected
720
+ */
721
+ _setIds() {
722
+ this.dom.tabs.id = this.dom.tabs.id || `tabs-${this.key}`;
723
+ this.dom.tabList.id = this.dom.tabList.id || `tab-list-${this.key}`;
724
+ }
725
+
726
+ /**
727
+ * Sets the ARIA attributes for the tablist.
728
+ *
729
+ * @protected
730
+ */
731
+ _setAriaAttributes() {
732
+ this.dom.tabList.setAttribute("role", "tablist");
733
+ }
734
+
735
+ /**
736
+ * Sets the transition durations of the tab as a CSS custom properties.
737
+ *
738
+ * The custom properties are:
739
+ * - `--graupl-tabs-transition-duration`,
740
+ * - `--graupl-tabs-open-transition-duration`, and
741
+ * - `--graupl-tabs-close-transition-duration`.
742
+ *
743
+ * The prefix of `graupl-` can be changed by setting the tab's prefix value.
744
+ *
745
+ * @protected
746
+ */
747
+ _setTransitionDurations() {
748
+ this.dom.tabs.style.setProperty(
749
+ `--${this.prefix}tabs-transition-duration`,
750
+ `${this.transitionDuration}ms`
751
+ );
752
+
753
+ this.dom.tabs.style.setProperty(
754
+ `--${this.prefix}tabs-open-transition-duration`,
755
+ `${this.openDuration}ms`
756
+ );
757
+
758
+ this.dom.tabs.style.setProperty(
759
+ `--${this.prefix}tabs-close-transition-duration`,
760
+ `${this.closeDuration}ms`
761
+ );
762
+ }
763
+
764
+ /**
765
+ * Sets DOM elements.
766
+ *
767
+ * Elements listed in _domLock cannot be set using this method.
768
+ *
769
+ * @protected
770
+ *
771
+ * @param {string} elementType - The type of element to populate.
772
+ * @param {Object<HTMLElement,boolean>} [options = {}] - The options for setting the DOM element type.
773
+ * @param {HTMLElement} [options.base = this.dom.tabs] - The element used as the base for the querySelector.
774
+ * @param {boolean} [options.overwrite = true] - A flag to set if the existing elements will be overwritten.
775
+ * @param {boolean} [options.strict = true] - A flag to set if the elements must be direct children of the base.
776
+ */
777
+ _setDOMElementType(
778
+ elementType,
779
+ { base = this.dom.tabs, overwrite = true, strict = true } = {}
780
+ ) {
781
+ if (typeof this.selectors[elementType] === "string") {
782
+ if (this._domLock.includes(elementType)) {
783
+ throw new Error(
784
+ `Graupl ${this.constructor.name}: "${elementType}" element cannot be set through _setDOMElementType.`
785
+ );
786
+ }
787
+
788
+ if (base !== this.dom.tabs) isValidInstance(HTMLElement, { base });
789
+
790
+ // Get the all elements matching the selector in the base.
791
+ const domElements = Array.from(
792
+ base.querySelectorAll(this.selectors[elementType])
793
+ );
794
+
795
+ // Filter the elements so only direct children of the base are kept.
796
+ const filteredElements = domElements.filter((item) =>
797
+ strict ? item.parentElement === base : true
798
+ );
799
+
800
+ if (overwrite) {
801
+ if (Array.isArray(this._dom[elementType])) {
802
+ this._dom[elementType] = filteredElements;
803
+ } else {
804
+ this._dom[elementType] = filteredElements[0] || null;
805
+ }
806
+ } else {
807
+ if (Array.isArray(this._dom[elementType])) {
808
+ this._dom[elementType] = [
809
+ ...this._dom[elementType],
810
+ ...filteredElements,
811
+ ];
812
+ } else {
813
+ this._dom[elementType] = filteredElements[0] || null;
814
+ }
815
+ }
816
+ } else {
817
+ throw new Error(
818
+ `Graupl ${this.constructor.name}: "${elementType}" is not a valid element type.`
819
+ );
820
+ }
821
+ }
822
+
823
+ /**
824
+ * Resets DOM elements.
825
+ *
826
+ * Elements listed in _domLock cannot be reset using this method.
827
+ *
828
+ * @protected
829
+ *
830
+ * @param {string} elementType - The type of element to clear.
831
+ */
832
+ _resetDOMElementType(elementType) {
833
+ if (typeof this.selectors[elementType] === "string") {
834
+ if (this._domLock.includes(elementType)) {
835
+ throw new Error(
836
+ `Graupl ${this.constructor.name}: "${elementType}" element cannot be reset through _resetDOMElementType.`
837
+ );
838
+ }
839
+
840
+ if (Array.isArray(this._dom[elementType])) {
841
+ this._dom[elementType] = [];
842
+ } else {
843
+ this._dom[elementType] = null;
844
+ }
845
+ } else {
846
+ throw new Error(
847
+ `Graupl ${this.constructor.name}: "${elementType}" is not a valid element type.`
848
+ );
849
+ }
850
+ }
851
+
852
+ /**
853
+ * Sets all DOM elements within the tab.
854
+ *
855
+ * Utilizes _setDOMElementType and
856
+ * _resetDOMElementType.
857
+ *
858
+ * @protected
859
+ */
860
+ _setDOMElements() {
861
+ this._resetDOMElementType("tabList");
862
+ this._setDOMElementType("tabList");
863
+
864
+ if (this.dom.tabList) {
865
+ this._resetDOMElementType("tabToggle");
866
+ this._setDOMElementType("tabToggle", { base: this.dom.tabList });
867
+ }
868
+
869
+ this._resetDOMElementType("tabContent");
870
+ this._setDOMElementType("tabContent");
871
+ }
872
+
873
+ /**
874
+ * Creates and initializes all tab toggles.
875
+ *
876
+ * @protected
877
+ */
878
+ _createChildElements() {
879
+ this.dom.tabToggle.forEach((tabToggle, index) => {
880
+ const toggle = new TabToggle({
881
+ toggleElement: tabToggle,
882
+ contentElement: this.dom.tabContent[index],
883
+ parentTab: this,
884
+ });
885
+
886
+ toggle.initialize();
887
+
888
+ this._elements.tabToggle.push(toggle);
889
+ });
890
+ }
891
+
892
+ /**
893
+ * Handles focus events throughout the tab for proper use.
894
+ *
895
+ * - Adds a `focus` listener to every tab item so when it gains focus,
896
+ * it will set the tab's current child to the index of the item.
897
+ *
898
+ * @protected
899
+ */
900
+ _handleFocus() {
901
+ this.elements.tabToggle.forEach((toggle, index) => {
902
+ toggle.dom.toggle.addEventListener("focus", () => {
903
+ this.currentChild = index;
904
+
905
+ if (this.isAutomatic) {
906
+ this.currentTabToggle.show();
907
+ }
908
+ });
909
+ });
910
+ }
911
+
912
+ /**
913
+ * Handles click events throughout the tab item for proper use.
914
+ *
915
+ * - Adds a `pointerup` listener to the tab item toggles that will toggle each tab item.
916
+ *
917
+ * @protected
918
+ */
919
+ _handleClick() {
920
+ this.elements.tabToggle.forEach((toggle, index) => {
921
+ toggle.dom.toggle.addEventListener("pointerup", () => {
922
+ this.currentChild = index;
923
+ toggle.show();
924
+ });
925
+ });
926
+ }
927
+
928
+ /**
929
+ * Handles keydown events throughout the tab item for proper use.
930
+ *
931
+ * This method exists to assist the _handleKeyup method.
932
+ *
933
+ * - Adds a `keydown` listener to all tab item toggles.
934
+ * - Blocks propagation on "Space", "Enter", "ArrowRight", "ArrowLeft", "Home", and "End" keys.
935
+ */
936
+ _handleKeydown() {
937
+ this.dom.tabToggle.forEach((tabToggle) => {
938
+ tabToggle.addEventListener("keydown", (event) => {
939
+ const key = keyPress(event);
940
+ const ToggleKeys = [
941
+ "Space",
942
+ "Enter",
943
+ "ArrowRight",
944
+ "ArrowLeft",
945
+ "Home",
946
+ "End",
947
+ ];
948
+
949
+ // Prevent default behavior for space and enter keys.
950
+ if (ToggleKeys.includes(key)) {
951
+ preventEvent(event);
952
+ }
953
+ });
954
+ });
955
+ }
956
+
957
+ /**
958
+ * Handles keyup events throughout the tab item for proper use.
959
+ *
960
+ * Adds the follow keybindings (explanations are taken from the WAI ARIA Practices Guide Tab Pattern):
961
+ *
962
+ * - `Enter` or `Space`:
963
+ * - When focus is on the tab link for a collapsed panel, expands the associated panel. If the implementation allows only one panel to be expanded, and if another panel is expanded, collapses that panel.
964
+ * - When focus is on the tab link for an expanded panel, collapses the panel if the implementation supports collapsing. Some implementations require one panel to be expanded at all times and allow only one panel to be expanded; so, they do not support a collapse function.
965
+ * - `Tab`: Moves focus to the next focusable element; all focusable elements in the tab are included in the page `Tab` sequence.
966
+ * - `Shift + Tab`: Moves focus to the previous focusable element; all focusable elements in the tab are included in the page `Tab` sequence.
967
+ * - `Down Arrow` (Optional): If focus is on an tab link, moves focus to the next tab link. If focus is on the last tab link, either does nothing or moves focus to the first tab link.
968
+ * - `Up Arrow` (Optional): If focus is on an tab link, moves focus to the previous tab link. If focus is on the first tab link, either does nothing or moves focus to the last tab link.
969
+ * - `Home` (Optional): When focus is on an tab link, moves focus to the first tab link.
970
+ * - `End` (Optional): When focus is on an tab link, moves focus to the last tab link.
971
+ *
972
+ * Note: When the above explanations mention "tab link", they are referring to the tab item toggle.
973
+ */
974
+ _handleKeyup() {
975
+ this.dom.tabToggle.forEach((tabToggle) => {
976
+ tabToggle.addEventListener("keyup", (event) => {
977
+ const key = keyPress(event);
978
+
979
+ switch (key) {
980
+ case "Space":
981
+ case "Enter":
982
+ preventEvent(event);
983
+ this.currentTabToggle.show();
984
+
985
+ break;
986
+ case "Home":
987
+ preventEvent(event);
988
+ this.focusFirstChild();
989
+
990
+ break;
991
+ case "End":
992
+ preventEvent(event);
993
+ this.focusLastChild();
994
+
995
+ break;
996
+ case "ArrowRight":
997
+ preventEvent(event);
998
+ this.focusNextChild();
999
+
1000
+ break;
1001
+ case "ArrowLeft":
1002
+ preventEvent(event);
1003
+ this.focusPreviousChild();
1004
+
1005
+ break;
1006
+ }
1007
+ });
1008
+ });
1009
+ }
1010
+
1011
+ /**
1012
+ * Focus the tab's current child.
1013
+ *
1014
+ * @public
1015
+ */
1016
+ focusCurrentChild() {
1017
+ if (this.currentChild !== -1) {
1018
+ this.currentTabToggle.focus();
1019
+ }
1020
+ }
1021
+
1022
+ /**
1023
+ * Focuses the tab's child at a given index.
1024
+ *
1025
+ * @public
1026
+ *
1027
+ * @param {number} index - The index of the child to focus.
1028
+ */
1029
+ focusChild(index) {
1030
+ this.blurCurrentChild();
1031
+ this.currentChild = index;
1032
+ this.focusCurrentChild();
1033
+ }
1034
+
1035
+ /**
1036
+ * Focuses the tab's first child.
1037
+ *
1038
+ * @public
1039
+ */
1040
+ focusFirstChild() {
1041
+ this.focusChild(0);
1042
+ }
1043
+
1044
+ /**
1045
+ * Focus the tab's last child.
1046
+ *
1047
+ * @public
1048
+ */
1049
+ focusLastChild() {
1050
+ this.focusChild(this.elements.tabToggle.length - 1);
1051
+ }
1052
+
1053
+ /**
1054
+ * Focus the tab's next child.
1055
+ *
1056
+ * @public
1057
+ */
1058
+ focusNextChild() {
1059
+ if (this.currentChild < this.elements.tabToggle.length - 1) {
1060
+ this.focusChild(this.currentChild + 1);
1061
+ } else {
1062
+ this.focusFirstChild();
1063
+ }
1064
+ }
1065
+
1066
+ /**
1067
+ * Focus the tab's previous child.
1068
+ *
1069
+ * @public
1070
+ */
1071
+ focusPreviousChild() {
1072
+ if (this.currentChild > 0) {
1073
+ this.focusChild(this.currentChild - 1);
1074
+ } else {
1075
+ this.focusLastChild();
1076
+ }
1077
+ }
1078
+
1079
+ /**
1080
+ * Blurs the tab's current child.
1081
+ *
1082
+ * @public
1083
+ */
1084
+ blurCurrentChild() {
1085
+ if (this.currentChild !== -1) {
1086
+ this.currentTabToggle.blur();
1087
+ }
1088
+ }
1089
+ }
1090
+
1091
+ export default Tabs;