@ulu/frontend 0.1.0-beta.33 → 0.1.0-beta.35

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 (209) hide show
  1. package/CHANGELOG.md +43 -17
  2. package/dist/ulu-frontend.min.css +1 -1
  3. package/dist/ulu-frontend.min.js +23 -23
  4. package/docs-dev/changelog/index.html +105 -10
  5. package/docs-dev/demos/accordion/index.html +30 -0
  6. package/docs-dev/demos/button/index.html +30 -0
  7. package/docs-dev/demos/button-verbose/index.html +30 -0
  8. package/docs-dev/demos/callout/index.html +39 -0
  9. package/docs-dev/demos/captioned-figure/index.html +30 -0
  10. package/docs-dev/demos/card/index.html +44 -14
  11. package/docs-dev/demos/card-grid/index.html +30 -0
  12. package/docs-dev/demos/css-icons/index.html +30 -0
  13. package/docs-dev/demos/data-grid/index.html +30 -0
  14. package/docs-dev/demos/data-table/index.html +55 -25
  15. package/docs-dev/demos/details-group/index.html +63 -0
  16. package/docs-dev/demos/file-save/index.html +30 -0
  17. package/docs-dev/demos/flipcard/index.html +30 -0
  18. package/docs-dev/demos/form-theme/index.html +30 -0
  19. package/docs-dev/demos/index.html +30 -0
  20. package/docs-dev/demos/list-inline/index.html +30 -0
  21. package/docs-dev/demos/list-lines/index.html +30 -0
  22. package/docs-dev/demos/menu-stack/index.html +30 -0
  23. package/docs-dev/demos/modals/index.html +43 -2
  24. package/docs-dev/demos/nav-strip/index.html +30 -0
  25. package/docs-dev/demos/overlay-section/index.html +30 -0
  26. package/docs-dev/demos/popovers/index.html +30 -0
  27. package/docs-dev/demos/print/index.html +30 -0
  28. package/docs-dev/demos/pull-quote/index.html +30 -0
  29. package/docs-dev/demos/rule/index.html +30 -0
  30. package/docs-dev/demos/scrollpoints/index.html +31 -1
  31. package/docs-dev/demos/spoke-spinner/index.html +30 -0
  32. package/docs-dev/demos/sticky-list/index.html +30 -0
  33. package/docs-dev/demos/tabs/index.html +66 -0
  34. package/docs-dev/demos/tag/index.html +30 -0
  35. package/docs-dev/demos/theme-toggle/index.html +30 -0
  36. package/docs-dev/demos/tiles/index.html +30 -0
  37. package/docs-dev/demos/tooltip/index.html +30 -0
  38. package/docs-dev/guide/building-stylesheet/index.html +30 -0
  39. package/docs-dev/guide/developing-ulu-scss-module/index.html +30 -0
  40. package/docs-dev/guide/index.html +30 -0
  41. package/docs-dev/index.html +30 -0
  42. package/docs-dev/javascript/events/index.html +30 -0
  43. package/docs-dev/javascript/index.html +30 -0
  44. package/docs-dev/javascript/settings/index.html +30 -0
  45. package/docs-dev/javascript/ui-breakpoints/index.html +30 -0
  46. package/docs-dev/javascript/ui-collapsible/index.html +30 -0
  47. package/docs-dev/javascript/ui-details-group/index.html +48 -30
  48. package/docs-dev/javascript/ui-dialog/index.html +62 -17
  49. package/docs-dev/javascript/ui-flipcard/index.html +91 -5
  50. package/docs-dev/javascript/ui-grid/index.html +40 -36
  51. package/docs-dev/javascript/ui-modal-builder/index.html +41 -32
  52. package/docs-dev/javascript/ui-overflow-scroller/index.html +30 -0
  53. package/docs-dev/javascript/ui-overflow-scroller-pager/index.html +30 -0
  54. package/docs-dev/javascript/ui-page/index.html +30 -0
  55. package/docs-dev/javascript/ui-popover/index.html +38 -12
  56. package/docs-dev/javascript/ui-print/index.html +30 -8
  57. package/docs-dev/javascript/ui-print-details/index.html +30 -0
  58. package/docs-dev/javascript/ui-programmatic-modal/index.html +30 -0
  59. package/docs-dev/javascript/ui-proxy-click/index.html +117 -2
  60. package/docs-dev/javascript/ui-resizer/index.html +30 -0
  61. package/docs-dev/javascript/ui-scroll-slider/index.html +68 -6
  62. package/docs-dev/javascript/ui-scrollpoint/index.html +36 -13
  63. package/docs-dev/javascript/ui-slider/index.html +226 -5
  64. package/docs-dev/javascript/ui-tabs/index.html +41 -48
  65. package/docs-dev/javascript/ui-theme-toggle/index.html +35 -13
  66. package/docs-dev/javascript/ui-tooltip/index.html +37 -11
  67. package/docs-dev/javascript/utils-class-logger/index.html +30 -0
  68. package/docs-dev/javascript/utils-dom/index.html +55 -0
  69. package/docs-dev/javascript/utils-file-save/index.html +30 -0
  70. package/docs-dev/javascript/utils-floating-ui/index.html +30 -0
  71. package/docs-dev/javascript/utils-id/index.html +30 -0
  72. package/docs-dev/javascript/utils-pause-youtube-video/index.html +30 -0
  73. package/docs-dev/javascript/utils-system/index.html +5437 -0
  74. package/docs-dev/sass/base/color/index.html +30 -0
  75. package/docs-dev/sass/base/elements/index.html +30 -0
  76. package/docs-dev/sass/base/index/index.html +30 -0
  77. package/docs-dev/sass/base/index.html +30 -0
  78. package/docs-dev/sass/base/keyframes/index.html +30 -0
  79. package/docs-dev/sass/base/layout/index.html +30 -0
  80. package/docs-dev/sass/base/normalize/index.html +30 -0
  81. package/docs-dev/sass/base/print/index.html +30 -0
  82. package/docs-dev/sass/base/root/index.html +30 -0
  83. package/docs-dev/sass/base/typography/index.html +30 -0
  84. package/docs-dev/sass/components/accordion/index.html +31 -1
  85. package/docs-dev/sass/components/adaptive-spacing/index.html +30 -0
  86. package/docs-dev/sass/components/badge/index.html +30 -0
  87. package/docs-dev/sass/components/basic-hero/index.html +30 -0
  88. package/docs-dev/sass/components/button/index.html +30 -0
  89. package/docs-dev/sass/components/button-verbose/index.html +30 -0
  90. package/docs-dev/sass/components/callout/index.html +30 -0
  91. package/docs-dev/sass/components/captioned-figure/index.html +30 -0
  92. package/docs-dev/sass/components/card/index.html +30 -0
  93. package/docs-dev/sass/components/card-grid/index.html +30 -0
  94. package/docs-dev/sass/components/css-icon/index.html +30 -0
  95. package/docs-dev/sass/components/data-grid/index.html +30 -0
  96. package/docs-dev/sass/components/data-table/index.html +45 -8
  97. package/docs-dev/sass/components/fill-context/index.html +30 -0
  98. package/docs-dev/sass/components/flipcard/index.html +30 -0
  99. package/docs-dev/sass/components/flipcard-grid/index.html +30 -0
  100. package/docs-dev/sass/components/form-theme/index.html +76 -52
  101. package/docs-dev/sass/components/hero/index.html +30 -0
  102. package/docs-dev/sass/components/horizontal-rule/index.html +30 -0
  103. package/docs-dev/sass/components/image-grid/index.html +30 -0
  104. package/docs-dev/sass/components/index/index.html +30 -0
  105. package/docs-dev/sass/components/index.html +30 -0
  106. package/docs-dev/sass/components/links/index.html +30 -0
  107. package/docs-dev/sass/components/list-inline/index.html +30 -0
  108. package/docs-dev/sass/components/list-lines/index.html +30 -0
  109. package/docs-dev/sass/components/list-ordered/index.html +30 -0
  110. package/docs-dev/sass/components/list-unordered/index.html +30 -0
  111. package/docs-dev/sass/components/menu-stack/index.html +30 -0
  112. package/docs-dev/sass/components/modal/index.html +30 -0
  113. package/docs-dev/sass/components/nav-strip/index.html +30 -0
  114. package/docs-dev/sass/components/overlay-section/index.html +30 -0
  115. package/docs-dev/sass/components/pager/index.html +30 -0
  116. package/docs-dev/sass/components/placeholder-block/index.html +30 -0
  117. package/docs-dev/sass/components/popover/index.html +30 -0
  118. package/docs-dev/sass/components/pull-quote/index.html +30 -0
  119. package/docs-dev/sass/components/ratio-box/index.html +30 -0
  120. package/docs-dev/sass/components/rule/index.html +30 -0
  121. package/docs-dev/sass/components/scroll-slider/index.html +38 -20
  122. package/docs-dev/sass/components/skip-link/index.html +30 -0
  123. package/docs-dev/sass/components/slider/index.html +30 -0
  124. package/docs-dev/sass/components/spoke-spinner/index.html +30 -0
  125. package/docs-dev/sass/components/sticky-list/index.html +30 -0
  126. package/docs-dev/sass/components/tabs/index.html +30 -0
  127. package/docs-dev/sass/components/tag/index.html +30 -0
  128. package/docs-dev/sass/components/tile-button/index.html +30 -0
  129. package/docs-dev/sass/components/tile-grid/index.html +30 -0
  130. package/docs-dev/sass/components/tile-grid-overlay/index.html +30 -0
  131. package/docs-dev/sass/components/vignette/index.html +30 -0
  132. package/docs-dev/sass/components/wysiwyg/index.html +30 -0
  133. package/docs-dev/sass/core/breakpoint/index.html +30 -0
  134. package/docs-dev/sass/core/button/index.html +30 -0
  135. package/docs-dev/sass/core/color/index.html +30 -0
  136. package/docs-dev/sass/core/cssvar/index.html +30 -0
  137. package/docs-dev/sass/core/element/index.html +30 -0
  138. package/docs-dev/sass/core/index.html +30 -0
  139. package/docs-dev/sass/core/layout/index.html +30 -0
  140. package/docs-dev/sass/core/path/index.html +30 -0
  141. package/docs-dev/sass/core/selector/index.html +30 -0
  142. package/docs-dev/sass/core/typography/index.html +30 -0
  143. package/docs-dev/sass/core/units/index.html +30 -0
  144. package/docs-dev/sass/core/utils/index.html +30 -0
  145. package/docs-dev/sass/helpers/color/index.html +30 -0
  146. package/docs-dev/sass/helpers/display/index.html +30 -0
  147. package/docs-dev/sass/helpers/index/index.html +30 -0
  148. package/docs-dev/sass/helpers/index.html +30 -0
  149. package/docs-dev/sass/helpers/print/index.html +30 -0
  150. package/docs-dev/sass/helpers/typography/index.html +30 -0
  151. package/docs-dev/sass/helpers/units/index.html +30 -0
  152. package/docs-dev/sass/helpers/utilities/index.html +30 -0
  153. package/docs-dev/sass/index.html +30 -0
  154. package/js/ui/breakpoints.js +1 -2
  155. package/js/ui/details-group.js +33 -42
  156. package/js/ui/dialog.js +64 -41
  157. package/js/ui/dialog.todo +2 -36
  158. package/js/ui/flipcard.js +37 -57
  159. package/js/ui/grid.js +15 -13
  160. package/js/ui/modal-builder.js +24 -38
  161. package/js/ui/popover.js +38 -39
  162. package/js/ui/print.js +16 -25
  163. package/js/ui/proxy-click.js +50 -36
  164. package/js/ui/scroll-slider.js +24 -30
  165. package/js/ui/scrollpoint.js +27 -63
  166. package/js/ui/slider.js +53 -55
  167. package/js/ui/tabs.js +23 -36
  168. package/js/ui/theme-toggle.js +37 -41
  169. package/js/ui/tooltip.js +27 -33
  170. package/js/utils/dom.js +12 -0
  171. package/js/utils/system.js +154 -0
  172. package/package.json +1 -1
  173. package/scss/components/_accordion.scss +1 -2
  174. package/scss/components/_data-table.scss +3 -0
  175. package/scss/components/_form-theme.scss +24 -25
  176. package/scss/components/_scroll-slider.scss +0 -4
  177. package/types/ui/breakpoints.d.ts.map +1 -1
  178. package/types/ui/details-group.d.ts +7 -12
  179. package/types/ui/details-group.d.ts.map +1 -1
  180. package/types/ui/dialog.d.ts +19 -14
  181. package/types/ui/dialog.d.ts.map +1 -1
  182. package/types/ui/flipcard.d.ts +16 -10
  183. package/types/ui/flipcard.d.ts.map +1 -1
  184. package/types/ui/grid.d.ts +4 -6
  185. package/types/ui/grid.d.ts.map +1 -1
  186. package/types/ui/modal-builder.d.ts +5 -9
  187. package/types/ui/modal-builder.d.ts.map +1 -1
  188. package/types/ui/popover.d.ts +6 -7
  189. package/types/ui/popover.d.ts.map +1 -1
  190. package/types/ui/print.d.ts +0 -4
  191. package/types/ui/print.d.ts.map +1 -1
  192. package/types/ui/proxy-click.d.ts +19 -3
  193. package/types/ui/proxy-click.d.ts.map +1 -1
  194. package/types/ui/scroll-slider.d.ts +5 -7
  195. package/types/ui/scroll-slider.d.ts.map +1 -1
  196. package/types/ui/scrollpoint.d.ts +3 -8
  197. package/types/ui/scrollpoint.d.ts.map +1 -1
  198. package/types/ui/slider.d.ts +22 -12
  199. package/types/ui/slider.d.ts.map +1 -1
  200. package/types/ui/tabs.d.ts +6 -8
  201. package/types/ui/tabs.d.ts.map +1 -1
  202. package/types/ui/theme-toggle.d.ts +6 -13
  203. package/types/ui/theme-toggle.d.ts.map +1 -1
  204. package/types/ui/tooltip.d.ts +3 -5
  205. package/types/ui/tooltip.d.ts.map +1 -1
  206. package/types/utils/dom.d.ts +6 -0
  207. package/types/utils/dom.d.ts.map +1 -1
  208. package/types/utils/system.d.ts +113 -0
  209. package/types/utils/system.d.ts.map +1 -0
package/js/ui/slider.js CHANGED
@@ -5,19 +5,20 @@
5
5
  // Slider
6
6
  // =============================================================================
7
7
 
8
- // Version: 1.0.10
8
+ // Version: 1.0.11
9
9
 
10
10
  // Changes:
11
+ // 1.0.11 | Updates for ComponentInitializer
11
12
  // 1.0.10 | Fix bug when two and going in reverse
12
- // 1.0.9 | Fix bug when there are only 2 slides (not sliding correctly [revesers because of switchSlide])
13
- // this is addressed now and should slide infinitly between two slides
14
- // 1.0.8 | Change API, to elements object (from individaul arguments),
13
+ // 1.0.9 | Fix bug when there are only 2 slides (not sliding correctly [reverse because of switchSlide])
14
+ // this is addressed now and should slide infinity between two slides
15
+ // 1.0.8 | Change API, to elements object (from individual arguments),
15
16
  // Add the ability to specify the element to append controls within
16
17
  // 1.0.6 | Add transition class for changes during transition,
17
18
  // add will-change to the transition
18
- // 1.0.5 | Fix transtion event difference on windows, convert all
19
+ // 1.0.5 | Fix transition event difference on windows, convert all
19
20
  // async stuff to promises and simplify
20
- // 1.0.4 | Remove live region annoucement (only used if auto rotate)
21
+ // 1.0.4 | Remove live region announcement (only used if auto rotate)
21
22
 
22
23
  // Reference: https://www.w3.org/WAI/tutorials/carousels/working-example/
23
24
  // https://www.w3.org/TR/wai-aria-practices/examples/carousel/carousel-1.html#
@@ -27,17 +28,28 @@
27
28
  // https://dev.opera.com/articles/css-will-change-property/
28
29
  // * Will Change use
29
30
 
31
+ import { ComponentInitializer } from "../utils/system.js";
30
32
  import { wrapSettingString } from "../settings.js";
31
33
  import maintain from 'ally.js/maintain/_maintain';
32
34
  import { hasRequiredProps } from '@ulu/utils/object.js';
33
35
  import { trimWhitespace } from "@ulu/utils/string.js";
34
36
  import { debounce } from "@ulu/utils/performance.js";
35
37
  import { log, logError, logWarning } from "../utils/class-logger.js";
36
- import { getDatasetOptionalJson } from "../utils/dom.js";
37
- import { createPager } from "./overflow-scroller-pager.js";
38
- import { getName } from "../events/index.js";
39
38
 
40
- const debugMode = false; // Global dev debug
39
+ /**
40
+ * Slider Component Initializer
41
+ */
42
+ export const initializer = new ComponentInitializer({
43
+ type: "slider",
44
+ baseAttribute: "data-ulu-slider"
45
+ });
46
+
47
+ const attrSelectorTrack = initializer.attributeSelector("track");
48
+ const attrSelectorTrackContainer = initializer.attributeSelector("track-container");
49
+ const attrSelectorControlContext = initializer.attributeSelector("control-context");
50
+ const attrSelectorSlide = initializer.attributeSelector("slide");
51
+
52
+ const instances = [];
41
53
  const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
42
54
  const eventOnce = { once: true };
43
55
  const cssDuration = d => `${ d }ms`;
@@ -57,52 +69,34 @@ const requiredElements = [
57
69
  ];
58
70
 
59
71
  /**
60
- * Default data attributes
72
+ * Initialize all sliders based on data attribute selectors
61
73
  */
62
- export const attrs = {
63
- init: "data-ulu-slider-init",
64
- slider: "data-ulu-slider",
65
- track: "data-ulu-slider-track",
66
- trackContainer: "data-ulu-slider-track-container",
67
- controls: "data-ulu-slider-control-context"
68
- };
69
-
70
- // Utils for selecting things based on attributes
71
- const attrSelector = key => `[${ attrs[key] }]`;
72
- const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
73
-
74
- const defaults = {
75
- amount: createPager()
76
- };
77
-
78
- const instances = [];
79
-
80
74
  export function init() {
81
- document.addEventListener(getName("pageModified"), setup);
82
- setup();
83
- }
84
-
85
- export function setup() {
86
- const builders = document.querySelectorAll(attrSelectorInitial("slider"));
87
- builders.forEach(setupSlider);
75
+ initializer.init({
76
+ withData: true,
77
+ events: ["pageModified"],
78
+ setup({ element, data, initialize }) {
79
+ setupSlider(element, data);
80
+ initialize();
81
+ }
82
+ });
88
83
  }
89
84
 
90
- export function setupSlider(container) {
91
- container.setAttribute(attrs.init, "");
92
- const options = getDatasetOptionalJson(container, "uluScrollSlider");
93
- const config = Object.assign({}, defaults, options);
85
+ /**
86
+ * Setup single slider instance from querying via data attribute selectors
87
+ * @param {Node} container The slide container to query children from
88
+ * @param {Object} options Options for slider class
89
+ */
90
+ export function setupSlider(container, options) {
91
+ const config = Object.assign({}, options);
94
92
  const elements = {
95
93
  container,
96
- track: container.querySelector("[data-ulu-slider-track]"),
97
- trackContainer: container.querySelector("[data-ulu-slider-track-container]"),
98
- controlContext: container.querySelector("[data-ulu-slider-control-context]"),
99
- slides: container.querySelectorAll("[data-ulu-slider-slide]")
94
+ track: container.querySelector(attrSelectorTrack),
95
+ trackContainer: container.querySelector(attrSelectorTrackContainer),
96
+ controlContext: container.querySelector(attrSelectorControlContext),
97
+ slides: container.querySelectorAll(attrSelectorSlide)
100
98
  };
101
- // Add in any global settings
102
- // Object.assign(config, {
103
- // callbacks: {}
104
- // });
105
- // /
99
+
106
100
  // This was added because there was an issue on the new windows, need to test this
107
101
  // config.transitionFade = true;
108
102
  if (elements.slides.length) {
@@ -110,8 +104,14 @@ export function setupSlider(container) {
110
104
  }
111
105
  }
112
106
 
107
+ /**
108
+ * Class that controls slider
109
+ */
113
110
  export class Slider {
114
111
  static instances = [];
112
+ /**
113
+ * Default options for slider
114
+ */
115
115
  static defaults = {
116
116
  classAccessiblyHidden: "hidden-visually",
117
117
  namespace: "Slider",
@@ -126,10 +126,8 @@ export class Slider {
126
126
  iconClassNext: wrapSettingString("iconClassNext"),
127
127
  // transition: true
128
128
  }
129
- // constructor(container, title, trackContainer, track, slides, config, debug = false) {
130
- constructor(elements, config, debug = false) {
129
+ constructor(elements, config) {
131
130
  const options = Object.assign({}, Slider.defaults, config);
132
- this.debug = debugMode || debug;
133
131
  this.options = options;
134
132
  this.slide = null;
135
133
  this.index = null;
@@ -511,7 +509,7 @@ export class Slider {
511
509
  const button = document.createElement("button");
512
510
  button.classList.add(this.getClass("nav-button"));
513
511
  button.setAttribute("type", "button");
514
- button.innerHTML = this.getNavContent(slide.number);
512
+ button.innerHTML = this.getNavContent(slide);
515
513
  slide.navButton = button; // Add reference to slide object
516
514
  button.addEventListener("click", this.goto.bind(this, index));
517
515
  return button;
@@ -523,8 +521,8 @@ export class Slider {
523
521
  <span class="${ this.getClass("control-icon") } ${ classes }" aria-hidden="true"></span>
524
522
  `;
525
523
  }
526
- getNavContent(number) {
527
- return `<span class="hidden-visually">Item ${ number }</span>`;
524
+ getNavContent(slide) {
525
+ return `<span class="hidden-visually">Item ${ slide.number }</span>`;
528
526
  }
529
527
  emit(name, args) {
530
528
  if (this.options.events[name]) {
package/js/ui/tabs.js CHANGED
@@ -9,9 +9,7 @@
9
9
  // setting this up to destroy tab interface when ui layout changes?
10
10
 
11
11
  import AriaTablist from "aria-tablist";
12
-
13
- const initAttr = "data-ulu-tablist-init";
14
- const errorHeader = "[data-ulu-tablist] error:";
12
+ import { ComponentInitializer } from "../utils/system.js";
15
13
 
16
14
  /**
17
15
  * Array of current tab instances (exported if you need to interact with them)
@@ -19,13 +17,28 @@ const errorHeader = "[data-ulu-tablist] error:";
19
17
  */
20
18
  export const instances = [];
21
19
 
20
+ /**
21
+ * Tabs Component Initializer
22
+ */
23
+ export const initializer = new ComponentInitializer({
24
+ type: "tabs",
25
+ baseAttribute: "data-ulu-tablist"
26
+ });
27
+
22
28
  /**
23
29
  * Init all instances currently in document
24
- * @param {Object} options Options to serve as defaults
25
30
  */
26
- export function init(options = {}) {
31
+ export function init() {
27
32
  const initial = () => {
28
- initWithin(document, options);
33
+ initializer.init({
34
+ events: ["pageModified"],
35
+ withData: true,
36
+ setup({ element, data, initialize }) {
37
+ setup(element, data);
38
+ initialize();
39
+ }
40
+ });
41
+
29
42
  // Run this on page load, optionally exported for use when page is running
30
43
  instances.forEach(openByCurrentHash);
31
44
  };
@@ -35,22 +48,6 @@ export function init(options = {}) {
35
48
  } else {
36
49
  window.addEventListener("load", initial);
37
50
  }
38
- // Initialize when page updates/changes
39
- document.addEventListener("pageModified", e => initWithin(e.target, options));
40
- }
41
-
42
- /**
43
- * Init all tabs within a certain context
44
- * @param {Node} context Element to init within
45
- * @param {Object} options Options to serve as defaults
46
- */
47
- export function initWithin(context, options = {}) {
48
- if (!context) {
49
- console.warn("Missing context to initWithin, skipping init of tabs");
50
- return;
51
- }
52
- const tablists = context.querySelectorAll(`[data-ulu-tablist]:not([${ initAttr }])`);
53
- tablists.forEach(element => setup(element, options));
54
51
  }
55
52
 
56
53
  /**
@@ -60,17 +57,7 @@ export function initWithin(context, options = {}) {
60
57
  * @return {Object} Instance object
61
58
  */
62
59
  export function setup(element, options = {}) {
63
- let elementOptions = {};
64
-
65
- if (element.dataset.uluTablist) {
66
- try {
67
- elementOptions = JSON.parse(element.dataset.uluTablist);
68
- } catch(e) {
69
- console.error(errorHeader, "(JSON Parse for options)", element);
70
- }
71
- }
72
-
73
- const config = Object.assign({}, options, elementOptions);
60
+ const config = Object.assign({}, options);
74
61
 
75
62
  if (config.vertical) {
76
63
  config.allArrows = true;
@@ -91,8 +78,6 @@ export function setup(element, options = {}) {
91
78
  if (config.equalHeights) {
92
79
  setHeights(element);
93
80
  }
94
-
95
- element.setAttribute(initAttr, "");
96
81
 
97
82
  return instance;
98
83
  }
@@ -150,7 +135,9 @@ function setHeights(element) {
150
135
  if (panel.hidden) {
151
136
  panel.hidden = false;
152
137
  panelHeight = panel.offsetHeight;
153
- panel.hidden = true;
138
+ // This explicity needs "hidden" for aria-tablist (it checks this string value)
139
+ // Will break the initial window push state when using openWithUrlHash
140
+ panel.setAttribute("hidden", "hidden");
154
141
  }
155
142
  return panelHeight;
156
143
  });
@@ -2,33 +2,32 @@
2
2
  * @module ui/theme-toggle
3
3
  */
4
4
 
5
+ import { ComponentInitializer } from "../utils/system.js";
5
6
  import { getName } from "../events/index.js";
6
- import { getDatasetJson, getElements, resolveClasses } from "../utils/dom.js";
7
+ import { getElements, resolveClasses } from "../utils/dom.js";
7
8
  import { hasRequiredProps } from "@ulu/utils/object.js";
8
9
 
9
10
  /**
10
- * Default data attributes
11
+ * Theme Toggle Component Initializer
11
12
  */
12
- export const attrs = {
13
- init: "data-ulu-theme-toggle-init",
14
- toggle: "data-ulu-theme-toggle",
15
- toggleIcon: "data-ulu-theme-toggle-icon",
16
- toggleLabel: "data-ulu-theme-toggle-label",
17
- toggleRemote: "data-ulu-theme-toggle-remote",
18
- state: "data-ulu-theme-toggle-state",
19
- };
13
+ export const initializer = new ComponentInitializer({
14
+ type: "theme-toggle",
15
+ baseAttribute: "data-ulu-theme-toggle"
16
+ });
17
+
18
+ const attrSelectorLabel = initializer.attributeSelector("label");
19
+ const attrSelectorIcon = initializer.attributeSelector("icon");
20
+ const attrRemote = initializer.getAttribute("remote");
21
+ const attrInit = initializer.getAttribute("init");
22
+ const attrState = initializer.getAttribute("state");
20
23
 
21
24
  // Utils for selecting things based on attributes
22
- const attrSelector = key => `[${ attrs[key] }]`;
23
- const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
24
- const queryAllInitial = key => document.querySelectorAll(attrSelectorInitial(key));
25
25
  const queryRemotes = group => document.querySelectorAll(
26
- `[${ attrs.toggleRemote }="${ group }"]`
26
+ `[${ attrRemote }="${ group }"]`
27
27
  );
28
28
  const queryRemotesInitial = group => document.querySelectorAll(
29
- `[${ attrs.toggleRemote }="${ group }"]:not([${ attrs.init }])`
29
+ `[${ attrRemote }="${ group }"]:not([${ attrInit }])`
30
30
  );
31
- const debugLog = (...msgs) => console.log("Theme Toggle:", ...msgs);
32
31
  const requiredToggleProps = ["target"];
33
32
  const checkToggleProps = hasRequiredProps(requiredToggleProps);
34
33
  const when = (cond, fn) => cond ? fn() : null; // Consider adding as util
@@ -109,24 +108,22 @@ export function setDefaults(options) {
109
108
  * - This will only initialize elements once, it is safe to call on page changes
110
109
  */
111
110
  export function init() {
112
- document.addEventListener(getName("pageModified"), setup);
113
- setup();
114
- }
115
-
116
- /**
117
- * Query and setup all
118
- */
119
- export function setup() {
120
- queryAllInitial("toggle").forEach(setupToggle);
111
+ initializer.init({
112
+ events: ["pageModified"],
113
+ withData: true,
114
+ setup({ element, data, initialize }) {
115
+ setupToggle(element, data);
116
+ initialize();
117
+ }
118
+ });
121
119
  }
122
120
 
123
121
  /**
124
122
  * Sets up a single toggle
125
123
  * @param {HTMLElement} toggle A toggle to be setup
126
124
  */
127
- export function setupToggle(toggle, passedOptions) {
128
- const elementOptions = getDatasetJson(toggle, "uluThemeToggle");
129
- const options = Object.assign({}, defaults, passedOptions, elementOptions);
125
+ export function setupToggle(toggle, userOptions) {
126
+ const options = Object.assign({}, defaults, userOptions);
130
127
 
131
128
  if (!checkToggleProps(options)) {
132
129
  console.error(`Missing a required option: ${ requiredToggleProps.join(", ") }`);
@@ -145,7 +142,6 @@ export function setupToggle(toggle, passedOptions) {
145
142
  setState(initialKey, ctx);
146
143
 
147
144
  toggle.addEventListener("click", onToggleClick);
148
- toggle.setAttribute(attrs.init, "");
149
145
 
150
146
  // Remotes listeners are attached initially and then we also
151
147
  // update them vs toggles which would be updated by the main pageModified
@@ -183,7 +179,7 @@ export function setupToggle(toggle, passedOptions) {
183
179
  const remotes = queryRemotesInitial(group);
184
180
  remotes.forEach(remote => {
185
181
  remote.addEventListener("click", onToggleClick);
186
- remote.setAttribute(attrs.init, "");
182
+ initializer.initializeElement(remote);
187
183
  });
188
184
  }
189
185
 
@@ -196,7 +192,7 @@ export function setupToggle(toggle, passedOptions) {
196
192
  const remotes = queryRemotesInitial(group);
197
193
  remotes.forEach(remote => {
198
194
  remote.removeEventListener("click", onToggleClick);
199
- remote.removeAttribute(attrs.init, "");
195
+ remote.removeAttribute(attrInit, "");
200
196
  });
201
197
  }
202
198
 
@@ -205,7 +201,7 @@ export function setupToggle(toggle, passedOptions) {
205
201
  */
206
202
  function destroy() {
207
203
  toggle.removeEventListener("click", onToggleClick);
208
- toggle.removeAttribute(attrs.init, "");
204
+ toggle.removeAttribute(attrInit, "");
209
205
  cleanupRemotes();
210
206
  document.removeEventListener(getName("pageModified"), attachRemotes);
211
207
  }
@@ -255,7 +251,7 @@ function setState(key, ctx) {
255
251
  };
256
252
 
257
253
  if (options.debug) {
258
- debugLog("set state context", stateCtx);
254
+ initializer.log("Set state context", stateCtx);
259
255
  }
260
256
 
261
257
  // Prepare classes to remove
@@ -264,15 +260,15 @@ function setState(key, ctx) {
264
260
 
265
261
  // Update all targets
266
262
  elements.targets.forEach(element => {
267
- element.setAttribute(attrs.state, key);
263
+ element.setAttribute(attrState, key);
268
264
  element.classList.remove(...otherTargetClasses);
269
265
  element.classList.add(...resolveClasses(theme.targetClass));
270
266
  });
271
267
 
272
268
  // Update all toggles and inner children
273
269
  elements.toggles.forEach(element => {
274
- const label = element.querySelector(attrSelector("toggleLabel"));
275
- const icon = element.querySelector(attrSelector("toggleIcon"));
270
+ const label = element.querySelector(attrSelectorLabel);
271
+ const icon = element.querySelector(attrSelectorIcon);
276
272
  if (label) {
277
273
  label.textContent = theme.label;
278
274
  }
@@ -280,7 +276,7 @@ function setState(key, ctx) {
280
276
  icon.classList.remove(...otherIconClasses);
281
277
  icon.classList.add(...resolveClasses(theme.iconClass));
282
278
  }
283
- element.setAttribute(attrs.state, key);
279
+ element.setAttribute(attrState, key);
284
280
  });
285
281
 
286
282
  // Optional callback if user want to set other things (ie. data-theme or something)
@@ -306,13 +302,13 @@ function resolveInitial(options) {
306
302
  const resolved = saved || mediaQueryPreference || initialState;
307
303
 
308
304
  if (options.debug) {
309
- debugLog("Preference Saved:", saved);
310
- debugLog("Media Query Preference:", mediaQueryPreference);
311
- debugLog("Initial State:", initialState);
305
+ initializer.log("Preference Saved", saved);
306
+ initializer.log("Media Query Preference", mediaQueryPreference);
307
+ initializer.log("Initial State:", initialState);
312
308
  }
313
309
 
314
310
  if (!resolved) {
315
- console.error("Failed to resolve initial theme (pass 'initialState' to options)");
311
+ initializer.logError("Failed to resolve initial theme (pass 'initialState' to options)");
316
312
  }
317
313
 
318
314
  return resolved;
package/js/ui/tooltip.js CHANGED
@@ -2,47 +2,41 @@
2
2
  * @module ui/tooltip
3
3
  */
4
4
 
5
+ import { ComponentInitializer } from "../utils/system.js";
5
6
  import { getName as getEventName } from "../events/index.js";
6
7
  import { createFloatingUi } from "../utils/floating-ui.js";
7
8
  import { createElementFromHtml } from "@ulu/utils/browser/dom.js";
8
9
  import { logError } from "../utils/class-logger.js";
9
- import { getDatasetOptionalJson } from "../utils/dom.js";
10
10
  import { newId, ensureId } from "../utils/id.js";
11
11
 
12
- const attrs = {
13
- trigger: "data-ulu-tooltip",
14
- init: "data-ulu-tooltip-init",
15
- body: "data-ulu-tooltip-display-body",
16
- arrow: "data-ulu-tooltip-arrow"
17
- };
18
- const attrSelector = key => `[${ attrs[key] }]`;
19
- const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
20
12
  /**
21
- * Initialize default popover
13
+ * Tooltip Component Initializer
22
14
  */
23
- export function init() {
24
- document.addEventListener(getEventName("pageModified"), setup);
25
- setup();
26
- }
15
+ export const initializer = new ComponentInitializer({
16
+ type: "tooltip",
17
+ baseAttribute: "data-ulu-tooltip"
18
+ });
19
+
20
+ const attrBody = initializer.getAttribute("body");
21
+ const attrSelectorBody = initializer.attributeSelector("body");
22
+ const attrSelectorArrow = initializer.attributeSelector("arrow");
27
23
 
28
24
  /**
29
- * Query all popovers on current page and set them up
30
- * - Use this manually if needed
31
- * - Won't setup a popover more than once
25
+ * Initialize default popover
32
26
  */
33
- export function setup() {
34
- const triggers = document.querySelectorAll(attrSelectorInitial("trigger"));
35
- triggers.forEach(setupTrigger);
36
- }
37
-
38
- export function setupTrigger(trigger) {
39
- const passed = getDatasetOptionalJson(trigger, "uluTooltip");
40
- const options = typeof passed === "object" ? passed : {};
41
- if (typeof passed === "string") {
42
- options.content = passed;
43
- }
44
- trigger.setAttribute(attrs.init, "");
45
- return new Tooltip({ trigger }, options);
27
+ export function init() {
28
+ initializer.init({
29
+ events: ["pageModified"],
30
+ withData: true,
31
+ setup({ element: trigger, data, initialize }) {
32
+ const options = typeof data === "object" ? data : {};
33
+ if (typeof data === "string") {
34
+ options.content = data;
35
+ }
36
+ initialize();
37
+ (new Tooltip({ trigger }, options));
38
+ }
39
+ });
46
40
  }
47
41
 
48
42
  /**
@@ -104,7 +98,7 @@ export class Tooltip {
104
98
  template(_config) {
105
99
  return `
106
100
  <div class="popover popover--tooltip">
107
- <div class="popover__inner" ${ attrs.body }>
101
+ <div class="popover__inner" ${ attrBody }>
108
102
  </div>
109
103
  <span class="popover__arrow" data-ulu-tooltip-arrow></span>
110
104
  </div>
@@ -178,7 +172,7 @@ export class Tooltip {
178
172
  createContentElement() {
179
173
  const { options } = this;
180
174
  const content = createElementFromHtml(options.template(options));
181
- const body = content.querySelector(attrSelector("body"));
175
+ const body = content.querySelector(attrSelectorBody);
182
176
  const innerContent = this.getInnerContent();
183
177
  if (options.isHtml) {
184
178
  body.innerHTML = innerContent;
@@ -191,7 +185,7 @@ export class Tooltip {
191
185
  }
192
186
 
193
187
  this.elements.content = content;
194
- this.elements.contentArrow = content.querySelector(attrSelector("arrow"));
188
+ this.elements.contentArrow = content.querySelector(attrSelectorArrow);
195
189
  document.body.appendChild(content);
196
190
  }
197
191
  attachHandlers() {
package/js/utils/dom.js CHANGED
@@ -5,6 +5,18 @@
5
5
 
6
6
  export const regexJsonString = /^[{\[][\s\S]*[}\]]$/;
7
7
 
8
+ /**
9
+ * Converts a data attribute name to its corresponding dataset property name.
10
+ * @param {string} dataAttribute - The data attribute name (e.g., "data-ulu-dialog").
11
+ * @returns {string} - The dataset property name (e.g., "uluDialog").
12
+ */
13
+ export function dataAttributeToDatasetKey(attribute) {
14
+ // Remove "data-" prefix then convert kebab-case to camelCase
15
+ return attribute
16
+ .replace(/^data-/, "")
17
+ .replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
18
+ }
19
+
8
20
  /**
9
21
  * Get an elements JSON dataset value
10
22
  * @param {Node} element