ku4web-components 6.5.3 → 6.5.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (259) hide show
  1. package/angular/index.js +1 -1
  2. package/angular/index.mjs +1 -1
  3. package/dist/cjs/app-globals-3a1e7e63.js +5 -0
  4. package/dist/cjs/css-shim-f1391d35.js +6 -0
  5. package/dist/cjs/dom-5345ed9a.js +75 -0
  6. package/dist/cjs/index-065185f8.js +3093 -0
  7. package/dist/cjs/index-16f16ed9.js +14 -0
  8. package/dist/cjs/index-1a439af7.js +14 -0
  9. package/dist/cjs/index-436596bf.js +10 -0
  10. package/dist/cjs/index-49d3746b.js +10 -0
  11. package/dist/cjs/ku4-carousel-controls.cjs.entry.js +2 -2
  12. package/dist/cjs/ku4-carousel-slide.cjs.entry.js +1 -1
  13. package/dist/cjs/ku4-carousel.cjs.entry.js +3 -3
  14. package/dist/cjs/ku4-col.cjs.entry.js +1 -1
  15. package/dist/cjs/ku4-drawer.cjs.entry.js +1 -1
  16. package/dist/cjs/ku4-feature.cjs.entry.js +2 -2
  17. package/dist/cjs/ku4-focus-trap.cjs.entry.js +26 -26
  18. package/dist/cjs/ku4-form.cjs.entry.js +3 -3
  19. package/dist/cjs/ku4-grid.cjs.entry.js +1 -1
  20. package/dist/cjs/ku4-label.cjs.entry.js +2 -2
  21. package/dist/cjs/ku4-mask.cjs.entry.js +3 -3
  22. package/dist/cjs/ku4-modal.cjs.entry.js +3 -3
  23. package/dist/cjs/ku4-panel.cjs.entry.js +1 -1
  24. package/dist/cjs/ku4-preview.cjs.entry.js +43 -14
  25. package/dist/cjs/ku4-tab-list.cjs.entry.js +4 -4
  26. package/dist/cjs/ku4-tab-panel.cjs.entry.js +3 -3
  27. package/dist/cjs/ku4-tab.cjs.entry.js +3 -3
  28. package/dist/cjs/ku4-table.cjs.entry.js +1 -1
  29. package/dist/cjs/ku4-tooltip.cjs.entry.js +2 -2
  30. package/dist/cjs/ku4-validation.cjs.entry.js +2 -2
  31. package/dist/cjs/ku4web-components.cjs.js +101 -6
  32. package/dist/cjs/loader.cjs.js +17 -1
  33. package/dist/cjs/{uid-d533dbb1.js → uid-7f3954c8.js} +1 -1
  34. package/dist/cjs/uid-a1348ea5.js +11 -0
  35. package/dist/collection/capabilities/a11y/aria.js +26 -0
  36. package/dist/collection/capabilities/angular/index.js +24 -0
  37. package/dist/collection/capabilities/decorators/deprecated.js +20 -0
  38. package/dist/collection/capabilities/decorators/index.js +3 -0
  39. package/dist/collection/capabilities/decorators/memoize.js +7 -0
  40. package/dist/collection/capabilities/dom/isFocusable.js +7 -0
  41. package/dist/collection/capabilities/dom/queryFocusable.js +2 -0
  42. package/dist/collection/capabilities/identity/uid.js +6 -0
  43. package/dist/collection/capabilities/mask/index.js +5 -0
  44. package/dist/collection/capabilities/mask/patterns/date.js +40 -0
  45. package/dist/collection/capabilities/mask/patterns/index.js +7 -0
  46. package/dist/collection/capabilities/react/index.js +25 -0
  47. package/dist/collection/capabilities/testing/html.js +14 -0
  48. package/dist/collection/capabilities/testing/styles.js +14 -0
  49. package/dist/collection/capabilities/vue/index.js +28 -0
  50. package/dist/collection/capabilities/vue3/index.js +26 -0
  51. package/dist/collection/collection-manifest.json +31 -0
  52. package/dist/collection/components/ku4-carousel/ku4-carousel.css +221 -0
  53. package/dist/collection/components/ku4-carousel/ku4-carousel.js +369 -0
  54. package/dist/collection/components/ku4-carousel-controls/ku4-carousel-controls.css +32 -0
  55. package/dist/collection/components/ku4-carousel-controls/ku4-carousel-controls.js +112 -0
  56. package/dist/collection/components/ku4-carousel-slide/ku4-carousel-slide.css +3 -0
  57. package/dist/collection/components/ku4-carousel-slide/ku4-carousel-slide.js +159 -0
  58. package/dist/collection/components/ku4-col/ku4-col.css +601 -0
  59. package/dist/collection/components/ku4-col/ku4-col.js +288 -0
  60. package/dist/collection/components/ku4-drawer/ku4-drawer.css +56 -0
  61. package/dist/collection/components/ku4-drawer/ku4-drawer.js +163 -0
  62. package/dist/collection/components/ku4-feature/ku4-feature.js +70 -0
  63. package/dist/collection/components/ku4-focus-trap/ku4-focus-trap.css +3 -0
  64. package/dist/collection/components/ku4-focus-trap/ku4-focus-trap.js +441 -0
  65. package/dist/collection/components/ku4-form/ku4-form.js +265 -0
  66. package/dist/collection/components/ku4-grid/ku4-grid.css +751 -0
  67. package/dist/collection/components/ku4-grid/ku4-grid.js +408 -0
  68. package/dist/collection/components/ku4-label/ku4-label.css +36 -0
  69. package/dist/collection/components/ku4-label/ku4-label.js +115 -0
  70. package/dist/collection/components/ku4-mask/ku4-mask.css +3 -0
  71. package/dist/collection/components/ku4-mask/ku4-mask.js +459 -0
  72. package/dist/collection/components/ku4-modal/ku4-modal.css +85 -0
  73. package/dist/collection/components/ku4-modal/ku4-modal.js +231 -0
  74. package/dist/collection/components/ku4-panel/ku4-panel.css +14 -0
  75. package/dist/collection/components/ku4-panel/ku4-panel.js +119 -0
  76. package/dist/collection/components/ku4-preview/ku4-preview.css +23 -0
  77. package/dist/collection/components/ku4-preview/ku4-preview.js +266 -0
  78. package/dist/collection/components/ku4-tab/ku4-tab.css +82 -0
  79. package/dist/collection/components/ku4-tab/ku4-tab.js +191 -0
  80. package/dist/collection/components/ku4-tab-list/ku4-tab-list.css +6 -0
  81. package/dist/collection/components/ku4-tab-list/ku4-tab-list.js +118 -0
  82. package/dist/collection/components/ku4-tab-panel/ku4-tab-panel.css +26 -0
  83. package/dist/collection/components/ku4-tab-panel/ku4-tab-panel.js +166 -0
  84. package/dist/collection/components/ku4-table/ku4-table.css +116 -0
  85. package/dist/collection/components/ku4-table/ku4-table.js +120 -0
  86. package/dist/collection/components/ku4-tooltip/ku4-tooltip.css +56 -0
  87. package/dist/collection/components/ku4-tooltip/ku4-tooltip.js +274 -0
  88. package/dist/collection/components/ku4-validation/ku4-validation.css +19 -0
  89. package/dist/collection/components/ku4-validation/ku4-validation.js +364 -0
  90. package/dist/collection/components/ku4-validation/validate.js +14 -0
  91. package/dist/collection/index.js +1 -0
  92. package/dist/collection/security.js +27 -0
  93. package/dist/esm/app-globals-0f993ce5.js +3 -0
  94. package/dist/esm/css-shim-10e6e2ae.js +4 -0
  95. package/dist/esm/dom-7cd9cf71.js +73 -0
  96. package/dist/esm/index-5448a818.js +3 -0
  97. package/dist/esm/index-6cfd87e4.js +3 -0
  98. package/dist/esm/index-77bdf1f1.js +3 -0
  99. package/dist/esm/index-a02dcfc8.js +3057 -0
  100. package/dist/esm/index-aa119486.js +3 -0
  101. package/dist/esm/ku4-carousel-controls.entry.js +2 -2
  102. package/dist/esm/ku4-carousel-slide.entry.js +1 -1
  103. package/dist/esm/ku4-carousel.entry.js +3 -3
  104. package/dist/esm/ku4-col.entry.js +1 -1
  105. package/dist/esm/ku4-drawer.entry.js +1 -1
  106. package/dist/esm/ku4-feature.entry.js +2 -2
  107. package/dist/esm/ku4-focus-trap.entry.js +3 -3
  108. package/dist/esm/ku4-form.entry.js +3 -3
  109. package/dist/esm/ku4-grid.entry.js +1 -1
  110. package/dist/esm/ku4-label.entry.js +2 -2
  111. package/dist/esm/ku4-mask.entry.js +3 -3
  112. package/dist/esm/ku4-modal.entry.js +3 -3
  113. package/dist/esm/ku4-panel.entry.js +1 -1
  114. package/dist/esm/ku4-preview.entry.js +34 -5
  115. package/dist/esm/ku4-tab-list.entry.js +4 -4
  116. package/dist/esm/ku4-tab-panel.entry.js +3 -3
  117. package/dist/esm/ku4-tab.entry.js +3 -3
  118. package/dist/esm/ku4-table.entry.js +1 -1
  119. package/dist/esm/ku4-tooltip.entry.js +2 -2
  120. package/dist/esm/ku4-validation.entry.js +2 -2
  121. package/dist/esm/ku4web-components.js +101 -6
  122. package/dist/esm/loader.js +17 -1
  123. package/dist/esm/uid-3716c2c4.js +9 -0
  124. package/dist/esm/{uid-fbebccfd.js → uid-d593801c.js} +1 -1
  125. package/dist/esm-es5/index-5448a818.js +1 -0
  126. package/dist/esm-es5/index-77bdf1f1.js +1 -0
  127. package/dist/esm-es5/ku4-carousel-controls.entry.js +1 -1
  128. package/dist/esm-es5/ku4-carousel.entry.js +1 -1
  129. package/dist/esm-es5/ku4-feature.entry.js +1 -1
  130. package/dist/esm-es5/ku4-focus-trap.entry.js +1 -1
  131. package/dist/esm-es5/ku4-form.entry.js +1 -1
  132. package/dist/esm-es5/ku4-label.entry.js +1 -1
  133. package/dist/esm-es5/ku4-mask.entry.js +1 -1
  134. package/dist/esm-es5/ku4-modal.entry.js +1 -1
  135. package/dist/esm-es5/ku4-preview.entry.js +1 -1
  136. package/dist/esm-es5/ku4-tab-list.entry.js +1 -1
  137. package/dist/esm-es5/ku4-tab-panel.entry.js +1 -1
  138. package/dist/esm-es5/ku4-tab.entry.js +1 -1
  139. package/dist/esm-es5/ku4-tooltip.entry.js +1 -1
  140. package/dist/esm-es5/ku4-validation.entry.js +1 -1
  141. package/dist/esm-es5/uid-d593801c.js +1 -0
  142. package/dist/index.js +1 -1
  143. package/dist/ku4web-components/app-globals-0f993ce5.js +3 -0
  144. package/dist/ku4web-components/app-globals-497eb362.system.js +1 -0
  145. package/dist/ku4web-components/css-shim-10e6e2ae.js +4 -0
  146. package/dist/ku4web-components/css-shim-c8dd4551.system.js +1 -0
  147. package/dist/ku4web-components/dom-67d1e45e.system.js +21 -0
  148. package/dist/ku4web-components/dom-7cd9cf71.js +73 -0
  149. package/dist/ku4web-components/index-1c93827a.system.js +1 -0
  150. package/dist/ku4web-components/index-29f2b09f.system.js +1 -0
  151. package/dist/ku4web-components/index-5d0cb00d.system.js +1 -0
  152. package/dist/ku4web-components/index-6cfd87e4.js +3 -0
  153. package/dist/ku4web-components/index-a02dcfc8.js +3057 -0
  154. package/dist/ku4web-components/index-aa119486.js +3 -0
  155. package/dist/ku4web-components/index.esm.js +1 -0
  156. package/dist/ku4web-components/index.system.js +1 -0
  157. package/dist/ku4web-components/ku4-carousel-controls.entry.js +89 -0
  158. package/dist/ku4web-components/ku4-carousel-controls.system.entry.js +1 -0
  159. package/dist/ku4web-components/ku4-carousel-slide.entry.js +47 -0
  160. package/dist/ku4web-components/ku4-carousel-slide.system.entry.js +1 -0
  161. package/dist/ku4web-components/ku4-carousel.entry.js +175 -0
  162. package/dist/ku4web-components/ku4-carousel.system.entry.js +1 -0
  163. package/dist/ku4web-components/ku4-col.entry.js +75 -0
  164. package/dist/ku4web-components/ku4-col.system.entry.js +1 -0
  165. package/dist/ku4web-components/ku4-drawer.entry.js +35 -0
  166. package/dist/ku4web-components/ku4-drawer.system.entry.js +1 -0
  167. package/dist/ku4web-components/ku4-feature.entry.js +29 -0
  168. package/dist/ku4web-components/ku4-feature.system.entry.js +1 -0
  169. package/dist/ku4web-components/ku4-focus-trap.entry.js +323 -0
  170. package/dist/ku4web-components/ku4-focus-trap.system.entry.js +1 -0
  171. package/dist/ku4web-components/ku4-form.entry.js +120 -0
  172. package/dist/ku4web-components/ku4-form.system.entry.js +1 -0
  173. package/dist/ku4web-components/ku4-grid.entry.js +108 -0
  174. package/dist/ku4web-components/ku4-grid.system.entry.js +1 -0
  175. package/dist/ku4web-components/ku4-label.entry.js +70 -0
  176. package/dist/ku4web-components/ku4-label.system.entry.js +1 -0
  177. package/dist/ku4web-components/ku4-mask.entry.js +343 -0
  178. package/dist/ku4web-components/ku4-mask.system.entry.js +1 -0
  179. package/dist/ku4web-components/ku4-modal.entry.js +80 -0
  180. package/dist/ku4web-components/ku4-modal.system.entry.js +1 -0
  181. package/dist/ku4web-components/ku4-panel.entry.js +49 -0
  182. package/dist/ku4web-components/ku4-panel.system.entry.js +1 -0
  183. package/dist/ku4web-components/ku4-preview.entry.js +128 -0
  184. package/dist/ku4web-components/ku4-preview.system.entry.js +1 -0
  185. package/dist/ku4web-components/ku4-tab-list.entry.js +76 -0
  186. package/dist/ku4web-components/ku4-tab-list.system.entry.js +1 -0
  187. package/dist/ku4web-components/ku4-tab-panel.entry.js +72 -0
  188. package/dist/ku4web-components/ku4-tab-panel.system.entry.js +1 -0
  189. package/dist/ku4web-components/ku4-tab.entry.js +63 -0
  190. package/dist/ku4web-components/ku4-tab.system.entry.js +1 -0
  191. package/dist/ku4web-components/ku4-table.entry.js +79 -0
  192. package/dist/ku4web-components/ku4-table.system.entry.js +1 -0
  193. package/dist/ku4web-components/ku4-tooltip.entry.js +120 -0
  194. package/dist/ku4web-components/ku4-tooltip.system.entry.js +1 -0
  195. package/dist/ku4web-components/ku4-validation.entry.js +162 -0
  196. package/dist/ku4web-components/ku4-validation.system.entry.js +1 -0
  197. package/dist/ku4web-components/ku4web-components.css +299 -1
  198. package/dist/ku4web-components/ku4web-components.esm.js +129 -1
  199. package/dist/ku4web-components/ku4web-components.js +1 -1
  200. package/dist/ku4web-components/ku4web-components.system.js +1 -0
  201. package/dist/ku4web-components/{p-c6a2f4ba.entry.js → p-046b3990.entry.js} +1 -1
  202. package/dist/ku4web-components/{p-018d598f.entry.js → p-0b777b57.entry.js} +1 -1
  203. package/dist/ku4web-components/p-0de744b1.system.js +1 -0
  204. package/dist/ku4web-components/{p-c760ec1e.system.entry.js → p-0f1646ca.system.entry.js} +1 -1
  205. package/dist/ku4web-components/p-14752b72.system.js +1 -0
  206. package/dist/ku4web-components/{p-5d39e051.system.entry.js → p-17c2a7ac.system.entry.js} +1 -1
  207. package/dist/ku4web-components/{p-536d6073.entry.js → p-1abe6f26.entry.js} +1 -1
  208. package/dist/ku4web-components/{p-7bac5d20.system.entry.js → p-1e19bc01.system.entry.js} +1 -1
  209. package/dist/ku4web-components/{p-dfc33643.system.entry.js → p-27647af0.system.entry.js} +1 -1
  210. package/dist/ku4web-components/p-2ee63f57.system.js +1 -1
  211. package/dist/ku4web-components/{p-973be48d.system.entry.js → p-3deab7f6.system.entry.js} +1 -1
  212. package/dist/ku4web-components/{p-23b35ab3.system.entry.js → p-4ecd9b1d.system.entry.js} +1 -1
  213. package/dist/ku4web-components/p-563d1517.system.js +1 -0
  214. package/dist/ku4web-components/p-5a54ccf4.js +1 -0
  215. package/dist/ku4web-components/{p-2681e152.system.entry.js → p-5e8921ef.system.entry.js} +1 -1
  216. package/dist/ku4web-components/{p-6459c75c.system.entry.js → p-6509d3e7.system.entry.js} +1 -1
  217. package/dist/ku4web-components/p-791e2dfc.js +1 -0
  218. package/dist/ku4web-components/{p-4a012d6d.entry.js → p-7b6ca6a8.entry.js} +1 -1
  219. package/dist/ku4web-components/{p-ec165afd.system.entry.js → p-7b93a362.system.entry.js} +1 -1
  220. package/dist/ku4web-components/{p-2faea8a9.system.entry.js → p-8173d389.system.entry.js} +1 -1
  221. package/dist/ku4web-components/{p-13c90d3d.system.entry.js → p-96033515.system.entry.js} +1 -1
  222. package/dist/ku4web-components/{p-e7d401cc.system.entry.js → p-9778d082.system.entry.js} +1 -1
  223. package/dist/ku4web-components/{p-09fb8c34.entry.js → p-9b01a63a.entry.js} +1 -1
  224. package/dist/ku4web-components/p-a110d244.js +1 -0
  225. package/dist/ku4web-components/{p-ff9db3e7.entry.js → p-ac7884f3.entry.js} +1 -1
  226. package/dist/ku4web-components/{p-ce600370.system.entry.js → p-ae7ce1fe.system.entry.js} +1 -1
  227. package/dist/ku4web-components/{p-be0d8b6a.entry.js → p-b1680ef4.entry.js} +1 -1
  228. package/dist/ku4web-components/{p-2f1425ac.entry.js → p-bb5410b5.entry.js} +1 -1
  229. package/dist/ku4web-components/{p-cbee5388.system.entry.js → p-bb698020.system.entry.js} +1 -1
  230. package/dist/ku4web-components/{p-eed33b36.entry.js → p-d42bd64d.entry.js} +1 -1
  231. package/dist/ku4web-components/{p-7a3871e3.entry.js → p-d4877fdf.entry.js} +1 -1
  232. package/dist/ku4web-components/{p-1ebea98a.entry.js → p-da8a8b83.entry.js} +1 -1
  233. package/dist/ku4web-components/{p-507093a6.entry.js → p-de3b2ba1.entry.js} +1 -1
  234. package/dist/ku4web-components/{p-e020ee68.entry.js → p-e11fbd79.entry.js} +1 -1
  235. package/dist/ku4web-components/{p-991d53c6.entry.js → p-ea1961f5.entry.js} +1 -1
  236. package/dist/ku4web-components/shadow-css-38a1326b.js +388 -0
  237. package/dist/ku4web-components/shadow-css-7fde17ac.system.js +13 -0
  238. package/dist/ku4web-components/uid-2ed9f227.system.js +1 -0
  239. package/dist/ku4web-components/uid-3716c2c4.js +9 -0
  240. package/package.json +8 -8
  241. package/react/index.js +1 -1
  242. package/react/index.mjs +1 -1
  243. package/vue/index.js +1 -1
  244. package/vue/index.mjs +1 -1
  245. package/vue3/index.js +1 -1
  246. package/vue3/index.mjs +1 -1
  247. package/dist/cjs/index-57e2cfa5.js +0 -10
  248. package/dist/cjs/index-b46d22c6.js +0 -14
  249. package/dist/esm/index-919b08e6.js +0 -3
  250. package/dist/esm/index-f9890388.js +0 -3
  251. package/dist/esm-es5/index-919b08e6.js +0 -1
  252. package/dist/esm-es5/index-f9890388.js +0 -1
  253. package/dist/esm-es5/uid-fbebccfd.js +0 -1
  254. package/dist/ku4web-components/p-16f6027a.js +0 -1
  255. package/dist/ku4web-components/p-50ea6684.js +0 -1
  256. package/dist/ku4web-components/p-c38c9cd1.system.js +0 -1
  257. package/dist/ku4web-components/p-cbb6fb91.js +0 -1
  258. package/dist/ku4web-components/p-e9770900.system.js +0 -1
  259. package/dist/ku4web-components/p-f8a2bf9b.system.js +0 -1
@@ -0,0 +1,441 @@
1
+ import { Component, Prop, Method, Watch, Element, h } from '@stencil/core';
2
+ import { Assert, deduplicate } from 'ku4es-kernel';
3
+ import { Event, Key } from 'ku4es-ui-kernel';
4
+ import { ariaHidden } from '../../capabilities/a11y/aria';
5
+ import isFocusable from '../../capabilities/dom/isFocusable';
6
+ import { queryTabbable, queryFocusable } from '../../capabilities/dom/queryFocusable';
7
+ const { tab } = Key;
8
+ const tabShift = Key.tab.shift;
9
+ const tabAlt = Key.tab.alt;
10
+ const tabAltShift = Key.tab.alt.shift;
11
+ /**
12
+ * @description ku4-focus-trap
13
+ */
14
+ export class Ku4FocusTrap {
15
+ constructor() {
16
+ this.iframes = [];
17
+ /**
18
+ * Focus trap will be active when true.
19
+ */
20
+ this.active = false;
21
+ this.handleKeyDown = this.handleKeyDown.bind(this);
22
+ this.handleKeyUp = this.handleKeyUp.bind(this);
23
+ this.handleMouse = this.handleMouse.bind(this);
24
+ }
25
+ activeHandler(value) {
26
+ value ? this.handleActivate() : this.handleDeactivate();
27
+ }
28
+ /**
29
+ * Activate focus trap
30
+ * @param {Element} [element] - Element to return focus to when trap is deactivated.
31
+ */
32
+ async activate(element) {
33
+ this.lastActiveElement = element || document.querySelector(this.return || null);
34
+ this.active = true;
35
+ }
36
+ /**
37
+ * Deactivate focus trap.
38
+ */
39
+ async deactivate() {
40
+ this.active = false;
41
+ }
42
+ handleActivate() {
43
+ this.lastActiveElement = this.lastActiveElement || document.activeElement;
44
+ if (this.lastActiveElement && this.lastActiveElement.blur) {
45
+ this.lastActiveElement.blur();
46
+ }
47
+ this.addEventListeners(this.elements);
48
+ ariaHidden(this.outerElements, true);
49
+ window.requestAnimationFrame(() => {
50
+ const element = (document.querySelector(this.initial || null) ||
51
+ this.focusableElements[0] ||
52
+ this.trapElements[0]);
53
+ element.blur();
54
+ element.focus();
55
+ this.activateTraps();
56
+ });
57
+ }
58
+ handleDeactivate() {
59
+ this.removeEventListeners(this.elements);
60
+ this.deactivateTraps();
61
+ ariaHidden(this.outerElements);
62
+ if (this.lastActiveElement && this.lastActiveElement.focus) {
63
+ this.lastActiveElement.focus();
64
+ }
65
+ this.lastActiveElement = null;
66
+ }
67
+ // Handles keydown and mutes the event if it occurs on a focusable
68
+ // item that is in the focus trap. This allows this block to force
69
+ // the decision as to who will get next focus and not let that
70
+ // decisioning fall out to the browser.
71
+ handleKeyDown(e) {
72
+ if ((tabShift.didFire(e) || tabAltShift.didFire(e))) {
73
+ try {
74
+ if (this.iframes.length > 0 && (this.trapElements[1] === e.target ||
75
+ !Assert.isNull(e.target.getAttribute('ku4-focus-wrap')) ||
76
+ this.iframes.some(iframe => iframe.contains(e.target)))) {
77
+ return;
78
+ }
79
+ if (this.trapElements[0] === e.target) {
80
+ this.trapElements[1].focus();
81
+ return Event.mute(e);
82
+ }
83
+ const nextIndex = this.focusableElements.indexOf(e.target) - 1;
84
+ const next = nextIndex < 0 ? this.focusableElements.length - 1 : nextIndex;
85
+ this.focusableElements[next].focus();
86
+ return Event.mute(e);
87
+ }
88
+ catch (e) {
89
+ return Event.mute(e);
90
+ }
91
+ }
92
+ if ((tab.didFire(e) || tabAlt.didFire(e))) {
93
+ try {
94
+ if (this.iframes.length > 0 && (this.trapElements[0] === e.target ||
95
+ !Assert.isNull(e.target.getAttribute('ku4-focus-wrap')) ||
96
+ this.iframes.some(iframe => iframe.contains(e.target)))) {
97
+ return;
98
+ }
99
+ if (this.trapElements[1] === e.target) {
100
+ this.trapElements[0].focus();
101
+ return Event.mute(e);
102
+ }
103
+ const nextIndex = this.focusableElements.indexOf(e.target) + 1;
104
+ const next = nextIndex >= this.focusableElements.length ? 0 : nextIndex;
105
+ this.focusableElements[next].focus();
106
+ return Event.mute(e);
107
+ }
108
+ catch (e) {
109
+ return Event.mute(e);
110
+ }
111
+ }
112
+ }
113
+ // Handles keyup and mutes the event if it occurs on a focusable
114
+ // item that is in the focus trap. This allows for us to determine
115
+ // if we need to move to the next focusable if the key is released
116
+ // on one of the trapElements (the two dynamically created wrapper
117
+ // elements that create the trap);
118
+ handleKeyUp(e) {
119
+ const index = this.trapElements.indexOf(e.target);
120
+ if (index === 0 && (tabShift.didFire(e) || tabAltShift.didFire(e))) {
121
+ const element = this.focusableElements[this.focusableElements.length - 1] || this.trapElements[1];
122
+ element.focus();
123
+ return Event.mute(e);
124
+ }
125
+ if (index === 1 && (tab.didFire(e) || tabAlt.didFire(e))) {
126
+ const element = this.focusableElements[0] || this.trapElements[0];
127
+ element.focus();
128
+ return Event.mute(e);
129
+ }
130
+ }
131
+ // Prevents all mouse activity on any elements that are not focusable
132
+ // inside of the active trap.
133
+ handleMouse(e) {
134
+ if (!this.elements.some(element => element === e.target)) {
135
+ Event.mute(e);
136
+ }
137
+ }
138
+ addEventListeners(elements) {
139
+ elements.forEach(element => element.addEventListener('keydown', this.handleKeyDown, { passive: true }));
140
+ elements.forEach(element => element.addEventListener('keyup', this.handleKeyUp, { passive: true }));
141
+ window.addEventListener('click', this.handleMouse, { passive: true });
142
+ window.addEventListener('mousedown', this.handleMouse, { passive: true });
143
+ window.addEventListener('mouseup', this.handleMouse, { passive: true });
144
+ window.addEventListener('touchstart', this.handleMouse, { passive: true });
145
+ }
146
+ removeEventListeners(elements) {
147
+ elements.forEach(element => element.removeEventListener('keydown', this.handleKeyDown, true));
148
+ elements.forEach(element => element.removeEventListener('keyup', this.handleKeyUp, true));
149
+ window.removeEventListener('click', this.handleMouse, true);
150
+ window.removeEventListener('mousedown', this.handleMouse, true);
151
+ window.removeEventListener('mouseup', this.handleMouse, true);
152
+ window.addEventListener('touchstart', this.handleMouse, true);
153
+ }
154
+ activateTraps() {
155
+ this.setTraps(0);
156
+ }
157
+ deactivateTraps() {
158
+ this.setTraps(-1);
159
+ }
160
+ setTraps(value) {
161
+ [].slice.call(this.host.querySelectorAll('[ku4-focus-trap], [ku4-focus-wrap]'))
162
+ .forEach(element => element.setAttribute('tabindex', value));
163
+ }
164
+ wrap(element) {
165
+ const fragment = document.createDocumentFragment();
166
+ fragment.appendChild(this.createWrapTag());
167
+ fragment.appendChild(element.cloneNode());
168
+ fragment.appendChild(this.createWrapTag());
169
+ element.parentNode.replaceChild(fragment, element);
170
+ }
171
+ createTrapTag() {
172
+ return this.createTag('ku4-focus-trap');
173
+ }
174
+ createWrapTag() {
175
+ return this.createTag('ku4-focus-wrap');
176
+ }
177
+ createTag(type) {
178
+ const trap = document.createElement('button');
179
+ trap.setAttribute(type, '');
180
+ trap.setAttribute('tabindex', '0');
181
+ trap.setAttribute('aria-hidden', 'true');
182
+ trap.style.position = 'static';
183
+ trap.style.display = 'block';
184
+ trap.style.width = '0';
185
+ trap.style.height = '0';
186
+ trap.style.margin = '0';
187
+ trap.style.padding = '0';
188
+ trap.style.border = 'none';
189
+ trap.style.outline = 'none';
190
+ return trap;
191
+ }
192
+ initialize() {
193
+ // All elements in this focus-trap
194
+ const innerElements = [].slice.call(this.host.querySelectorAll('*'));
195
+ // May need to break this out as it is really included for the mouse events
196
+ // e.g. for an overlay on a modal to make that clickable that is make it
197
+ // so this does not include it for muting the mouse events. This component
198
+ // is very powerful in shutting everything down and needs to allow for
199
+ // the ability to let items be clickable.
200
+ const inclusions = [].slice.call(document.querySelectorAll(this.include || null) || []);
201
+ // May need to break this out as it is really here to explicitly exclude items from
202
+ // being read out by screen readers. That is make them hidden so that screen
203
+ // readers get the same treatment as regular users.
204
+ const exclusions = [].slice.call(document.querySelectorAll(this.exclude) || []);
205
+ let shadowExclusions = [];
206
+ (this.excludeShadow || '').split(',').forEach((selector) => {
207
+ if (Assert.isNullOrEmpty(selector)) {
208
+ return;
209
+ }
210
+ try {
211
+ const parts = selector.trim().replace(/\s/, '|').split('|');
212
+ const shadowElements = document.querySelector(parts[0]).shadowRoot.querySelectorAll(parts[1]);
213
+ shadowExclusions = shadowExclusions.concat([].slice.call(shadowElements || []));
214
+ }
215
+ catch (e) {
216
+ // eslint-disable-next-line no-console
217
+ console.error('Invalid shadow selector', selector);
218
+ }
219
+ });
220
+ // Get all of the iframes as we cannot reach into them to find
221
+ // their focusable elements. We can only focus on the trap elements
222
+ // that wrap it
223
+ this.iframes = [].slice.call(this.host.querySelectorAll('iframe') || []);
224
+ this.iframes.forEach(iframe => this.wrap(iframe));
225
+ // Set element in this trap deduplicating any that may have been duplicated
226
+ // with careless user inclusions.
227
+ this.elements = deduplicate([...queryTabbable(this.host), ...inclusions]);
228
+ // Get the focusable elements. This may be overkill as we really only need
229
+ // to know the first and last focusable. If that is the case, we may be
230
+ // able to just use the first and last `this.element` it is still not clear.
231
+ this.focusableElements = this.elements
232
+ .reduce((acc, value) => {
233
+ if (isFocusable(value) && !this.trapElements.includes(value)) {
234
+ acc.push(value);
235
+ }
236
+ return acc;
237
+ }, []);
238
+ /**
239
+ * We can not currently do this this way because MSEdge
240
+ * is reordering querySelectorAll items such that they
241
+ * not selecting in DOM order. If/when we dump support
242
+ * for MSEdge (non Chromium) or it fixes support we
243
+ * can move to this more efficient way. Until then, we
244
+ * need to use the && condition .includes in the
245
+ * `reduce` above. It will be more efficient to do it
246
+ * the below way when we can.
247
+ */
248
+ // this.focusableElements.shift();
249
+ // this.focusableElements.pop();
250
+ //This may need to be defied more specifically as a11y as it is needed
251
+ //for the screen reader capabilities and may be interfering with
252
+ //regular usage.
253
+ this.outerElements = [...queryFocusable(document.body), ...exclusions, ...shadowExclusions]
254
+ .filter(element => !(element === this.host ||
255
+ innerElements.includes(element) ||
256
+ inclusions.includes(element)));
257
+ }
258
+ componentDidLoad() {
259
+ const trapStart = this.createTrapTag();
260
+ const trapEnd = this.createTrapTag();
261
+ this.trapElements = [trapStart, trapEnd];
262
+ this.host.insertBefore(trapStart, this.host.firstChild);
263
+ this.host.appendChild(trapEnd);
264
+ this.initialize();
265
+ if (this.active) {
266
+ this.handleActivate();
267
+ }
268
+ else {
269
+ this.handleDeactivate();
270
+ }
271
+ }
272
+ disconnectedCallback() {
273
+ if (this.active) {
274
+ this.handleDeactivate();
275
+ }
276
+ }
277
+ render() {
278
+ return h("slot", null);
279
+ }
280
+ static get is() { return "ku4-focus-trap"; }
281
+ static get encapsulation() { return "shadow"; }
282
+ static get originalStyleUrls() { return {
283
+ "$": ["ku4-focus-trap.scss"]
284
+ }; }
285
+ static get styleUrls() { return {
286
+ "$": ["ku4-focus-trap.css"]
287
+ }; }
288
+ static get properties() { return {
289
+ "active": {
290
+ "type": "boolean",
291
+ "mutable": true,
292
+ "complexType": {
293
+ "original": "boolean",
294
+ "resolved": "boolean",
295
+ "references": {}
296
+ },
297
+ "required": false,
298
+ "optional": false,
299
+ "docs": {
300
+ "tags": [],
301
+ "text": "Focus trap will be active when true."
302
+ },
303
+ "attribute": "active",
304
+ "reflect": true,
305
+ "defaultValue": "false"
306
+ },
307
+ "include": {
308
+ "type": "string",
309
+ "mutable": false,
310
+ "complexType": {
311
+ "original": "string",
312
+ "resolved": "string",
313
+ "references": {}
314
+ },
315
+ "required": false,
316
+ "optional": false,
317
+ "docs": {
318
+ "tags": [],
319
+ "text": "A querySelector of elements to include in the trap that\nare not children of this focus trap. This can be useful\nfor specific situations such as modal overlays."
320
+ },
321
+ "attribute": "include",
322
+ "reflect": false
323
+ },
324
+ "exclude": {
325
+ "type": "string",
326
+ "mutable": false,
327
+ "complexType": {
328
+ "original": "string",
329
+ "resolved": "string",
330
+ "references": {}
331
+ },
332
+ "required": false,
333
+ "optional": false,
334
+ "docs": {
335
+ "tags": [],
336
+ "text": "A querySelector of elements to explicitly exclude. This\ncan be useful for greedy accessibility apis and screen\nreader fallover. Pass a comma delimited string of multiple\nselectors to target multiple exclusions."
337
+ },
338
+ "attribute": "exclude",
339
+ "reflect": false
340
+ },
341
+ "excludeShadow": {
342
+ "type": "string",
343
+ "mutable": false,
344
+ "complexType": {
345
+ "original": "string",
346
+ "resolved": "string",
347
+ "references": {}
348
+ },
349
+ "required": false,
350
+ "optional": false,
351
+ "docs": {
352
+ "tags": [],
353
+ "text": "A querySelector of shadow elements to explicitly exclude. This\ncan be useful for greedy accessibility apis and screen\nreader fallover. Pass a comma delimited string of multiple\nselectors to target multiple exclusions. Pass selectors that\nstarts with the target components host lightDom element\nE.g. `'ku4-carousel .next, ku4-carousel .prev'` will explicitly\nexclude the target ku4-carousel next and previous buttons from\nbeing navigable by greedy accessibility tools, i.e. VoiceOver."
354
+ },
355
+ "attribute": "exclude-shadow",
356
+ "reflect": false
357
+ },
358
+ "initial": {
359
+ "type": "string",
360
+ "mutable": false,
361
+ "complexType": {
362
+ "original": "string",
363
+ "resolved": "string",
364
+ "references": {}
365
+ },
366
+ "required": false,
367
+ "optional": false,
368
+ "docs": {
369
+ "tags": [],
370
+ "text": "A querySelector of element to initially focus"
371
+ },
372
+ "attribute": "initial",
373
+ "reflect": false
374
+ },
375
+ "return": {
376
+ "type": "string",
377
+ "mutable": false,
378
+ "complexType": {
379
+ "original": "string",
380
+ "resolved": "string",
381
+ "references": {}
382
+ },
383
+ "required": false,
384
+ "optional": false,
385
+ "docs": {
386
+ "tags": [],
387
+ "text": "A querySelector of element to return focus to"
388
+ },
389
+ "attribute": "return",
390
+ "reflect": false
391
+ }
392
+ }; }
393
+ static get methods() { return {
394
+ "activate": {
395
+ "complexType": {
396
+ "signature": "(element?: any) => Promise<void>",
397
+ "parameters": [{
398
+ "tags": [{
399
+ "name": "param",
400
+ "text": "element - Element to return focus to when trap is deactivated."
401
+ }],
402
+ "text": "- Element to return focus to when trap is deactivated."
403
+ }],
404
+ "references": {
405
+ "Promise": {
406
+ "location": "global"
407
+ }
408
+ },
409
+ "return": "Promise<void>"
410
+ },
411
+ "docs": {
412
+ "text": "Activate focus trap",
413
+ "tags": [{
414
+ "name": "param",
415
+ "text": "element - Element to return focus to when trap is deactivated."
416
+ }]
417
+ }
418
+ },
419
+ "deactivate": {
420
+ "complexType": {
421
+ "signature": "() => Promise<void>",
422
+ "parameters": [],
423
+ "references": {
424
+ "Promise": {
425
+ "location": "global"
426
+ }
427
+ },
428
+ "return": "Promise<void>"
429
+ },
430
+ "docs": {
431
+ "text": "Deactivate focus trap.",
432
+ "tags": []
433
+ }
434
+ }
435
+ }; }
436
+ static get elementRef() { return "host"; }
437
+ static get watchers() { return [{
438
+ "propName": "active",
439
+ "methodName": "activeHandler"
440
+ }]; }
441
+ }
@@ -0,0 +1,265 @@
1
+ import { Component, Method, Element, h, Prop, Event } from '@stencil/core';
2
+ import { Assert, wait } from 'ku4es-kernel';
3
+ import { form } from 'ku4es-ui-kernel';
4
+ /**
5
+ * @description ku4-form
6
+ */
7
+ export class Ku4Form {
8
+ constructor() {
9
+ this.validate = this.validate.bind(this);
10
+ this.handleReset = this.handleReset.bind(this);
11
+ }
12
+ /**
13
+ * Returns a list of the names of all of the fields
14
+ * associated with this form.
15
+ */
16
+ async listFieldNames() {
17
+ return form.readFieldNames(this.form);
18
+ }
19
+ /**
20
+ * Validates this form. This method is automatically called
21
+ * internally on submit of the form only allowing a successful
22
+ * submit if the form is valid.
23
+ */
24
+ async validate() {
25
+ const { fields } = this;
26
+ const methods = fields.map(field => field.validate());
27
+ this.isValid = await Promise.all(methods).then(values => !values.some(v => v === false));
28
+ this.valid = this.isValid;
29
+ this.invalid = !this.isValid;
30
+ await wait(100)
31
+ .then(() => this.host.querySelectorAll('ku4-validation[invalid]'))
32
+ .then(invalid => this.didValidate.emit({ invalid }));
33
+ return this.isValid;
34
+ }
35
+ /**
36
+ * A string of the name of the field to invalidate
37
+ * @param {string} name
38
+ */
39
+ async invalidate(name) {
40
+ if (Assert.isArray(name)) {
41
+ name.forEach((name) => {
42
+ const field = this.fields.find(field => field.for === name);
43
+ if (field) {
44
+ field.invalid = true;
45
+ }
46
+ });
47
+ }
48
+ else {
49
+ const field = this.fields.find(field => field.for === name);
50
+ if (field) {
51
+ field.invalid = true;
52
+ }
53
+ }
54
+ this.isValid = false;
55
+ this.valid = this.isValid;
56
+ this.invalid = !this.isValid;
57
+ return this;
58
+ }
59
+ /**
60
+ * Reads data from the associated form
61
+ */
62
+ async read() {
63
+ return form.read(this.form);
64
+ }
65
+ /**
66
+ * Writes data to the associated form
67
+ */
68
+ async write(data) {
69
+ form.write(this.form, data);
70
+ Object.keys(data).forEach((name) => {
71
+ try {
72
+ this.form.querySelector(`[name="${name}"]`)
73
+ .dispatchEvent(new window.Event('change'));
74
+ }
75
+ catch (e) {
76
+ /* Fail silently */
77
+ }
78
+ });
79
+ return this;
80
+ }
81
+ get form() {
82
+ return this.host.querySelector('form');
83
+ }
84
+ get fields() {
85
+ return [].slice.call(this.form.querySelectorAll('ku4-validation'));
86
+ }
87
+ handleReset() {
88
+ this.isValid = true;
89
+ this.valid = this.isValid;
90
+ this.invalid = !this.isValid;
91
+ }
92
+ componentWillLoad() {
93
+ const { form } = this;
94
+ if (Assert.exists(form)) {
95
+ const onsubmit = form.onsubmit || (() => { });
96
+ form.onsubmit = (e) => {
97
+ e.preventDefault();
98
+ this.validate()
99
+ .then(valid => valid && onsubmit.call(form, e))
100
+ .then(returnValue => !Assert.isFalse(returnValue) && form.submit());
101
+ return false;
102
+ };
103
+ form.addEventListener('reset', this.handleReset);
104
+ this.fields.forEach(field => field.addEventListener('validated', this.validate));
105
+ }
106
+ }
107
+ disconnectedCallback() {
108
+ const { form } = this;
109
+ if (Assert.exists(form)) {
110
+ form.removeEventListener('reset', this.handleReset);
111
+ this.fields.forEach(field => field.removeEventListener('validated', this.validate));
112
+ }
113
+ }
114
+ render() {
115
+ return h("slot", null);
116
+ }
117
+ static get is() { return "ku4-form"; }
118
+ static get properties() { return {
119
+ "valid": {
120
+ "type": "boolean",
121
+ "mutable": true,
122
+ "complexType": {
123
+ "original": "boolean",
124
+ "resolved": "boolean",
125
+ "references": {}
126
+ },
127
+ "required": false,
128
+ "optional": false,
129
+ "docs": {
130
+ "tags": [],
131
+ "text": ""
132
+ },
133
+ "attribute": "valid",
134
+ "reflect": false
135
+ },
136
+ "invalid": {
137
+ "type": "boolean",
138
+ "mutable": true,
139
+ "complexType": {
140
+ "original": "boolean",
141
+ "resolved": "boolean",
142
+ "references": {}
143
+ },
144
+ "required": false,
145
+ "optional": false,
146
+ "docs": {
147
+ "tags": [],
148
+ "text": "Set to true to display as invalid"
149
+ },
150
+ "attribute": "invalid",
151
+ "reflect": true
152
+ }
153
+ }; }
154
+ static get events() { return [{
155
+ "method": "didValidate",
156
+ "name": "validate",
157
+ "bubbles": true,
158
+ "cancelable": true,
159
+ "composed": true,
160
+ "docs": {
161
+ "tags": [],
162
+ "text": "Event fired when this form validates."
163
+ },
164
+ "complexType": {
165
+ "original": "any",
166
+ "resolved": "any",
167
+ "references": {}
168
+ }
169
+ }]; }
170
+ static get methods() { return {
171
+ "listFieldNames": {
172
+ "complexType": {
173
+ "signature": "() => Promise<any>",
174
+ "parameters": [],
175
+ "references": {
176
+ "Promise": {
177
+ "location": "global"
178
+ }
179
+ },
180
+ "return": "Promise<any>"
181
+ },
182
+ "docs": {
183
+ "text": "Returns a list of the names of all of the fields\nassociated with this form.",
184
+ "tags": []
185
+ }
186
+ },
187
+ "validate": {
188
+ "complexType": {
189
+ "signature": "() => Promise<any>",
190
+ "parameters": [],
191
+ "references": {
192
+ "Promise": {
193
+ "location": "global"
194
+ }
195
+ },
196
+ "return": "Promise<any>"
197
+ },
198
+ "docs": {
199
+ "text": "Validates this form. This method is automatically called\ninternally on submit of the form only allowing a successful\nsubmit if the form is valid.",
200
+ "tags": []
201
+ }
202
+ },
203
+ "invalidate": {
204
+ "complexType": {
205
+ "signature": "(name: any) => Promise<this>",
206
+ "parameters": [{
207
+ "tags": [{
208
+ "name": "param",
209
+ "text": "name"
210
+ }],
211
+ "text": ""
212
+ }],
213
+ "references": {
214
+ "Promise": {
215
+ "location": "global"
216
+ }
217
+ },
218
+ "return": "Promise<this>"
219
+ },
220
+ "docs": {
221
+ "text": "A string of the name of the field to invalidate",
222
+ "tags": [{
223
+ "name": "param",
224
+ "text": "name"
225
+ }]
226
+ }
227
+ },
228
+ "read": {
229
+ "complexType": {
230
+ "signature": "() => Promise<any>",
231
+ "parameters": [],
232
+ "references": {
233
+ "Promise": {
234
+ "location": "global"
235
+ }
236
+ },
237
+ "return": "Promise<any>"
238
+ },
239
+ "docs": {
240
+ "text": "Reads data from the associated form",
241
+ "tags": []
242
+ }
243
+ },
244
+ "write": {
245
+ "complexType": {
246
+ "signature": "(data: any) => Promise<this>",
247
+ "parameters": [{
248
+ "tags": [],
249
+ "text": ""
250
+ }],
251
+ "references": {
252
+ "Promise": {
253
+ "location": "global"
254
+ }
255
+ },
256
+ "return": "Promise<this>"
257
+ },
258
+ "docs": {
259
+ "text": "Writes data to the associated form",
260
+ "tags": []
261
+ }
262
+ }
263
+ }; }
264
+ static get elementRef() { return "host"; }
265
+ }