@ulu/frontend 0.0.3

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 (323) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/dist/ulu-frontend.min.css +1 -0
  4. package/dist/ulu-frontend.min.js +1 -0
  5. package/index.js +2 -0
  6. package/js/deprecated/doc-ready.js +28 -0
  7. package/js/deprecated/jquery-prototypes.js +309 -0
  8. package/js/deprecated/mini-collapsible-popper-positioning.js +126 -0
  9. package/js/deprecated/mini-collapsible.js +607 -0
  10. package/js/deprecated/script-loader.js +60 -0
  11. package/js/events/index.js +42 -0
  12. package/js/helpers/css-breakpoint.js +247 -0
  13. package/js/helpers/file-save.js +48 -0
  14. package/js/helpers/node-data-manager.js +74 -0
  15. package/js/helpers/pause-youtube-video.js +42 -0
  16. package/js/helpers/scrollbar-width-property.js +10 -0
  17. package/js/index.js +15 -0
  18. package/js/polyfills/element-closest.js +17 -0
  19. package/js/ui/flipcard.js +202 -0
  20. package/js/ui/grid.js +67 -0
  21. package/js/ui/modals.js +219 -0
  22. package/js/ui/overflow-scroller-pager.js +58 -0
  23. package/js/ui/overflow-scroller.js +160 -0
  24. package/js/ui/programmatic-modal.js +91 -0
  25. package/js/ui/resizer.js +60 -0
  26. package/js/ui/slider.js +468 -0
  27. package/js/ui/tabs.js +109 -0
  28. package/js/ui/tooltip.js +82 -0
  29. package/js/utils/array.js +28 -0
  30. package/js/utils/dom.js +122 -0
  31. package/js/utils/logger.js +69 -0
  32. package/js/utils/object.js +22 -0
  33. package/js/utils/performance.js +43 -0
  34. package/js/utils/regex.js +10 -0
  35. package/js/utils/string.js +107 -0
  36. package/js/waypoints/README.md +3 -0
  37. package/js/waypoints/anchor-menu.js +76 -0
  38. package/js/waypoints/element-waypoint.js +75 -0
  39. package/js/waypoints/examples/page-link-menu.md +106 -0
  40. package/js/waypoints/state-in-attribute.js +32 -0
  41. package/package.json +38 -0
  42. package/scss/README.md +58 -0
  43. package/scss/_breakpoint.scss +190 -0
  44. package/scss/_button.scss +241 -0
  45. package/scss/_calculate.scss +64 -0
  46. package/scss/_color.scss +211 -0
  47. package/scss/_cssvar.scss +116 -0
  48. package/scss/_element.scss +276 -0
  49. package/scss/_grid.scss +699 -0
  50. package/scss/_index.scss +29 -0
  51. package/scss/_layout.scss +202 -0
  52. package/scss/_path.scss +58 -0
  53. package/scss/_selector.scss +81 -0
  54. package/scss/_typography.scss +320 -0
  55. package/scss/_units.scss +47 -0
  56. package/scss/_utility.scss +12 -0
  57. package/scss/_utils.scss +209 -0
  58. package/scss/base/_color.scss +13 -0
  59. package/scss/base/_elements.scss +188 -0
  60. package/scss/base/_index.scss +62 -0
  61. package/scss/base/_keyframes.scss +78 -0
  62. package/scss/base/_layout.scss +100 -0
  63. package/scss/base/_normalize.scss +315 -0
  64. package/scss/base/_typography.scss +41 -0
  65. package/scss/components/README.md +5 -0
  66. package/scss/components/README.todos +15 -0
  67. package/scss/components/_button.scss +95 -0
  68. package/scss/components/_index.scss +63 -0
  69. package/scss/components/_links.scss +34 -0
  70. package/scss/components/_list-lines.scss +73 -0
  71. package/scss/components/_list-ordered.scss +16 -0
  72. package/scss/components/_list-unordered.scss +21 -0
  73. package/scss/components/_rule.scss +93 -0
  74. package/scss/helpers/_color.scss +14 -0
  75. package/scss/helpers/_display.scss +73 -0
  76. package/scss/helpers/_index.scss +67 -0
  77. package/scss/helpers/_print.scss +58 -0
  78. package/scss/helpers/_typography.scss +80 -0
  79. package/scss/helpers/_units.scss +79 -0
  80. package/scss/helpers/_utilities.scss +102 -0
  81. package/scss/stylesheets/README.md +3 -0
  82. package/scss/stylesheets/full.scss +17 -0
  83. package/trash/js-old/deprecated/doc-ready.js +28 -0
  84. package/trash/js-old/deprecated/jquery-prototypes.js +309 -0
  85. package/trash/js-old/deprecated/mini-collapsible-popper-positioning.js +126 -0
  86. package/trash/js-old/deprecated/mini-collapsible.js +607 -0
  87. package/trash/js-old/deprecated/script-loader.js +60 -0
  88. package/trash/js-old/events/index.js +42 -0
  89. package/trash/js-old/helpers/css-breakpoint.js +247 -0
  90. package/trash/js-old/helpers/file-save.js +48 -0
  91. package/trash/js-old/helpers/node-data-manager.js +74 -0
  92. package/trash/js-old/helpers/pause-youtube-video.js +42 -0
  93. package/trash/js-old/index.js +15 -0
  94. package/trash/js-old/polyfills/element-closest.js +17 -0
  95. package/trash/js-old/ui/flipcard.js +202 -0
  96. package/trash/js-old/ui/grid.js +67 -0
  97. package/trash/js-old/ui/modals.js +219 -0
  98. package/trash/js-old/ui/programmatic-modal.js +91 -0
  99. package/trash/js-old/ui/resizer.js +60 -0
  100. package/trash/js-old/ui/slider.js +469 -0
  101. package/trash/js-old/ui/tabs.js +109 -0
  102. package/trash/js-old/ui/tooltip.js +82 -0
  103. package/trash/js-old/utils/array.js +28 -0
  104. package/trash/js-old/utils/dom.js +122 -0
  105. package/trash/js-old/utils/logger.js +69 -0
  106. package/trash/js-old/utils/object.js +22 -0
  107. package/trash/js-old/utils/performance.js +43 -0
  108. package/trash/js-old/utils/regex.js +10 -0
  109. package/trash/js-old/utils/string.js +107 -0
  110. package/trash/js-old/waypoints/README.md +3 -0
  111. package/trash/js-old/waypoints/anchor-menu.js +76 -0
  112. package/trash/js-old/waypoints/element-waypoint.js +75 -0
  113. package/trash/js-old/waypoints/examples/page-link-menu.md +106 -0
  114. package/trash/js-old/waypoints/state-in-attribute.js +32 -0
  115. package/trash/js-old-230729/deprecated/doc-ready.js +28 -0
  116. package/trash/js-old-230729/deprecated/jquery-prototypes.js +309 -0
  117. package/trash/js-old-230729/deprecated/mini-collapsible-popper-positioning.js +126 -0
  118. package/trash/js-old-230729/deprecated/mini-collapsible.js +607 -0
  119. package/trash/js-old-230729/deprecated/script-loader.js +60 -0
  120. package/trash/js-old-230729/events/index.js +42 -0
  121. package/trash/js-old-230729/helpers/css-breakpoint.js +247 -0
  122. package/trash/js-old-230729/helpers/file-save.js +48 -0
  123. package/trash/js-old-230729/helpers/node-data-manager.js +74 -0
  124. package/trash/js-old-230729/helpers/pause-youtube-video.js +42 -0
  125. package/trash/js-old-230729/helpers/scrollbar-width-property.js +10 -0
  126. package/trash/js-old-230729/index.js +15 -0
  127. package/trash/js-old-230729/polyfills/element-closest.js +17 -0
  128. package/trash/js-old-230729/ui/flipcard.js +202 -0
  129. package/trash/js-old-230729/ui/grid.js +67 -0
  130. package/trash/js-old-230729/ui/modals.js +219 -0
  131. package/trash/js-old-230729/ui/overflow-scroller-pager.js +58 -0
  132. package/trash/js-old-230729/ui/overflow-scroller.js +160 -0
  133. package/trash/js-old-230729/ui/programmatic-modal.js +91 -0
  134. package/trash/js-old-230729/ui/resizer.js +60 -0
  135. package/trash/js-old-230729/ui/slider.js +468 -0
  136. package/trash/js-old-230729/ui/tabs.js +109 -0
  137. package/trash/js-old-230729/ui/tooltip.js +82 -0
  138. package/trash/js-old-230729/utils/array.js +28 -0
  139. package/trash/js-old-230729/utils/dom.js +122 -0
  140. package/trash/js-old-230729/utils/logger.js +69 -0
  141. package/trash/js-old-230729/utils/object.js +22 -0
  142. package/trash/js-old-230729/utils/performance.js +43 -0
  143. package/trash/js-old-230729/utils/regex.js +10 -0
  144. package/trash/js-old-230729/utils/string.js +107 -0
  145. package/trash/js-old-230729/waypoints/README.md +3 -0
  146. package/trash/js-old-230729/waypoints/anchor-menu.js +76 -0
  147. package/trash/js-old-230729/waypoints/element-waypoint.js +75 -0
  148. package/trash/js-old-230729/waypoints/examples/page-link-menu.md +106 -0
  149. package/trash/js-old-230729/waypoints/state-in-attribute.js +32 -0
  150. package/trash/logo-1.svg +13 -0
  151. package/trash/logo.svg +16 -0
  152. package/trash/scss-before-cqc-update/README.md +58 -0
  153. package/trash/scss-before-cqc-update/_breakpoint.scss +190 -0
  154. package/trash/scss-before-cqc-update/_button.scss +229 -0
  155. package/trash/scss-before-cqc-update/_calculate.scss +65 -0
  156. package/trash/scss-before-cqc-update/_color.scss +211 -0
  157. package/trash/scss-before-cqc-update/_cssvar.scss +116 -0
  158. package/trash/scss-before-cqc-update/_element.scss +275 -0
  159. package/trash/scss-before-cqc-update/_index.scss +29 -0
  160. package/trash/scss-before-cqc-update/_layout.scss +247 -0
  161. package/trash/scss-before-cqc-update/_path.scss +59 -0
  162. package/trash/scss-before-cqc-update/_selector.scss +82 -0
  163. package/trash/scss-before-cqc-update/_typography.scss +322 -0
  164. package/trash/scss-before-cqc-update/_units.scss +48 -0
  165. package/trash/scss-before-cqc-update/_utility.scss +13 -0
  166. package/trash/scss-before-cqc-update/_utils.scss +211 -0
  167. package/trash/scss-before-cqc-update/base/_color.scss +14 -0
  168. package/trash/scss-before-cqc-update/base/_elements.scss +189 -0
  169. package/trash/scss-before-cqc-update/base/_index.scss +63 -0
  170. package/trash/scss-before-cqc-update/base/_keyframes.scss +74 -0
  171. package/trash/scss-before-cqc-update/base/_layout.scss +88 -0
  172. package/trash/scss-before-cqc-update/base/_normalize.scss +316 -0
  173. package/trash/scss-before-cqc-update/base/_typography.scss +42 -0
  174. package/trash/scss-before-cqc-update/components/README.md +5 -0
  175. package/trash/scss-before-cqc-update/components/README.todos +15 -0
  176. package/trash/scss-before-cqc-update/components/_button.scss +96 -0
  177. package/trash/scss-before-cqc-update/components/_grid.scss +671 -0
  178. package/trash/scss-before-cqc-update/components/_index.scss +70 -0
  179. package/trash/scss-before-cqc-update/components/_links.scss +35 -0
  180. package/trash/scss-before-cqc-update/components/_list-lines.scss +74 -0
  181. package/trash/scss-before-cqc-update/components/_list-ordered.scss +17 -0
  182. package/trash/scss-before-cqc-update/components/_list-unordered.scss +22 -0
  183. package/trash/scss-before-cqc-update/components/_rule.scss +94 -0
  184. package/trash/scss-before-cqc-update/helpers/_color.scss +15 -0
  185. package/trash/scss-before-cqc-update/helpers/_display.scss +73 -0
  186. package/trash/scss-before-cqc-update/helpers/_index.scss +68 -0
  187. package/trash/scss-before-cqc-update/helpers/_print.scss +59 -0
  188. package/trash/scss-before-cqc-update/helpers/_typography.scss +73 -0
  189. package/trash/scss-before-cqc-update/helpers/_units.scss +79 -0
  190. package/trash/scss-before-cqc-update/helpers/_utilities.scss +88 -0
  191. package/trash/scss-before-cqc-update/stylesheets/README.md +3 -0
  192. package/trash/scss-before-cqc-update/stylesheets/full.scss +17 -0
  193. package/trash/scss-old/README.md +58 -0
  194. package/trash/scss-old/_breakpoint.scss +140 -0
  195. package/trash/scss-old/_button.scss +223 -0
  196. package/trash/scss-old/_calculate.scss +64 -0
  197. package/trash/scss-old/_color.scss +200 -0
  198. package/trash/scss-old/_element.scss +262 -0
  199. package/trash/scss-old/_grid.scss +558 -0
  200. package/trash/scss-old/_index.scss +25 -0
  201. package/trash/scss-old/_layout.scss +170 -0
  202. package/trash/scss-old/_path.scss +58 -0
  203. package/trash/scss-old/_selector.scss +81 -0
  204. package/trash/scss-old/_typography.scss +320 -0
  205. package/trash/scss-old/_units.scss +47 -0
  206. package/trash/scss-old/_utility.scss +12 -0
  207. package/trash/scss-old/_utils.scss +186 -0
  208. package/trash/scss-old/base/_color.scss +13 -0
  209. package/trash/scss-old/base/_elements.scss +183 -0
  210. package/trash/scss-old/base/_index.scss +62 -0
  211. package/trash/scss-old/base/_keyframes.scss +74 -0
  212. package/trash/scss-old/base/_layout.scss +81 -0
  213. package/trash/scss-old/base/_normalize.scss +316 -0
  214. package/trash/scss-old/base/_typography.scss +42 -0
  215. package/trash/scss-old/components/README.md +5 -0
  216. package/trash/scss-old/components/README.todos +15 -0
  217. package/trash/scss-old/components/_button.scss +74 -0
  218. package/trash/scss-old/components/_index.scss +63 -0
  219. package/trash/scss-old/components/_links.scss +34 -0
  220. package/trash/scss-old/components/_list-lines.scss +73 -0
  221. package/trash/scss-old/components/_list-ordered.scss +16 -0
  222. package/trash/scss-old/components/_list-unordered.scss +21 -0
  223. package/trash/scss-old/components/_rule.scss +84 -0
  224. package/trash/scss-old/helpers/_color.scss +14 -0
  225. package/trash/scss-old/helpers/_display.scss +68 -0
  226. package/trash/scss-old/helpers/_index.scss +67 -0
  227. package/trash/scss-old/helpers/_print.scss +59 -0
  228. package/trash/scss-old/helpers/_typography.scss +73 -0
  229. package/trash/scss-old/helpers/_units.scss +68 -0
  230. package/trash/scss-old/helpers/_utilities.scss +82 -0
  231. package/trash/scss-old/packages/README.md +3 -0
  232. package/trash/scss-old/packages/everything.scss +17 -0
  233. package/trash/scss-old-2/README.md +58 -0
  234. package/trash/scss-old-2/_breakpoint.scss +139 -0
  235. package/trash/scss-old-2/_button.scss +223 -0
  236. package/trash/scss-old-2/_calculate.scss +64 -0
  237. package/trash/scss-old-2/_color.scss +202 -0
  238. package/trash/scss-old-2/_element.scss +263 -0
  239. package/trash/scss-old-2/_grid.scss +558 -0
  240. package/trash/scss-old-2/_index.scss +25 -0
  241. package/trash/scss-old-2/_layout.scss +170 -0
  242. package/trash/scss-old-2/_path.scss +58 -0
  243. package/trash/scss-old-2/_selector.scss +81 -0
  244. package/trash/scss-old-2/_typography.scss +320 -0
  245. package/trash/scss-old-2/_units.scss +47 -0
  246. package/trash/scss-old-2/_utility.scss +12 -0
  247. package/trash/scss-old-2/_utils.scss +186 -0
  248. package/trash/scss-old-2/base/_color.scss +13 -0
  249. package/trash/scss-old-2/base/_elements.scss +182 -0
  250. package/trash/scss-old-2/base/_index.scss +62 -0
  251. package/trash/scss-old-2/base/_keyframes.scss +73 -0
  252. package/trash/scss-old-2/base/_layout.scss +83 -0
  253. package/trash/scss-old-2/base/_normalize.scss +315 -0
  254. package/trash/scss-old-2/base/_typography.scss +41 -0
  255. package/trash/scss-old-2/components/README.md +5 -0
  256. package/trash/scss-old-2/components/README.todos +15 -0
  257. package/trash/scss-old-2/components/_button.scss +95 -0
  258. package/trash/scss-old-2/components/_index.scss +63 -0
  259. package/trash/scss-old-2/components/_links.scss +33 -0
  260. package/trash/scss-old-2/components/_list-lines.scss +73 -0
  261. package/trash/scss-old-2/components/_list-ordered.scss +16 -0
  262. package/trash/scss-old-2/components/_list-unordered.scss +21 -0
  263. package/trash/scss-old-2/components/_rule.scss +84 -0
  264. package/trash/scss-old-2/helpers/_color.scss +14 -0
  265. package/trash/scss-old-2/helpers/_display.scss +67 -0
  266. package/trash/scss-old-2/helpers/_index.scss +67 -0
  267. package/trash/scss-old-2/helpers/_print.scss +58 -0
  268. package/trash/scss-old-2/helpers/_typography.scss +72 -0
  269. package/trash/scss-old-2/helpers/_units.scss +68 -0
  270. package/trash/scss-old-2/helpers/_utilities.scss +81 -0
  271. package/trash/scss-old-2/packages/README.md +3 -0
  272. package/trash/scss-old-2/packages/everything.scss +17 -0
  273. package/trash/scss-old-230729/README.md +58 -0
  274. package/trash/scss-old-230729/_breakpoint.scss +139 -0
  275. package/trash/scss-old-230729/_button.scss +223 -0
  276. package/trash/scss-old-230729/_calculate.scss +64 -0
  277. package/trash/scss-old-230729/_color.scss +202 -0
  278. package/trash/scss-old-230729/_element.scss +273 -0
  279. package/trash/scss-old-230729/_grid.scss +694 -0
  280. package/trash/scss-old-230729/_index.scss +25 -0
  281. package/trash/scss-old-230729/_layout.scss +193 -0
  282. package/trash/scss-old-230729/_path.scss +58 -0
  283. package/trash/scss-old-230729/_selector.scss +81 -0
  284. package/trash/scss-old-230729/_typography.scss +320 -0
  285. package/trash/scss-old-230729/_units.scss +47 -0
  286. package/trash/scss-old-230729/_utility.scss +12 -0
  287. package/trash/scss-old-230729/_utils.scss +186 -0
  288. package/trash/scss-old-230729/base/_color.scss +13 -0
  289. package/trash/scss-old-230729/base/_elements.scss +188 -0
  290. package/trash/scss-old-230729/base/_index.scss +62 -0
  291. package/trash/scss-old-230729/base/_keyframes.scss +73 -0
  292. package/trash/scss-old-230729/base/_layout.scss +83 -0
  293. package/trash/scss-old-230729/base/_normalize.scss +315 -0
  294. package/trash/scss-old-230729/base/_typography.scss +41 -0
  295. package/trash/scss-old-230729/components/README.md +5 -0
  296. package/trash/scss-old-230729/components/README.todos +15 -0
  297. package/trash/scss-old-230729/components/_button.scss +95 -0
  298. package/trash/scss-old-230729/components/_index.scss +63 -0
  299. package/trash/scss-old-230729/components/_links.scss +34 -0
  300. package/trash/scss-old-230729/components/_list-lines.scss +73 -0
  301. package/trash/scss-old-230729/components/_list-ordered.scss +16 -0
  302. package/trash/scss-old-230729/components/_list-unordered.scss +21 -0
  303. package/trash/scss-old-230729/components/_rule.scss +93 -0
  304. package/trash/scss-old-230729/helpers/_color.scss +14 -0
  305. package/trash/scss-old-230729/helpers/_display.scss +73 -0
  306. package/trash/scss-old-230729/helpers/_index.scss +67 -0
  307. package/trash/scss-old-230729/helpers/_print.scss +58 -0
  308. package/trash/scss-old-230729/helpers/_typography.scss +72 -0
  309. package/trash/scss-old-230729/helpers/_units.scss +68 -0
  310. package/trash/scss-old-230729/helpers/_utilities.scss +87 -0
  311. package/trash/scss-old-230729/packages/README.md +3 -0
  312. package/trash/scss-old-230729/packages/everything.scss +17 -0
  313. package/trash/vue/directives/background-image-url.js +12 -0
  314. package/trash/vue/helpers/add-required-components.js +14 -0
  315. package/trash/vue/ui/CollapsibleRegion/CollapsibleRegion.vue +277 -0
  316. package/trash/vue/ui/CollapsibleRegion/Demo.vue +101 -0
  317. package/trash/vue/ui/Dropdown/Dropdown.vue +184 -0
  318. package/trash/vue/ui/Modals/components/Modal.vue +49 -0
  319. package/trash/vue/ui/Modals/components/Modals.vue +103 -0
  320. package/trash/vue/ui/Modals/plugin.js +215 -0
  321. package/trash/vue/ui/Modals/readme.note +10 -0
  322. package/trash/vue/ui/Modals/reference/example-usage.vue +27 -0
  323. package/trash/vue/ui/Modals/reference/wcag-example/dialog.js +324 -0
@@ -0,0 +1,215 @@
1
+ // =============================================================================
2
+ // Vue Modal Plugin
3
+ // =============================================================================
4
+ //
5
+ // Version: 1.0.2
6
+ //
7
+ // Changes: - 1.0.1 | Added rootComponent for access to app root,
8
+ // added ability to pass instance props
9
+ // - 1.0.2 | Added clickOutsideCloses to Modal class (and component close condition)
10
+ //
11
+ // Description: Vue plugin that will add accessible modal features. Will only
12
+ // support dialog modals (aria). Non-dialog modals will be handled
13
+ // separately since they won't display as modals usually.
14
+ //
15
+ // Details: - Exposes global <modal> component
16
+ // - Creates and mounts <modals> container component
17
+ // - Uses a separate Vue instance for the container
18
+ // - Can be configured to mount anywhere in DOM
19
+ // - Has accessibility features to return focus
20
+ //
21
+ // Todo: - Workout how multiple modals would work
22
+ // - Challenge: There is only one component really
23
+ // - Challenge: Will need to store info for previous modal
24
+ // - Can we let the user manage this complexity?
25
+ // - Maybe consider switching to use vue-portal
26
+ // - https://portal-vue.linusb.org/guide/getting-started.html#multiple-portals-one-target
27
+ //
28
+ // Reference:
29
+ // https://www.w3.org/TR/wai-aria-practices/examples/dialog-modal/dialog.html
30
+ // https://www.w3.org/TR/wai-aria-practices/#dialog_modal
31
+ // https://allyjs.io/tutorials/accessible-dialog.html
32
+ // - In this article they mention don't bank on keydown changing the focus only
33
+ // - This article is the most accurate and complete
34
+ // https://snipcart.com/blog/vue-js-plugin
35
+ //
36
+ // Issues: - maintain.tabFocus is removing the focus wring in chrome (not sure why)
37
+ // - Could have to do with how the browser doesn't add focus when the element
38
+ // is focused because of a click?
39
+ //
40
+
41
+ // External
42
+ import maintain from 'ally.js/maintain/_maintain';
43
+ import when from 'ally.js/when/_when';
44
+ import query from 'ally.js/query/_query';
45
+
46
+ // Internal
47
+ import modalsComponent from "./components/Modals.vue";
48
+ import modalComponent from "./components/Modal.vue";
49
+
50
+ class Modals {
51
+ constructor(options) {
52
+ // Pull out users array of modal configurations
53
+ // - we will pass them through the constructor below
54
+ // - No need for the original array
55
+ const modals = options.modals;
56
+ delete options.modals;
57
+
58
+ this.modals = {};
59
+ this.disabledHandler = null;
60
+ this.tabHandler = null;
61
+ this.escapeHandler = null;
62
+ this.rootInstance = null; // User can pass the context of their app this way
63
+ this.root = null;
64
+ Object.assign(this, options);
65
+ this.registerModals(modals);
66
+ }
67
+ /**
68
+ * Passes user modal configuration through the Modal class
69
+ * and maps to an object/lookup table.
70
+ * @param {array} array array of modal configurations
71
+ */
72
+ registerModals(array) {
73
+ array.forEach((modal) => {
74
+ this.modals[modal.name] = new Modal(modal);
75
+ });
76
+ }
77
+ install(Vue, options) {
78
+
79
+ const instanceProperties = options.instanceProperties || {};
80
+ const self = this;
81
+
82
+ // Install the global modals component
83
+ Vue.component('modal', this.modalComponent);
84
+
85
+ // Create a new Vue instance to add reactivity to the
86
+ // data, which will allow the modal component to dynamically
87
+ // switch components when the user open() a modal.
88
+ //
89
+ // User adds modal components to an object, each key is a different modal
90
+ // { ...options, component: vueComponent }
91
+ // similar to how you use the router
92
+ const root = new Vue({
93
+ // Allow the user to add instance properties (like store)
94
+ ...instanceProperties,
95
+ render: createElement => createElement(modalsComponent),
96
+ data: {
97
+ modals: self.modals,
98
+ active: null,
99
+ activeKey: null,
100
+ rootInstance: null,
101
+ returnFocusTo: null
102
+ },
103
+ methods: {
104
+ /**
105
+ * Opens a Modal
106
+ *
107
+ * @param {string} key Key the modal was stored in "modals" object
108
+ * @param {object} options Object of options
109
+ * - @key {Element} closeTo The element that should be focused when the user exits the modal
110
+ * - @key {Function} onOpenBefore Callback before the modal is opened
111
+ * - @key {Function} onOpenAfter Callback when the modal is opened
112
+ * - @key {Function} onCloseBefore Callback before the modal is closed
113
+ * - @key {Function} onCloseAfter Callback when the modal is closed
114
+ * @return {} Unused
115
+ */
116
+ open(key, { returnFocusTo }) {
117
+ this.activeKey = key;
118
+ this.active = this.modals[key];
119
+ this.returnFocusTo = returnFocusTo || null;
120
+ },
121
+ close() {
122
+ const { returnFocusTo, activeKey } = this;
123
+ if (self.disabledHandler) {
124
+ self.disabledHandler.disengage();
125
+ }
126
+ if (self.tabHandler) {
127
+ self.tabHandler.disengage();
128
+ }
129
+ if (self.escapeHandler) {
130
+ self.escapeHandler.disengage();
131
+ }
132
+ this.active = null;
133
+ this.activeKey = null;
134
+ switch (typeof returnFocusTo) {
135
+ case "string":
136
+ const element = document.querySelector(returnFocusTo);
137
+ if (element) {
138
+ element.focus();
139
+ }
140
+ break;
141
+ case "object":
142
+ if (returnFocusTo && returnFocusTo.focus) {
143
+ returnFocusTo.focus();
144
+ }
145
+ break;
146
+ case "function":
147
+ returnFocusTo(activeKey);
148
+ break;
149
+ }
150
+ }
151
+ }
152
+ });
153
+ // Then we mount the vue instance to the Document
154
+ // - Default we choose to add to end of body so that
155
+ // the modals are always the top layer
156
+ root.$mount(this.mountTo());
157
+ // Listen to the modal component to send an event when it's
158
+ // child has mounted > next tick (DOM ready)
159
+ root.$on("modal-mount", () => {
160
+ const context = root.$el;
161
+ // Handlers
162
+ this.disabledHandler = maintain.disabled({ filter: context });
163
+ // this.tabHandler = maintain.tabFocus({ context: context });
164
+ this.escapeHandler = when.key({ escape: root.close.bind(root) });
165
+ // Focus the First
166
+ let element = query.firstTabbable({
167
+ context: context,
168
+ defaultToContext: true,
169
+ });
170
+ // Check if there was a focusable element (if not use the labeledBy Element)
171
+ if (!element) {
172
+ element = context.querySelector('#' + root.active.labeledBy);
173
+ // Make it focusable
174
+ if (element && !element.hasAttribute('tabindex')) {
175
+ element.setAttribute('tabindex', '-1');
176
+ }
177
+ }
178
+ if (element) {
179
+ element.focus();
180
+ }
181
+ });
182
+ // Add a global property to all Vue Instances so they can interact with the
183
+ // modal root instance for things like open and close.
184
+ Vue.prototype.$modals = this.root = root;
185
+ }
186
+ /**
187
+ * Change where the modals container is mounted in the document
188
+ * - User can define their own element in DOM to mount to returned to vm.$mount()
189
+ * @return {element} Return native DOM element
190
+ */
191
+ mountTo() {
192
+ return document.body.appendChild(document.createElement('div'));
193
+ }
194
+ /**
195
+ * Allows the user to assign their app component to a property accessible in the modal components
196
+ */
197
+ setRootInstance(rootInstance) {
198
+ this.root.rootInstance = rootInstance;
199
+ }
200
+ }
201
+ // Defaults (on prototype)
202
+ Modals.prototype.modalComponent = modalComponent; // User can replace the modal template/component
203
+
204
+
205
+ class Modal {
206
+ constructor(config) {
207
+ Object.assign(this, config);
208
+ }
209
+ }
210
+
211
+ // Defaults
212
+ Modal.prototype.labeledBy = "modal__label";
213
+ Modal.prototype.clickOutsideCloses = true;
214
+
215
+ export default Modals;
@@ -0,0 +1,10 @@
1
+ Plan:
2
+ - Setup like vue-router components
3
+ - modal container will show currentModal
4
+ - Like the router shows a component based on URL
5
+ - All modals will be setup using Vue.component()
6
+ - The names will be registered and displayed with modals.open(modalName)
7
+
8
+
9
+ Packages Required:
10
+ "ally.js": "^1.4.1",
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <div>
3
+ <button @click="openModalTest">Open a modal</button>
4
+ <button @click="openModalTest2">Open a modal 2</button>
5
+ </div>
6
+ </template>
7
+
8
+ <script>
9
+ export default {
10
+ name: 'example',
11
+ methods: {
12
+ openModalTest(e) {
13
+ this.$modals.open('backup', {
14
+ returnFocusTo: e.target
15
+ });
16
+ },
17
+ openModalTest2(e) {
18
+ this.$modals.open('preferences', {
19
+ returnFocusTo: e.target
20
+ });
21
+ }
22
+ }
23
+ }
24
+ </script>
25
+
26
+ <style lang="scss">
27
+ </style>
@@ -0,0 +1,324 @@
1
+ /*
2
+ * This content is licensed according to the W3C Software License at
3
+ * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
4
+ */
5
+
6
+ var aria = aria || {};
7
+
8
+ aria.Utils = aria.Utils || {};
9
+
10
+ (function () {
11
+ /*
12
+ * When util functions move focus around, set this true so the focus listener
13
+ * can ignore the events.
14
+ */
15
+ aria.Utils.IgnoreUtilFocusChanges = false;
16
+
17
+ aria.Utils.dialogOpenClass = 'has-dialog';
18
+
19
+ /**
20
+ * @desc Set focus on descendant nodes until the first focusable element is
21
+ * found.
22
+ * @param element
23
+ * DOM node for which to find the first focusable descendant.
24
+ * @returns
25
+ * true if a focusable element is found and focus is set.
26
+ */
27
+ aria.Utils.focusFirstDescendant = function (element) {
28
+ for (var i = 0; i < element.childNodes.length; i++) {
29
+ var child = element.childNodes[i];
30
+ if (aria.Utils.attemptFocus(child) ||
31
+ aria.Utils.focusFirstDescendant(child)) {
32
+ return true;
33
+ }
34
+ }
35
+ return false;
36
+ }; // end focusFirstDescendant
37
+
38
+ /**
39
+ * @desc Find the last descendant node that is focusable.
40
+ * @param element
41
+ * DOM node for which to find the last focusable descendant.
42
+ * @returns
43
+ * true if a focusable element is found and focus is set.
44
+ */
45
+ aria.Utils.focusLastDescendant = function (element) {
46
+ for (var i = element.childNodes.length - 1; i >= 0; i--) {
47
+ var child = element.childNodes[i];
48
+ if (aria.Utils.attemptFocus(child) ||
49
+ aria.Utils.focusLastDescendant(child)) {
50
+ return true;
51
+ }
52
+ }
53
+ return false;
54
+ }; // end focusLastDescendant
55
+
56
+ /**
57
+ * @desc Set Attempt to set focus on the current node.
58
+ * @param element
59
+ * The node to attempt to focus on.
60
+ * @returns
61
+ * true if element is focused.
62
+ */
63
+ aria.Utils.attemptFocus = function (element) {
64
+ if (!aria.Utils.isFocusable(element)) {
65
+ return false;
66
+ }
67
+
68
+ aria.Utils.IgnoreUtilFocusChanges = true;
69
+ try {
70
+ element.focus();
71
+ }
72
+ catch (e) {
73
+ }
74
+ aria.Utils.IgnoreUtilFocusChanges = false;
75
+ return (document.activeElement === element);
76
+ }; // end attemptFocus
77
+
78
+ /* Modals can open modals. Keep track of them with this array. */
79
+ aria.OpenDialogList = aria.OpenDialogList || new Array(0);
80
+
81
+ /**
82
+ * @returns the last opened dialog (the current dialog)
83
+ */
84
+ aria.getCurrentDialog = function () {
85
+ if (aria.OpenDialogList && aria.OpenDialogList.length) {
86
+ return aria.OpenDialogList[aria.OpenDialogList.length - 1];
87
+ }
88
+ };
89
+
90
+ aria.closeCurrentDialog = function () {
91
+ var currentDialog = aria.getCurrentDialog();
92
+ if (currentDialog) {
93
+ currentDialog.close();
94
+ return true;
95
+ }
96
+
97
+ return false;
98
+ };
99
+
100
+ aria.handleEscape = function (event) {
101
+ var key = event.which || event.keyCode;
102
+
103
+ if (key === aria.KeyCode.ESC && aria.closeCurrentDialog()) {
104
+ event.stopPropagation();
105
+ }
106
+ };
107
+
108
+ document.addEventListener('keyup', aria.handleEscape);
109
+
110
+ /**
111
+ * @constructor
112
+ * @desc Dialog object providing modal focus management.
113
+ *
114
+ * Assumptions: The element serving as the dialog container is present in the
115
+ * DOM and hidden. The dialog container has role='dialog'.
116
+ *
117
+ * @param dialogId
118
+ * The ID of the element serving as the dialog container.
119
+ * @param focusAfterClosed
120
+ * Either the DOM node or the ID of the DOM node to focus when the
121
+ * dialog closes.
122
+ * @param focusFirst
123
+ * Optional parameter containing either the DOM node or the ID of the
124
+ * DOM node to focus when the dialog opens. If not specified, the
125
+ * first focusable element in the dialog will receive focus.
126
+ */
127
+ aria.Dialog = function (dialogId, focusAfterClosed, focusFirst) {
128
+ this.dialogNode = document.getElementById(dialogId);
129
+ if (this.dialogNode === null) {
130
+ throw new Error('No element found with id="' + dialogId + '".');
131
+ }
132
+
133
+ var validRoles = ['dialog', 'alertdialog'];
134
+ var isDialog = (this.dialogNode.getAttribute('role') || '')
135
+ .trim()
136
+ .split(/\s+/g)
137
+ .some(function (token) {
138
+ return validRoles.some(function (role) {
139
+ return token === role;
140
+ });
141
+ });
142
+ if (!isDialog) {
143
+ throw new Error(
144
+ 'Dialog() requires a DOM element with ARIA role of dialog or alertdialog.');
145
+ }
146
+
147
+ // Wrap in an individual backdrop element if one doesn't exist
148
+ // Native <dialog> elements use the ::backdrop pseudo-element, which
149
+ // works similarly.
150
+ var backdropClass = 'dialog-backdrop';
151
+ if (this.dialogNode.parentNode.classList.contains(backdropClass)) {
152
+ this.backdropNode = this.dialogNode.parentNode;
153
+ }
154
+ else {
155
+ this.backdropNode = document.createElement('div');
156
+ this.backdropNode.className = backdropClass;
157
+ this.dialogNode.parentNode.insertBefore(this.backdropNode, this.dialogNode);
158
+ this.backdropNode.appendChild(this.dialogNode);
159
+ }
160
+ this.backdropNode.classList.add('active');
161
+
162
+ // Disable scroll on the body element
163
+ document.body.classList.add(aria.Utils.dialogOpenClass);
164
+
165
+ if (typeof focusAfterClosed === 'string') {
166
+ this.focusAfterClosed = document.getElementById(focusAfterClosed);
167
+ }
168
+ else if (typeof focusAfterClosed === 'object') {
169
+ this.focusAfterClosed = focusAfterClosed;
170
+ }
171
+ else {
172
+ throw new Error(
173
+ 'the focusAfterClosed parameter is required for the aria.Dialog constructor.');
174
+ }
175
+
176
+ if (typeof focusFirst === 'string') {
177
+ this.focusFirst = document.getElementById(focusFirst);
178
+ }
179
+ else if (typeof focusFirst === 'object') {
180
+ this.focusFirst = focusFirst;
181
+ }
182
+ else {
183
+ this.focusFirst = null;
184
+ }
185
+
186
+ // Bracket the dialog node with two invisible, focusable nodes.
187
+ // While this dialog is open, we use these to make sure that focus never
188
+ // leaves the document even if dialogNode is the first or last node.
189
+ var preDiv = document.createElement('div');
190
+ this.preNode = this.dialogNode.parentNode.insertBefore(preDiv,
191
+ this.dialogNode);
192
+ this.preNode.tabIndex = 0;
193
+ var postDiv = document.createElement('div');
194
+ this.postNode = this.dialogNode.parentNode.insertBefore(postDiv,
195
+ this.dialogNode.nextSibling);
196
+ this.postNode.tabIndex = 0;
197
+
198
+ // If this modal is opening on top of one that is already open,
199
+ // get rid of the document focus listener of the open dialog.
200
+ if (aria.OpenDialogList.length > 0) {
201
+ aria.getCurrentDialog().removeListeners();
202
+ }
203
+
204
+ this.addListeners();
205
+ aria.OpenDialogList.push(this);
206
+ this.clearDialog();
207
+ this.dialogNode.className = 'default_dialog'; // make visible
208
+
209
+ if (this.focusFirst) {
210
+ this.focusFirst.focus();
211
+ }
212
+ else {
213
+ aria.Utils.focusFirstDescendant(this.dialogNode);
214
+ }
215
+
216
+ this.lastFocus = document.activeElement;
217
+ }; // end Dialog constructor
218
+
219
+ aria.Dialog.prototype.clearDialog = function () {
220
+ Array.prototype.map.call(
221
+ this.dialogNode.querySelectorAll('input'),
222
+ function (input) {
223
+ input.value = '';
224
+ }
225
+ );
226
+ };
227
+
228
+ /**
229
+ * @desc
230
+ * Hides the current top dialog,
231
+ * removes listeners of the top dialog,
232
+ * restore listeners of a parent dialog if one was open under the one that just closed,
233
+ * and sets focus on the element specified for focusAfterClosed.
234
+ */
235
+ aria.Dialog.prototype.close = function () {
236
+ aria.OpenDialogList.pop();
237
+ this.removeListeners();
238
+ aria.Utils.remove(this.preNode);
239
+ aria.Utils.remove(this.postNode);
240
+ this.dialogNode.className = 'hidden';
241
+ this.backdropNode.classList.remove('active');
242
+ this.focusAfterClosed.focus();
243
+
244
+ // If a dialog was open underneath this one, restore its listeners.
245
+ if (aria.OpenDialogList.length > 0) {
246
+ aria.getCurrentDialog().addListeners();
247
+ }
248
+ else {
249
+ document.body.classList.remove(aria.Utils.dialogOpenClass);
250
+ }
251
+ }; // end close
252
+
253
+ /**
254
+ * @desc
255
+ * Hides the current dialog and replaces it with another.
256
+ *
257
+ * @param newDialogId
258
+ * ID of the dialog that will replace the currently open top dialog.
259
+ * @param newFocusAfterClosed
260
+ * Optional ID or DOM node specifying where to place focus when the new dialog closes.
261
+ * If not specified, focus will be placed on the element specified by the dialog being replaced.
262
+ * @param newFocusFirst
263
+ * Optional ID or DOM node specifying where to place focus in the new dialog when it opens.
264
+ * If not specified, the first focusable element will receive focus.
265
+ */
266
+ aria.Dialog.prototype.replace = function (newDialogId, newFocusAfterClosed,
267
+ newFocusFirst) {
268
+ var closedDialog = aria.getCurrentDialog();
269
+ aria.OpenDialogList.pop();
270
+ this.removeListeners();
271
+ aria.Utils.remove(this.preNode);
272
+ aria.Utils.remove(this.postNode);
273
+ this.dialogNode.className = 'hidden';
274
+ this.backdropNode.classList.remove('active');
275
+
276
+ var focusAfterClosed = newFocusAfterClosed || this.focusAfterClosed;
277
+ var dialog = new aria.Dialog(newDialogId, focusAfterClosed, newFocusFirst);
278
+ }; // end replace
279
+
280
+ aria.Dialog.prototype.addListeners = function () {
281
+ document.addEventListener('focus', this.trapFocus, true);
282
+ }; // end addListeners
283
+
284
+ aria.Dialog.prototype.removeListeners = function () {
285
+ document.removeEventListener('focus', this.trapFocus, true);
286
+ }; // end removeListeners
287
+
288
+ aria.Dialog.prototype.trapFocus = function (event) {
289
+ if (aria.Utils.IgnoreUtilFocusChanges) {
290
+ return;
291
+ }
292
+ var currentDialog = aria.getCurrentDialog();
293
+ if (currentDialog.dialogNode.contains(event.target)) {
294
+ currentDialog.lastFocus = event.target;
295
+ }
296
+ else {
297
+ aria.Utils.focusFirstDescendant(currentDialog.dialogNode);
298
+ if (currentDialog.lastFocus == document.activeElement) {
299
+ aria.Utils.focusLastDescendant(currentDialog.dialogNode);
300
+ }
301
+ currentDialog.lastFocus = document.activeElement;
302
+ }
303
+ }; // end trapFocus
304
+
305
+ window.openDialog = function (dialogId, focusAfterClosed, focusFirst) {
306
+ var dialog = new aria.Dialog(dialogId, focusAfterClosed, focusFirst);
307
+ };
308
+
309
+ window.closeDialog = function (closeButton) {
310
+ var topDialog = aria.getCurrentDialog();
311
+ if (topDialog.dialogNode.contains(closeButton)) {
312
+ topDialog.close();
313
+ }
314
+ }; // end closeDialog
315
+
316
+ window.replaceDialog = function (newDialogId, newFocusAfterClosed,
317
+ newFocusFirst) {
318
+ var topDialog = aria.getCurrentDialog();
319
+ if (topDialog.dialogNode.contains(document.activeElement)) {
320
+ topDialog.replace(newDialogId, newFocusAfterClosed, newFocusFirst);
321
+ }
322
+ }; // end replaceDialog
323
+
324
+ }());