@ulu/frontend 0.1.0-beta.5 → 0.1.0-beta.50

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 (296) hide show
  1. package/CHANGELOG.md +382 -0
  2. package/dist/ulu-frontend.min.css +1 -1
  3. package/dist/ulu-frontend.min.js +28 -27
  4. package/docs-dev/assets/main.js +832 -421
  5. package/docs-dev/assets/placeholder/icon-calendar.svg +1 -0
  6. package/docs-dev/assets/placeholder/icon-check.svg +1 -0
  7. package/docs-dev/assets/style.css +629 -233
  8. package/docs-dev/changelog/index.html +0 -0
  9. package/docs-dev/changelog/updates-and-changes/index.html +5109 -0
  10. package/docs-dev/demos/accordion/index.html +0 -4809
  11. package/docs-dev/demos/basic-hero/index.html +0 -0
  12. package/docs-dev/demos/breakpoints-manager/index.html +0 -0
  13. package/docs-dev/demos/button/index.html +0 -4621
  14. package/docs-dev/demos/button-verbose/index.html +0 -0
  15. package/docs-dev/demos/callout/index.html +0 -4661
  16. package/docs-dev/demos/captioned-figure/index.html +0 -4683
  17. package/docs-dev/demos/card/index.html +0 -5040
  18. package/docs-dev/demos/card-grid/index.html +0 -0
  19. package/docs-dev/demos/card-new/index.html +5088 -0
  20. package/docs-dev/demos/card-old/index.html +5223 -0
  21. package/docs-dev/demos/card.1/index.html +5223 -0
  22. package/docs-dev/demos/card.TRASH/index.html +5541 -0
  23. package/docs-dev/demos/counter-list/index.html +0 -0
  24. package/docs-dev/demos/css-icons/index.html +0 -5272
  25. package/docs-dev/demos/data-grid/index.html +0 -5606
  26. package/docs-dev/demos/data-table/index.html +0 -4697
  27. package/docs-dev/demos/details-group/index.html +0 -0
  28. package/docs-dev/demos/file-save/index.html +0 -4672
  29. package/docs-dev/demos/flipcard/index.html +0 -5221
  30. package/docs-dev/demos/form-theme/index.html +0 -4852
  31. package/docs-dev/demos/hero/index.html +0 -301
  32. package/docs-dev/demos/image-grid/index.html +0 -157
  33. package/docs-dev/demos/index.html +0 -4610
  34. package/docs-dev/demos/list-inline/index.html +0 -0
  35. package/docs-dev/demos/list-inline.1/index.html +4727 -0
  36. package/docs-dev/demos/list-lines/index.html +0 -0
  37. package/docs-dev/demos/menu-stack/index.html +0 -4751
  38. package/docs-dev/demos/modals/index.html +0 -4718
  39. package/docs-dev/demos/nav-strip/index.html +0 -4722
  40. package/docs-dev/demos/overlay-section/index.html +0 -4628
  41. package/docs-dev/demos/popovers/index.html +0 -4628
  42. package/docs-dev/demos/print/index.html +0 -4630
  43. package/docs-dev/demos/pull-quote/index.html +0 -4629
  44. package/docs-dev/demos/rule/index.html +0 -4679
  45. package/docs-dev/demos/scroll-slider/index.html +0 -204
  46. package/docs-dev/demos/scrollpoints/index.html +0 -4648
  47. package/docs-dev/demos/slider/index.html +0 -164
  48. package/docs-dev/demos/spoke-spinner/index.html +0 -4625
  49. package/docs-dev/demos/sticky-list/index.html +0 -0
  50. package/docs-dev/demos/tabs/index.html +0 -4714
  51. package/docs-dev/demos/tag/index.html +0 -4630
  52. package/docs-dev/demos/theme-toggle/index.html +0 -0
  53. package/docs-dev/demos/tile-grid-overlay/index.html +0 -382
  54. package/docs-dev/demos/tiles/index.html +0 -4879
  55. package/docs-dev/demos/tooltip/index.html +0 -4658
  56. package/docs-dev/guide/building-stylesheet/index.html +0 -4679
  57. package/docs-dev/guide/developing-ulu-scss-module/index.html +0 -4731
  58. package/docs-dev/guide/index.html +0 -4612
  59. package/docs-dev/guide/updates-and-changes/index.html +5033 -0
  60. package/docs-dev/index.html +0 -4659
  61. package/docs-dev/javascript/events/index.html +0 -4770
  62. package/docs-dev/javascript/index.html +0 -4625
  63. package/docs-dev/javascript/settings/index.html +0 -0
  64. package/docs-dev/javascript/ui-breakpoints/index.html +0 -5070
  65. package/docs-dev/javascript/ui-collapsible/index.html +0 -4737
  66. package/docs-dev/javascript/ui-details-group/index.html +0 -0
  67. package/docs-dev/javascript/ui-dialog/index.html +0 -4771
  68. package/docs-dev/javascript/ui-flipcard/index.html +0 -4621
  69. package/docs-dev/javascript/ui-grid/index.html +0 -4678
  70. package/docs-dev/javascript/ui-modal-builder/index.html +0 -4760
  71. package/docs-dev/javascript/ui-overflow-scroller/index.html +0 -4610
  72. package/docs-dev/javascript/ui-overflow-scroller-pager/index.html +0 -4628
  73. package/docs-dev/javascript/ui-page/index.html +0 -4625
  74. package/docs-dev/javascript/ui-popover/index.html +0 -4664
  75. package/docs-dev/javascript/ui-print/index.html +0 -4677
  76. package/docs-dev/javascript/ui-print-details/index.html +0 -4640
  77. package/docs-dev/javascript/ui-programmatic-modal/index.html +0 -4610
  78. package/docs-dev/javascript/ui-proxy-click/index.html +990 -324
  79. package/docs-dev/javascript/ui-resizer/index.html +901 -320
  80. package/docs-dev/javascript/ui-scroll-slider/index.html +0 -4639
  81. package/docs-dev/javascript/ui-scrollpoint/index.html +0 -4857
  82. package/docs-dev/javascript/ui-slider/index.html +1099 -327
  83. package/docs-dev/javascript/ui-tabs/index.html +914 -370
  84. package/docs-dev/javascript/ui-theme-toggle/index.html +5410 -0
  85. package/docs-dev/javascript/ui-tooltip/index.html +940 -363
  86. package/docs-dev/javascript/utils-class-logger/index.html +901 -320
  87. package/docs-dev/javascript/utils-css/index.html +5224 -0
  88. package/docs-dev/javascript/utils-dom/index.html +1054 -339
  89. package/docs-dev/javascript/utils-file-save/index.html +901 -320
  90. package/docs-dev/javascript/utils-floating-ui/index.html +901 -320
  91. package/docs-dev/javascript/utils-id/index.html +901 -320
  92. package/docs-dev/javascript/utils-pause-youtube-video/index.html +901 -320
  93. package/docs-dev/javascript/utils-system/index.html +5527 -0
  94. package/docs-dev/sass/base/color/index.html +0 -4643
  95. package/docs-dev/sass/base/elements/index.html +0 -4814
  96. package/docs-dev/sass/base/index/index.html +0 -4813
  97. package/docs-dev/sass/base/index.html +0 -4619
  98. package/docs-dev/sass/base/keyframes/index.html +0 -4645
  99. package/docs-dev/sass/base/layout/index.html +0 -4805
  100. package/docs-dev/sass/base/normalize/index.html +0 -4653
  101. package/docs-dev/sass/base/print/index.html +0 -4649
  102. package/docs-dev/sass/base/root/index.html +0 -4669
  103. package/docs-dev/sass/base/typography/index.html +0 -4669
  104. package/docs-dev/sass/components/accordion/index.html +0 -4971
  105. package/docs-dev/sass/components/adaptive-spacing/index.html +0 -4914
  106. package/docs-dev/sass/components/badge/index.html +0 -4862
  107. package/docs-dev/sass/components/basic-hero/index.html +0 -0
  108. package/docs-dev/sass/components/button/index.html +0 -4798
  109. package/docs-dev/sass/components/button-verbose/index.html +0 -4910
  110. package/docs-dev/sass/components/callout/index.html +0 -4937
  111. package/docs-dev/sass/components/captioned-figure/index.html +0 -4788
  112. package/docs-dev/sass/components/card/index.html +0 -5146
  113. package/docs-dev/sass/components/card-grid/index.html +0 -4812
  114. package/docs-dev/sass/components/counter-list/index.html +0 -0
  115. package/docs-dev/sass/components/css-icon/index.html +0 -4909
  116. package/docs-dev/sass/components/data-grid/index.html +0 -5044
  117. package/docs-dev/sass/components/data-table/index.html +0 -4795
  118. package/docs-dev/sass/components/fill-context/index.html +0 -4678
  119. package/docs-dev/sass/components/flipcard/index.html +0 -4948
  120. package/docs-dev/sass/components/flipcard-grid/index.html +0 -4799
  121. package/docs-dev/sass/components/form-theme/index.html +0 -5428
  122. package/docs-dev/sass/components/hero/index.html +0 -4800
  123. package/docs-dev/sass/components/horizontal-rule/index.html +0 -4797
  124. package/docs-dev/sass/components/image-grid/index.html +0 -4804
  125. package/docs-dev/sass/components/index/index.html +0 -4848
  126. package/docs-dev/sass/components/index.html +0 -4619
  127. package/docs-dev/sass/components/links/index.html +0 -4648
  128. package/docs-dev/sass/components/list-inline/index.html +0 -0
  129. package/docs-dev/sass/components/list-lines/index.html +0 -4843
  130. package/docs-dev/sass/components/list-ordered/index.html +0 -4644
  131. package/docs-dev/sass/components/list-unordered/index.html +0 -4648
  132. package/docs-dev/sass/components/menu-stack/index.html +0 -4978
  133. package/docs-dev/sass/components/modal/index.html +0 -5025
  134. package/docs-dev/sass/components/nav-strip/index.html +0 -4898
  135. package/docs-dev/sass/components/overlay-section/index.html +0 -4842
  136. package/docs-dev/sass/components/pager/index.html +0 -4960
  137. package/docs-dev/sass/components/placeholder-block/index.html +0 -4882
  138. package/docs-dev/sass/components/popover/index.html +0 -4957
  139. package/docs-dev/sass/components/pull-quote/index.html +0 -4856
  140. package/docs-dev/sass/components/ratio-box/index.html +0 -4802
  141. package/docs-dev/sass/components/rule/index.html +0 -4804
  142. package/docs-dev/sass/components/scroll-slider/index.html +0 -4915
  143. package/docs-dev/sass/components/skip-link/index.html +0 -4788
  144. package/docs-dev/sass/components/slider/index.html +0 -4924
  145. package/docs-dev/sass/components/spoke-spinner/index.html +0 -4862
  146. package/docs-dev/sass/components/sticky-list/index.html +0 -0
  147. package/docs-dev/sass/components/tabs/index.html +0 -4938
  148. package/docs-dev/sass/components/tag/index.html +0 -4963
  149. package/docs-dev/sass/components/tile-button/index.html +0 -4843
  150. package/docs-dev/sass/components/tile-grid/index.html +0 -4978
  151. package/docs-dev/sass/components/tile-grid-overlay/index.html +0 -4779
  152. package/docs-dev/sass/components/vignette/index.html +0 -4792
  153. package/docs-dev/sass/components/wysiwyg/index.html +0 -4808
  154. package/docs-dev/sass/core/breakpoint/index.html +0 -5401
  155. package/docs-dev/sass/core/button/index.html +0 -5535
  156. package/docs-dev/sass/core/color/index.html +0 -5385
  157. package/docs-dev/sass/core/cssvar/index.html +0 -5410
  158. package/docs-dev/sass/core/element/index.html +0 -5533
  159. package/docs-dev/sass/core/index.html +0 -4608
  160. package/docs-dev/sass/core/layout/index.html +0 -5368
  161. package/docs-dev/sass/core/path/index.html +0 -4777
  162. package/docs-dev/sass/core/selector/index.html +0 -4856
  163. package/docs-dev/sass/core/typography/index.html +0 -5782
  164. package/docs-dev/sass/core/units/index.html +0 -4815
  165. package/docs-dev/sass/core/utils/index.html +0 -6256
  166. package/docs-dev/sass/helpers/color/index.html +0 -4643
  167. package/docs-dev/sass/helpers/display/index.html +0 -4648
  168. package/docs-dev/sass/helpers/index/index.html +0 -4810
  169. package/docs-dev/sass/helpers/index.html +0 -4619
  170. package/docs-dev/sass/helpers/print/index.html +843 -292
  171. package/docs-dev/sass/helpers/typography/index.html +0 -4671
  172. package/docs-dev/sass/helpers/units/index.html +0 -4817
  173. package/docs-dev/sass/helpers/utilities/index.html +0 -4648
  174. package/docs-dev/sass/index.html +0 -4670
  175. package/js/index.js +1 -0
  176. package/js/settings.js +95 -0
  177. package/js/ui/breakpoints.js +19 -16
  178. package/js/ui/collapsible.js +8 -1
  179. package/js/ui/details-group.js +112 -0
  180. package/js/ui/dialog.js +90 -42
  181. package/js/ui/dialog.todo +2 -36
  182. package/js/ui/flipcard.js +37 -57
  183. package/js/ui/grid.js +15 -13
  184. package/js/ui/index.js +1 -0
  185. package/js/ui/modal-builder.js +45 -54
  186. package/js/ui/overflow-scroller.js +6 -4
  187. package/js/ui/popover.js +38 -38
  188. package/js/ui/print.js +16 -25
  189. package/js/ui/programmatic-modal.js +9 -3
  190. package/js/ui/proxy-click.js +50 -36
  191. package/js/ui/scroll-slider.js +24 -30
  192. package/js/ui/scrollpoint.js +28 -64
  193. package/js/ui/slider.js +61 -62
  194. package/js/ui/tabs.js +23 -36
  195. package/js/ui/theme-toggle.js +331 -94
  196. package/js/ui/tooltip.js +27 -32
  197. package/js/utils/css.js +13 -0
  198. package/js/utils/dom.js +85 -8
  199. package/js/utils/font-awesome.js +18 -0
  200. package/js/utils/index.js +2 -1
  201. package/js/utils/system.js +154 -0
  202. package/package.json +14 -8
  203. package/scss/_breakpoint.scss +16 -3
  204. package/scss/_color.scss +37 -5
  205. package/scss/_element.scss +94 -2
  206. package/scss/_layout.scss +7 -8
  207. package/scss/_units.scss +3 -2
  208. package/scss/_utils.scss +248 -13
  209. package/scss/components/README.todos +14 -0
  210. package/scss/components/_accordion.scss +18 -20
  211. package/scss/components/_badge.scss +3 -2
  212. package/scss/components/_basic-hero.scss +112 -0
  213. package/scss/components/_button-verbose.scss +102 -20
  214. package/scss/components/_callout.scss +127 -79
  215. package/scss/components/_captioned-figure.scss +23 -5
  216. package/scss/components/_card-grid.scss +1 -1
  217. package/scss/components/_card.scss +261 -88
  218. package/scss/components/_counter-list.scss +133 -0
  219. package/scss/components/_css-icon.scss +33 -28
  220. package/scss/components/_data-grid.scss +38 -9
  221. package/scss/components/_data-table.scss +44 -4
  222. package/scss/components/_flipcard.scss +21 -15
  223. package/scss/components/_form-theme.scss +146 -135
  224. package/scss/components/_hero.scss +12 -10
  225. package/scss/components/_index.scss +24 -0
  226. package/scss/components/_list-inline.scss +80 -0
  227. package/scss/components/_list-lines.scss +44 -33
  228. package/scss/components/_list-ordered.scss +0 -1
  229. package/scss/components/_menu-stack.scss +42 -26
  230. package/scss/components/_modal.scss +29 -19
  231. package/scss/components/_nav-strip.scss +5 -1
  232. package/scss/components/_overlay-section.scss +4 -6
  233. package/scss/components/_pager.scss +6 -6
  234. package/scss/components/_placeholder-block.scss +4 -4
  235. package/scss/components/_popover.scss +174 -73
  236. package/scss/components/_pull-quote.scss +13 -13
  237. package/scss/components/_ratio-box.scss +2 -5
  238. package/scss/components/_rule.scss +1 -1
  239. package/scss/components/_scroll-slider.scss +2 -6
  240. package/scss/components/_skip-link.scss +2 -1
  241. package/scss/components/_slider.scss +18 -38
  242. package/scss/components/_spoke-spinner.scss +2 -2
  243. package/scss/components/_sticky-list.scss +206 -0
  244. package/scss/components/_tabs.scss +4 -2
  245. package/scss/components/_tag.scss +1 -1
  246. package/scss/components/_vignette.scss +3 -5
  247. package/scss/helpers/_display.scss +15 -18
  248. package/scss/helpers/_print.scss +12 -7
  249. package/scss/helpers/_utilities.scss +42 -32
  250. package/types/index.d.ts +1 -0
  251. package/types/settings.d.ts +66 -0
  252. package/types/settings.d.ts.map +1 -0
  253. package/types/ui/breakpoints.d.ts +14 -14
  254. package/types/ui/breakpoints.d.ts.map +1 -1
  255. package/types/ui/collapsible.d.ts.map +1 -1
  256. package/types/ui/details-group.d.ts +38 -0
  257. package/types/ui/details-group.d.ts.map +1 -0
  258. package/types/ui/dialog.d.ts +20 -14
  259. package/types/ui/dialog.d.ts.map +1 -1
  260. package/types/ui/flipcard.d.ts +16 -10
  261. package/types/ui/flipcard.d.ts.map +1 -1
  262. package/types/ui/grid.d.ts +4 -6
  263. package/types/ui/grid.d.ts.map +1 -1
  264. package/types/ui/index.d.ts +1 -0
  265. package/types/ui/modal-builder.d.ts +8 -11
  266. package/types/ui/modal-builder.d.ts.map +1 -1
  267. package/types/ui/overflow-scroller.d.ts +2 -2
  268. package/types/ui/overflow-scroller.d.ts.map +1 -1
  269. package/types/ui/popover.d.ts +6 -7
  270. package/types/ui/popover.d.ts.map +1 -1
  271. package/types/ui/print.d.ts +0 -4
  272. package/types/ui/print.d.ts.map +1 -1
  273. package/types/ui/programmatic-modal.d.ts.map +1 -1
  274. package/types/ui/proxy-click.d.ts +19 -3
  275. package/types/ui/proxy-click.d.ts.map +1 -1
  276. package/types/ui/scroll-slider.d.ts +5 -7
  277. package/types/ui/scroll-slider.d.ts.map +1 -1
  278. package/types/ui/scrollpoint.d.ts +3 -8
  279. package/types/ui/scrollpoint.d.ts.map +1 -1
  280. package/types/ui/slider.d.ts +24 -14
  281. package/types/ui/slider.d.ts.map +1 -1
  282. package/types/ui/tabs.d.ts +6 -8
  283. package/types/ui/tabs.d.ts.map +1 -1
  284. package/types/ui/theme-toggle.d.ts +51 -7
  285. package/types/ui/theme-toggle.d.ts.map +1 -1
  286. package/types/ui/tooltip.d.ts +3 -5
  287. package/types/ui/tooltip.d.ts.map +1 -1
  288. package/types/utils/css.d.ts +11 -0
  289. package/types/utils/css.d.ts.map +1 -0
  290. package/types/utils/dom.d.ts +45 -6
  291. package/types/utils/dom.d.ts.map +1 -1
  292. package/types/utils/font-awesome.d.ts +5 -0
  293. package/types/utils/font-awesome.d.ts.map +1 -0
  294. package/types/utils/index.d.ts +1 -0
  295. package/types/utils/system.d.ts +113 -0
  296. package/types/utils/system.d.ts.map +1 -0
package/js/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  // - Will not include things that aren't used in every site (those would need to
6
6
  // imported manually
7
7
 
8
+ export * as settings from "./settings.js";
8
9
  export * as events from "./events/index.js";
9
10
  export * as ui from "./ui/index.js";
10
11
  export * as utils from "./utils/index.js";
package/js/settings.js ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @module settings
3
+ * @description Manages shared configuration for the library.
4
+ */
5
+
6
+ /**
7
+ * Default settings
8
+ * @typedef {object} Defaults
9
+ * @property {string} iconClassClose - The CSS class string for the close icon
10
+ * @property {string} iconClassDragX - The CSS class string for the drag X icon
11
+ * @property {string} iconClassPrevious - The CSS class string for the previous icon
12
+ * @property {string} iconClassNext - The CSS class string for the next icon
13
+ * @property {string} cssvarPrefix - The prefix to use for CSS custom properties
14
+ */
15
+
16
+ /**
17
+ * @type {Defaults}
18
+ */
19
+ const defaults = {
20
+ iconClassClose: "css-icon css-icon--close",
21
+ iconClassDragX: "css-icon css-icon--drag-x",
22
+ iconClassPrevious: "css-icon css-icon--angle-left",
23
+ iconClassNext: "css-icon css-icon--angle-right",
24
+ cssvarPrefix: "",
25
+ };
26
+
27
+ // Current configuration, initialized with defaults
28
+ let currentSettings = { ...defaults };
29
+
30
+ /**
31
+ * Retrieves a copy of the default settings.
32
+ * @returns {object} A copy of the default settings object.
33
+ */
34
+ export function getDefaultSettings() {
35
+ return { ...defaults };
36
+ }
37
+
38
+ /**
39
+ * Updates multiple configuration settings.
40
+ * @param {object} changes An object containing the settings to update.
41
+ */
42
+ export function updateSettings(changes) {
43
+ Object.assign(currentSettings, changes);
44
+ }
45
+
46
+ /**
47
+ * Retrieves a copy of the current configuration settings.
48
+ * @returns {object} A copy of the current settings object.
49
+ */
50
+ export function getSettings() {
51
+ return { ...currentSettings };
52
+ }
53
+
54
+ /**
55
+ * Retrieves a specific configuration setting by key.
56
+ * @param {string} key The key of the setting to retrieve.
57
+ * @returns {*} The value of the setting, or undefined if not found.
58
+ */
59
+ export function getSetting(key) {
60
+ if (!currentSettings.hasOwnProperty(key)) {
61
+ console.warn(`Attempted to access non-existent setting: ${key}`);
62
+ return undefined;
63
+ }
64
+ return currentSettings[key];
65
+ }
66
+
67
+ /**
68
+ * Updates a specific configuration setting.
69
+ * @param {string} key The key of the setting to update.
70
+ * @param {*} value The new value for the setting.
71
+ */
72
+ export function updateSetting(key, value) {
73
+ currentSettings[key] = value;
74
+ }
75
+
76
+ /**
77
+ * Creates a wrapped string representation of a configuration setting.
78
+ * This function returns an object with a `toString()` method that, when called,
79
+ * retrieves the current value of the specified setting. This allows the setting
80
+ * to be used as a string literal, dynamically retrieving its value.
81
+ *
82
+ * @param {String} key The key of the setting to wrap.
83
+ * @param {Function} transform Optional function to transform the setting's
84
+ * value when its string representation is requested.
85
+ * @returns {Object} An object with a `toString()` method that returns the
86
+ * (optionally transformed) setting value as a string.
87
+ */
88
+ export function wrapSettingString(key, transform) {
89
+ return {
90
+ toString() {
91
+ const value = getSetting(key);
92
+ return transform ? transform(value) : value;
93
+ }
94
+ };
95
+ }
@@ -5,8 +5,11 @@
5
5
  // Pass breakpoints from CSS to stylesheet, use this to attach behaviors on breakpoints
6
6
  import { removeArrayElement } from "@ulu/utils/array.js";
7
7
  import { getName } from "../events/index.js";
8
+ import { wrapSettingString } from "../settings.js";
9
+ import { getCustomProperty } from "../utils/css.js";
8
10
  import { log, logError } from "../utils/class-logger.js";
9
11
 
12
+ const getDefaultCustomProperty = prefix => getCustomProperty(prefix, "breakpoint");
10
13
 
11
14
  // Resize Handler to update breakpoints for all instances (Called after resize finished)
12
15
  window.addEventListener(getName("pageResized"), () => {
@@ -16,25 +19,26 @@ window.addEventListener(getName("pageResized"), () => {
16
19
  /**
17
20
  * @class
18
21
  * Class that provides method for retrieving and acting on breakpoints passed
19
- * from CSS (using element psuedo content prop)
22
+ * from CSS (using element pseudo content prop)
20
23
  */
21
24
  export class BreakpointManager {
22
25
  static instances = [];
23
26
  static defaults = {
24
27
  element: document?.documentElement,
25
- valueFromPsuedo: false,
28
+ valueFromPseudo: false,
26
29
  customProperty: "--breakpoint",
27
- psuedoSelector: ':before',
30
+ customProperty: wrapSettingString("cssvarPrefix", getDefaultCustomProperty),
31
+ pseudoSelector: ':before',
28
32
  order: ["none", "small", "medium", "large"],
29
33
  debug: false
30
34
  }
31
35
  /**
32
- * @param {Object} config Configruation object
36
+ * @param {Object} config Configuration object
33
37
  * @param {Array} config.order Array of strings that correspond to the breakpoints setup in the styles, Breakpoints from smallest to largest, defaults to [small, medium, large]
34
38
  * @param {Array} config.customProperty Property to grab breakpoint from (default is --breakpoint)
35
- * @param {Array} config.valueFromPsuedo Use the legacy method of grabbing breakpoint from psuedo element, default uses custom property
36
- * @param {Node} config.element The element to retrieve active breakpoint from stylesheet. (default is html) For using the old psuedo method, adjust this to document.body
37
- * @param {String} config.psuedoSelector Change psuedo selector used to get the breakpoint from the psuedo's content property
39
+ * @param {Array} config.valueFromPseudo Use the legacy method of grabbing breakpoint from pseudo element, default uses custom property
40
+ * @param {Node} config.element The element to retrieve active breakpoint from stylesheet. (default is html) For using the old pseudo method, adjust this to document.body
41
+ * @param {String} config.pseudoSelector Change pseudo selector used to get the breakpoint from the pseudo's content property
38
42
  */
39
43
  constructor(config) {
40
44
  Object.assign(this, BreakpointManager.defaults, config);
@@ -51,9 +55,9 @@ export class BreakpointManager {
51
55
  BreakpointManager.instances.push(this);
52
56
  }
53
57
  /**
54
- * Add a callback for everytime a breakpoint changes
58
+ * Add a callback for every time a breakpoint changes
55
59
  * - Not recommended, possibly use to watch for changes, etc
56
- * - For more control use intance.at(name) with breakpoint methods
60
+ * - For more control use instance.at(name) with breakpoint methods
57
61
  * @param {Function} callback Function to call, passed one argument current instance which can be used to get information about breakpoints
58
62
  */
59
63
  onChange(callback) {
@@ -67,10 +71,10 @@ export class BreakpointManager {
67
71
  removeArrayElement(this.onChangeCallbacks, callback);
68
72
  }
69
73
  /**
70
- * Get breakpoint from a psuedo element
74
+ * Get breakpoint from a pseudo element
71
75
  */
72
- getBreakpointInPsuedo() {
73
- return window.getComputedStyle(this.element, this.psuedoSelector).content.replace(/^"|"$/g, '');
76
+ getBreakpointInPseudo() {
77
+ return window.getComputedStyle(this.element, this.pseudoSelector).content.replace(/^"|"$/g, '');
74
78
  }
75
79
  /**
76
80
  * Get breakpoint from a custom property
@@ -82,8 +86,8 @@ export class BreakpointManager {
82
86
  * Get breakpoint from element (design note: user could override prototype)
83
87
  */
84
88
  getBreakpoint() {
85
- if (this.valueFromPsuedo) {
86
- return this.getBreakpointInPsuedo();
89
+ if (this.valueFromPseudo) {
90
+ return this.getBreakpointInPseudo();
87
91
  } else {
88
92
  return this.getBreakpointInProperty();
89
93
  }
@@ -97,9 +101,8 @@ export class BreakpointManager {
97
101
  logError(this, 'Unable to get current breakpoint, maybe order is incorrect? Breakpoint check skipped!');
98
102
  return;
99
103
  }
100
- // console.log('name:\n', name);
101
104
  if (name === this.active) return;
102
- // this.log(`current breakpoint: ${ name }`);
105
+
103
106
  // Update active and cache last
104
107
  this.previous = this.active;
105
108
  this.previousIndex = this.activeIndex;
@@ -71,7 +71,14 @@ export class Collapsible {
71
71
  }
72
72
  this.focusoutHandler = (event) => {
73
73
  if (focusoutCloses) {
74
- this.close(event);
74
+ // If closing on focus out we attach one-time event to
75
+ // see which element is focused next (in between focusout and focusin
76
+ // it's the body) so doing the logic in focusout won't work
77
+ document.addEventListener('focusin', () => {
78
+ if (!content.contains(document.activeElement)) {
79
+ this.close(event);
80
+ }
81
+ }, { once: true });
75
82
  }
76
83
  };
77
84
  trigger.addEventListener("click", this.clickHandler);
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @module ui/details-group
3
+ * @description Manages groups of details (ie. onlyOneOpen at a time)
4
+ */
5
+
6
+ import { ComponentInitializer } from "../utils/system.js";
7
+
8
+ /**
9
+ * Dialog Component Initializer
10
+ */
11
+ export const initializer = new ComponentInitializer({
12
+ type: "details-group",
13
+ baseAttribute: "data-ulu-details-group"
14
+ });
15
+
16
+ const childInitAttr = initializer.getAttribute("child-init");
17
+ const defaults = {
18
+ onlyOneOpen: true,
19
+ childSelector: ":scope > details"
20
+ };
21
+
22
+ /**
23
+ * Initialize everything in document
24
+ * - This will only initialize elements once, it is safe to call on page changes
25
+ */
26
+ export function init() {
27
+ initializer.init({
28
+ withData: true,
29
+ events: ["pageModified"],
30
+ setup({ element, data, initialize }) {
31
+ setupGroup(element, data);
32
+ initialize();
33
+ }
34
+ });
35
+ }
36
+
37
+ /**
38
+ * @typedef {Object} DetailsGroupInstance
39
+ * @property {Function} destroy A function to remove event listeners and attributes.
40
+ * @property {HTMLElement} element The parent element.
41
+ * @property {Function} setupChildren A function to initialize the child details elements.
42
+ */
43
+
44
+ /**
45
+ * Sets up a single group of details elements to manage their behavior.
46
+ * @param {HTMLElement} element - The parent element containing the details elements.
47
+ * @param {Object} options - The options for this group
48
+ * @returns {DetailsGroupInstance}
49
+ */
50
+ export function setupGroup(element, userOptions) {
51
+ const options = Object.assign({}, defaults, userOptions);
52
+
53
+ // Added try because we are using querySelectorAll with :scope by default
54
+ // which will not work in Internet Explorer or early edge (some alt. browsers too)
55
+ try {
56
+ setupChildren();
57
+ } catch(error) {
58
+ console.error(error);
59
+ }
60
+
61
+ /**
62
+ * Queries all current children in element
63
+ * @ignore
64
+ */
65
+ function queryChildren() {
66
+ return element.querySelectorAll(options.childSelector);
67
+ }
68
+
69
+ /**
70
+ * Sets up any children not already setup in group
71
+ */
72
+ function setupChildren() {
73
+ queryChildren().forEach(child => {
74
+ if (child.hasAttribute(childInitAttr)) {
75
+ return;
76
+ } else {
77
+ child.setAttribute(childInitAttr, "");
78
+ }
79
+ child.addEventListener("toggle", toggleHandler);
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Toggle handler for child details element
85
+ * - For things like one open at a time
86
+ * @ignore
87
+ */
88
+ function toggleHandler({ target }) {
89
+ if (options.onlyOneOpen) {
90
+ if (target.open) {
91
+ queryChildren().forEach(child => {
92
+ if (child !== target && child.open) {
93
+ child.open = false;
94
+ }
95
+ });
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Function removes all handlers and init attributes
102
+ */
103
+ function destroy() {
104
+ queryChildren().forEach(child => {
105
+ child.removeEventListener("toggle", toggleHandler);
106
+ child.removeAttribute(childInitAttr);
107
+ });
108
+ element.removeAttribute(initializer.getAttribute("init"));
109
+ }
110
+
111
+ return { destroy, element, setupChildren };
112
+ }
package/js/ui/dialog.js CHANGED
@@ -2,23 +2,24 @@
2
2
  * @module ui/dialog
3
3
  */
4
4
 
5
- import { getName } from "../events/index.js";
6
- import { getDatasetJson, wasClickOutside } from "../utils/dom.js";
5
+ import { ComponentInitializer } from "../utils/system.js";
6
+ import { wasClickOutside, getScrollbarWidth } from "../utils/dom.js";
7
7
  import { pauseVideos as pauseYoutubeVideos, prepVideos as prepYoutubeVideos } from "../utils/pause-youtube-video.js";
8
+
8
9
  /**
9
- * Default data attributes
10
+ * Base attribute for a dialog
10
11
  */
11
- export const attrs = {
12
- init: "data-ulu-dialog-init",
13
- dialog: "data-ulu-dialog",
14
- trigger: "data-ulu-dialog-trigger",
15
- close: "data-ulu-dialog-close",
16
- };
12
+ export const baseAttribute = "data-ulu-dialog"; // Exposed for modal builder
17
13
 
18
- // Utils for selecting things based on attributes
19
- const attrSelector = key => `[${ attrs[key] }]`;
20
- const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
21
- const queryAllInitial = key => document.querySelectorAll(attrSelectorInitial(key));
14
+ /**
15
+ * Dialog Component Initializer
16
+ */
17
+ export const initializer = new ComponentInitializer({ type: "dialog", baseAttribute });
18
+
19
+ /**
20
+ * Attribute for close buttons within a dialog
21
+ */
22
+ export const closeAttribute = initializer.getAttribute("close"); // Exposed for modal builder
22
23
 
23
24
  /**
24
25
  * Dialog Defaults
@@ -42,6 +43,15 @@ export const defaults = {
42
43
  * Whether or not to pause videos when dialog closes (currently just youtube and native)
43
44
  */
44
45
  pauseVideos: true,
46
+ /**
47
+ * When open and not non-modal, the body is prevented from scrolling (defaults to true).
48
+ */
49
+ preventScroll: true,
50
+ /**
51
+ * Compensate for layout shift when preventing scroll. Which adds padding equal to scrollbars
52
+ * width while dialog is open
53
+ */
54
+ preventScrollShift: true,
45
55
  };
46
56
 
47
57
 
@@ -49,7 +59,7 @@ export const defaults = {
49
59
  let currentDefaults = { ...defaults };
50
60
 
51
61
  /**
52
- * @param {Object} options Change options used as default for dialogs, can then be overriden by data attribute settings on element
62
+ * @param {Object} options Change options used as default for dialogs, can then be overridden by data attribute settings on element
53
63
  */
54
64
  export function setDefaults(options) {
55
65
  currentDefaults = Object.assign({}, currentDefaults, options);
@@ -60,35 +70,48 @@ export function setDefaults(options) {
60
70
  * - This will only initialize elements once, it is safe to call on page changes
61
71
  */
62
72
  export function init() {
63
- document.addEventListener(getName("pageModified"), setup);
64
- setup();
65
- }
66
-
67
- /**
68
- * Setup dialogs and triggers
69
- */
70
- export function setup() {
71
- // Then setup all dialogs (including those that were built)
72
- const dialogs = queryAllInitial("dialog");
73
- dialogs.forEach(setupDialog);
74
-
75
- const triggers = queryAllInitial("trigger");
76
- triggers.forEach(setupTrigger);
73
+ // Initialize all the dialogs
74
+ initializer.init({
75
+ events: ["pageModified"],
76
+ withData: true,
77
+ setup({ element, initialize, data }) {
78
+ setupDialog(element, data);
79
+ initialize();
80
+ }
81
+ });
82
+
83
+ // Initialize all triggers (things that trigger opening a dialog)
84
+ initializer.init({
85
+ key: "trigger",
86
+ events: ["pageModified"],
87
+ withData: true,
88
+ setup({ element, initialize, data: dialogId }) {
89
+ setupTrigger(element, dialogId);
90
+ initialize();
91
+ }
92
+ });
77
93
  }
78
94
 
79
95
  /**
80
96
  * Setup click handlers on a trigger
81
- * @param {Node} trigger
97
+ * @param {Node} trigger Trigger button element
98
+ * @param {String} dialogId The dialog's id to open
82
99
  */
83
- export function setupTrigger(trigger) {
100
+ export function setupTrigger(trigger, dialogId) {
84
101
  trigger.addEventListener("click", handleTrigger);
85
- trigger.setAttribute(attrs.init, "");
86
102
 
87
- function handleTrigger() {
88
- const id = trigger.dataset.uluDialogTrigger;
89
- const dialog = document.getElementById(id);
103
+ function handleTrigger(event) {
104
+
105
+ // If a link is used (not recommended) we need to prevent
106
+ // the page from scrolling
107
+ const closestLink = event.target.closest("a");
108
+ if (closestLink) {
109
+ event.preventDefault();
110
+ }
111
+
112
+ const dialog = document.getElementById(dialogId);
90
113
  if (!dialog) {
91
- console.error("Could not locate dialog (id)", id);
114
+ console.error("Could not locate dialog (id)", dialogId);
92
115
  return;
93
116
  }
94
117
  if (dialog?.tagName?.toLowerCase() !== "dialog") {
@@ -104,20 +127,45 @@ export function setupTrigger(trigger) {
104
127
  * Setup click handlers for a dialog
105
128
  * @param {Node} dialog
106
129
  */
107
- export function setupDialog(dialog) {
108
- const options = getDialogOptions(dialog);
130
+ export function setupDialog(dialog, userOptions) {
131
+ const options = Object.assign({}, currentDefaults, userOptions);
132
+ const body = document.body;
133
+
109
134
  dialog.addEventListener("click", handleClicks);
110
- dialog.setAttribute(attrs.init, "");
135
+
111
136
  if (options.documentEnd) {
112
- document.body.appendChild(dialog);
137
+ body.appendChild(dialog);
113
138
  }
114
139
  if (options.pauseVideos) {
115
140
  prepVideos(dialog);
116
141
  }
117
142
 
143
+ // Allow preventScroll if it is a modal dialog
144
+ // Caching value of overflow before setting so we don't assume what it's initial value is
145
+ if (!options.nonModal && options.preventScroll) {
146
+
147
+ let overflowValue = body.style.overflow;
148
+ let paddingRightValue = body.style.paddingRight;
149
+
150
+ dialog.addEventListener("toggle", (event) => {
151
+ const isOpen = event.newState === "open";
152
+ if (isOpen) {
153
+ overflowValue = body.style.overflow;
154
+ paddingRightValue = body.style.paddingRight;
155
+ }
156
+
157
+ // This will compensate for scrollbar jump (if user has it enabled)
158
+ if (options.preventScrollShift) {
159
+ body.style.paddingRight = isOpen ? `${ getScrollbarWidth() }px` : paddingRightValue;
160
+ }
161
+
162
+ body.style.overflow = isOpen ? "hidden" : overflowValue;
163
+ });
164
+ }
165
+
118
166
  function handleClicks(event) {
119
167
  const { target } = event;
120
- const closeFromButton = target.closest("[data-ulu-dialog-close]");
168
+ const closeFromButton = target.closest(initializer.attributeSelector("close"));
121
169
  let closeFromOutside = options.clickOutsideCloses &&
122
170
  target === dialog &&
123
171
  wasClickOutside(dialog, event);
@@ -136,8 +184,7 @@ export function setupDialog(dialog) {
136
184
  * @returns {Object}
137
185
  */
138
186
  export function getDialogOptions(dialog) {
139
- const options = getDatasetJson(dialog, "uluDialog");
140
- return Object.assign({}, currentDefaults, options);
187
+ return Object.assign({}, currentDefaults, initializer.getData(dialog));
141
188
  }
142
189
 
143
190
  /**
@@ -146,6 +193,7 @@ export function getDialogOptions(dialog) {
146
193
  function prepVideos(dialog) {
147
194
  prepYoutubeVideos(dialog);
148
195
  }
196
+
149
197
  /**
150
198
  * Prep videos to be paused for a given dialog
151
199
  */
package/js/ui/dialog.todo CHANGED
@@ -1,37 +1,3 @@
1
- Styling:
2
- ✔ Animations? @done
3
- ☐ Check styling on left right
1
+ Dialog Todos:
4
2
  ☐ Setup fullscreen option / modifier
5
- Setup programmatic modal with new system
6
- ☐ Resizing
7
- ✔ Work out how this can work with native and click outside @done
8
- ✔ Figure out how to setup icon for the resizer for all sites @done
9
- * Fontawesome, or should this just be CSS so we don't need any icons for it
10
- * Same for close button should we just use CSS and omit any FA requirements
11
- * Or make it super easy to implement the icon only in the template (like default icon classses)
12
- * Then user can choose to implement their own (via class) or use the styles that come with it
13
- ☐ Prevent Browser Scroll
14
- ✔ How should height work? Should a centered modal expand to it's content's height (up to the viewport height) or always be cropped and scroll (static height)? @done
15
- Todos:
16
- ✔ How should the relationship between a dialog and it's trigger work @done
17
- * Think there should be no relationship? Just triggers are triggers just attach a handler to open DOM centric way (add errors when the dialog doesn't exist)
18
- * For the dialogs they should just have handlers attached for close
19
- * Init should find all one's that need to be built and build them, then it should initialize them the same way as non-built dialogs
20
- ✔ Support both modal and non-modal dialogs (rename)? @done
21
- ✘ Divide into 4 modules @cancelled
22
- 1. Initializer (data-attributes)
23
- 2. Templater (for Drupal projects and standard modals)
24
- 3. Open/Close Behaviors
25
- 4. Programmatic Modal
26
- * This is tough because its opionated towards our system in Drupal (jQuery)
27
- ✔ How should this all be structured @done
28
- * JS template dialogs?
29
- * Pros
30
- * Many users create the modals in content in CMS we don't want to make that difficult or get stuck with structure
31
- * Cons
32
- * Templating is in JS so dialogs don't make much sense on their own
33
- * Could continue the div to dialog conversion (so modal content is inline unless JS running). Don't want to optimize too much for no js anymore anyways
34
- * writing the dialog by hand makes sense for non defualt modal styles or users that have another structure but need the scripting part
35
- * Solution
36
- * Breakup module into two parts the underlying modal scripting (open close trigger) and (conversion modal templating [w. resizer] and as <div>)
37
- * Then we can have both without any extra code and seperation
3
+ Prevent Browser Scroll