@ulu/frontend 0.1.0-beta.9 → 0.1.0-beta.90

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 (316) hide show
  1. package/CHANGELOG.md +606 -0
  2. package/README.dev.md +3 -3
  3. package/README.md +14 -4
  4. package/dist/ulu-frontend.min.css +1 -1
  5. package/dist/ulu-frontend.min.js +36 -29
  6. package/docs-dev/.nojekyll +1 -0
  7. package/docs-dev/assets/main.js +8290 -635
  8. package/docs-dev/assets/placeholder/icon-calendar.svg +1 -0
  9. package/docs-dev/assets/placeholder/icon-check.svg +1 -0
  10. package/docs-dev/assets/style.css +789 -338
  11. package/docs-dev/changelog/index.html +6985 -0
  12. package/docs-dev/demos/accordion/index.html +1126 -334
  13. package/docs-dev/demos/badge/index.html +5535 -0
  14. package/docs-dev/demos/basic-hero/index.html +111 -0
  15. package/docs-dev/demos/breakpoints-manager/index.html +5546 -0
  16. package/docs-dev/demos/button/index.html +1172 -338
  17. package/docs-dev/demos/button-group/index.html +5532 -0
  18. package/docs-dev/demos/button-verbose/index.html +5538 -0
  19. package/docs-dev/demos/callout/index.html +1177 -344
  20. package/docs-dev/demos/captioned-figure/index.html +1120 -327
  21. package/docs-dev/demos/card/index.html +1186 -754
  22. package/docs-dev/demos/card-grid/index.html +5657 -0
  23. package/docs-dev/demos/counter-list/index.html +5540 -0
  24. package/docs-dev/demos/css-icons/index.html +1148 -332
  25. package/docs-dev/demos/data-grid/index.html +1120 -327
  26. package/docs-dev/demos/data-table/index.html +1298 -372
  27. package/docs-dev/demos/details-group/index.html +5567 -0
  28. package/docs-dev/demos/file-save/index.html +1120 -327
  29. package/docs-dev/demos/flipcard/index.html +1120 -327
  30. package/docs-dev/demos/form-theme/index.html +1144 -364
  31. package/docs-dev/demos/headline-label/index.html +5502 -0
  32. package/docs-dev/demos/hero/index.html +12 -4
  33. package/docs-dev/demos/image-grid/index.html +12 -4
  34. package/docs-dev/demos/index.html +1121 -328
  35. package/docs-dev/demos/list-inline/index.html +1120 -327
  36. package/docs-dev/demos/list-lines/index.html +1120 -327
  37. package/docs-dev/demos/menu-stack/index.html +1159 -351
  38. package/docs-dev/demos/modals/index.html +1259 -343
  39. package/docs-dev/demos/nav-strip/index.html +1120 -327
  40. package/docs-dev/demos/overlay-section/index.html +1205 -342
  41. package/docs-dev/demos/panel/index.html +5562 -0
  42. package/docs-dev/demos/popovers/index.html +1368 -333
  43. package/docs-dev/demos/print/index.html +1120 -327
  44. package/docs-dev/demos/pull-quote/index.html +1120 -327
  45. package/docs-dev/demos/rail/index.html +5598 -0
  46. package/docs-dev/demos/rule/index.html +1137 -332
  47. package/docs-dev/demos/scroll-slider/index.html +72 -106
  48. package/docs-dev/demos/scrollpoints/index.html +1121 -328
  49. package/docs-dev/demos/slider/index.html +12 -4
  50. package/docs-dev/demos/spoke-spinner/index.html +1120 -327
  51. package/docs-dev/demos/{list-inline.1 → sticky-list}/index.html +1159 -363
  52. package/docs-dev/demos/tabs/index.html +1156 -327
  53. package/docs-dev/demos/tag/index.html +1120 -327
  54. package/docs-dev/demos/theme-toggle/index.html +5579 -0
  55. package/docs-dev/demos/tile-grid-overlay/index.html +12 -4
  56. package/docs-dev/demos/tiles/index.html +1120 -327
  57. package/docs-dev/demos/tooltip/index.html +1120 -327
  58. package/docs-dev/demos/wysiwyg/index.html +5552 -0
  59. package/docs-dev/guide/building-stylesheet/index.html +1120 -327
  60. package/docs-dev/guide/developing-ulu-scss-module/index.html +1120 -327
  61. package/docs-dev/guide/index.html +1120 -327
  62. package/docs-dev/index.html +1120 -327
  63. package/docs-dev/javascript/events/index.html +1158 -327
  64. package/docs-dev/javascript/index.html +1120 -327
  65. package/docs-dev/javascript/settings/index.html +5705 -0
  66. package/docs-dev/javascript/ui-breakpoints/index.html +1134 -343
  67. package/docs-dev/javascript/ui-collapsible/index.html +1119 -328
  68. package/docs-dev/javascript/ui-details-group/index.html +5622 -0
  69. package/docs-dev/javascript/ui-dialog/index.html +1151 -345
  70. package/docs-dev/javascript/ui-flipcard/index.html +1180 -333
  71. package/docs-dev/javascript/ui-grid/index.html +1130 -365
  72. package/docs-dev/javascript/ui-modal-builder/index.html +1303 -372
  73. package/docs-dev/javascript/ui-overflow-scroller/index.html +1119 -328
  74. package/docs-dev/javascript/ui-overflow-scroller-pager/index.html +1119 -328
  75. package/docs-dev/javascript/ui-page/index.html +1119 -328
  76. package/docs-dev/javascript/ui-popover/index.html +1129 -342
  77. package/docs-dev/javascript/ui-print/index.html +1117 -334
  78. package/docs-dev/javascript/ui-print-details/index.html +1119 -328
  79. package/docs-dev/javascript/ui-programmatic-modal/index.html +1119 -328
  80. package/docs-dev/javascript/ui-proxy-click/index.html +1208 -332
  81. package/docs-dev/javascript/ui-resizer/index.html +1400 -344
  82. package/docs-dev/javascript/ui-scroll-slider/index.html +1159 -336
  83. package/docs-dev/javascript/ui-scrollpoint/index.html +1129 -345
  84. package/docs-dev/javascript/ui-slider/index.html +1317 -335
  85. package/docs-dev/javascript/ui-tabs/index.html +1138 -384
  86. package/docs-dev/javascript/ui-theme-toggle/index.html +5710 -0
  87. package/docs-dev/javascript/ui-tooltip/index.html +1136 -349
  88. package/docs-dev/javascript/utils-class-logger/index.html +1120 -329
  89. package/docs-dev/javascript/utils-css/index.html +5524 -0
  90. package/docs-dev/javascript/utils-dom/index.html +1153 -442
  91. package/docs-dev/javascript/utils-file-save/index.html +1119 -328
  92. package/docs-dev/javascript/utils-floating-ui/index.html +1119 -328
  93. package/docs-dev/javascript/utils-id/index.html +1119 -328
  94. package/docs-dev/javascript/utils-pause-youtube-video/index.html +1119 -328
  95. package/docs-dev/javascript/utils-system/index.html +5827 -0
  96. package/docs-dev/sass/base/color/index.html +1119 -328
  97. package/docs-dev/sass/base/elements/index.html +1127 -336
  98. package/docs-dev/sass/base/index/index.html +1119 -328
  99. package/docs-dev/sass/base/index.html +1120 -327
  100. package/docs-dev/sass/base/keyframes/index.html +1120 -329
  101. package/docs-dev/sass/base/layout/index.html +1119 -328
  102. package/docs-dev/sass/base/normalize/index.html +1119 -328
  103. package/docs-dev/sass/base/print/index.html +1119 -328
  104. package/docs-dev/sass/base/root/index.html +1119 -328
  105. package/docs-dev/sass/base/typography/index.html +1119 -328
  106. package/docs-dev/sass/components/accordion/index.html +1142 -344
  107. package/docs-dev/sass/components/adaptive-spacing/index.html +1119 -328
  108. package/docs-dev/sass/components/badge/index.html +1145 -343
  109. package/docs-dev/sass/components/basic-hero/index.html +5685 -0
  110. package/docs-dev/sass/components/button/index.html +1119 -328
  111. package/docs-dev/sass/components/button-group/index.html +5683 -0
  112. package/docs-dev/sass/components/button-verbose/index.html +1205 -339
  113. package/docs-dev/sass/components/callout/index.html +1224 -414
  114. package/docs-dev/sass/components/captioned-figure/index.html +1243 -337
  115. package/docs-dev/sass/components/card/index.html +1215 -352
  116. package/docs-dev/sass/components/card-grid/index.html +1119 -328
  117. package/docs-dev/sass/components/counter-list/index.html +5767 -0
  118. package/docs-dev/sass/components/css-icon/index.html +1140 -342
  119. package/docs-dev/sass/components/data-grid/index.html +1139 -341
  120. package/docs-dev/sass/components/data-table/index.html +1327 -346
  121. package/docs-dev/sass/components/fill-context/index.html +1119 -328
  122. package/docs-dev/sass/components/flipcard/index.html +1161 -339
  123. package/docs-dev/sass/components/flipcard-grid/index.html +1119 -328
  124. package/docs-dev/sass/components/form-theme/index.html +1334 -447
  125. package/docs-dev/sass/components/headline-label/index.html +5713 -0
  126. package/docs-dev/sass/components/hero/index.html +1179 -340
  127. package/docs-dev/sass/components/horizontal-rule/index.html +1119 -328
  128. package/docs-dev/sass/components/image-grid/index.html +1119 -328
  129. package/docs-dev/sass/components/index/index.html +1136 -338
  130. package/docs-dev/sass/components/index.html +1120 -327
  131. package/docs-dev/sass/components/links/index.html +1119 -328
  132. package/docs-dev/sass/components/list-inline/index.html +1119 -328
  133. package/docs-dev/sass/components/list-lines/index.html +1119 -328
  134. package/docs-dev/sass/components/list-ordered/index.html +1119 -328
  135. package/docs-dev/sass/components/list-unordered/index.html +1119 -328
  136. package/docs-dev/sass/components/menu-stack/index.html +1156 -352
  137. package/docs-dev/sass/components/modal/index.html +1173 -347
  138. package/docs-dev/sass/components/nav-strip/index.html +1127 -336
  139. package/docs-dev/sass/components/overlay-section/index.html +1127 -336
  140. package/docs-dev/sass/components/pager/index.html +1119 -328
  141. package/docs-dev/sass/components/panel/index.html +5913 -0
  142. package/docs-dev/sass/components/placeholder-block/index.html +1119 -328
  143. package/docs-dev/sass/components/popover/index.html +1179 -352
  144. package/docs-dev/sass/components/pull-quote/index.html +1131 -340
  145. package/docs-dev/sass/components/rail/index.html +5700 -0
  146. package/docs-dev/sass/components/ratio-box/index.html +1127 -336
  147. package/docs-dev/sass/components/rule/index.html +1120 -329
  148. package/docs-dev/sass/components/scroll-slider/index.html +1129 -350
  149. package/docs-dev/sass/components/skip-link/index.html +1119 -328
  150. package/docs-dev/sass/components/slider/index.html +1173 -394
  151. package/docs-dev/sass/components/spoke-spinner/index.html +1121 -330
  152. package/docs-dev/sass/components/sticky-list/index.html +5903 -0
  153. package/docs-dev/sass/components/table-sticky/index.html +5677 -0
  154. package/docs-dev/sass/components/tabs/index.html +1154 -348
  155. package/docs-dev/sass/components/tag/index.html +1121 -330
  156. package/docs-dev/sass/components/tile-button/index.html +1119 -328
  157. package/docs-dev/sass/components/tile-grid/index.html +1119 -328
  158. package/docs-dev/sass/components/tile-grid-overlay/index.html +1119 -328
  159. package/docs-dev/sass/components/vignette/index.html +1131 -334
  160. package/docs-dev/sass/components/wysiwyg/index.html +1159 -350
  161. package/docs-dev/sass/core/breakpoint/index.html +1212 -369
  162. package/docs-dev/sass/core/button/index.html +1151 -358
  163. package/docs-dev/sass/core/color/index.html +1291 -368
  164. package/docs-dev/sass/core/cssvar/index.html +1119 -328
  165. package/docs-dev/sass/core/element/index.html +1440 -367
  166. package/docs-dev/sass/core/index.html +1119 -328
  167. package/docs-dev/sass/core/layout/index.html +1173 -363
  168. package/docs-dev/sass/core/path/index.html +1119 -328
  169. package/docs-dev/sass/core/selector/index.html +1119 -328
  170. package/docs-dev/sass/core/typography/index.html +1119 -328
  171. package/docs-dev/sass/core/units/index.html +1127 -330
  172. package/docs-dev/sass/core/utils/index.html +2389 -449
  173. package/docs-dev/sass/helpers/color/index.html +1119 -328
  174. package/docs-dev/sass/helpers/display/index.html +1120 -329
  175. package/docs-dev/sass/helpers/index/index.html +1119 -328
  176. package/docs-dev/sass/helpers/index.html +1120 -327
  177. package/docs-dev/sass/helpers/print/index.html +759 -298
  178. package/docs-dev/sass/helpers/typography/index.html +1119 -328
  179. package/docs-dev/sass/helpers/units/index.html +1119 -328
  180. package/docs-dev/sass/helpers/utilities/index.html +1121 -330
  181. package/docs-dev/sass/index.html +1120 -327
  182. package/js/events/index.js +17 -5
  183. package/js/index.js +1 -0
  184. package/js/settings.js +97 -0
  185. package/js/ui/breakpoints.js +19 -16
  186. package/js/ui/collapsible.js +8 -1
  187. package/js/ui/details-group.js +112 -0
  188. package/js/ui/dialog.js +103 -44
  189. package/js/ui/dialog.todo +2 -36
  190. package/js/ui/flipcard.js +37 -57
  191. package/js/ui/grid.js +15 -13
  192. package/js/ui/index.js +1 -0
  193. package/js/ui/modal-builder.js +127 -70
  194. package/js/ui/overflow-scroller.js +6 -4
  195. package/js/ui/page.js +2 -2
  196. package/js/ui/popover.js +38 -38
  197. package/js/ui/print.js +16 -25
  198. package/js/ui/programmatic-modal.js +9 -3
  199. package/js/ui/proxy-click.js +50 -36
  200. package/js/ui/resizer.js +408 -39
  201. package/js/ui/scroll-slider.js +24 -30
  202. package/js/ui/scrollpoint.js +29 -64
  203. package/js/ui/slider.js +108 -63
  204. package/js/ui/tabs.js +23 -36
  205. package/js/ui/theme-toggle.js +332 -94
  206. package/js/ui/tooltip.js +27 -32
  207. package/js/utils/class-logger.js +3 -3
  208. package/js/utils/css.js +13 -0
  209. package/js/utils/dom.js +23 -64
  210. package/js/utils/font-awesome.js +19 -0
  211. package/js/utils/index.js +2 -1
  212. package/js/utils/system.js +155 -0
  213. package/package.json +23 -8
  214. package/scss/README.md +4 -0
  215. package/scss/_breakpoint.scss +39 -5
  216. package/scss/_button.scss +7 -5
  217. package/scss/_color.scss +40 -9
  218. package/scss/_element.scss +124 -2
  219. package/scss/_layout.scss +7 -8
  220. package/scss/_units.scss +3 -2
  221. package/scss/_utils.scss +387 -16
  222. package/scss/base/_elements.scss +0 -1
  223. package/scss/base/_keyframes.scss +10 -0
  224. package/scss/base/_layout.scss +1 -0
  225. package/scss/base/_print.scss +2 -0
  226. package/scss/base/_root.scss +2 -0
  227. package/scss/components/README.todos +14 -0
  228. package/scss/components/_accordion.scss +33 -19
  229. package/scss/components/_badge.scss +23 -4
  230. package/scss/components/_basic-hero.scss +112 -0
  231. package/scss/components/_button-group.scss +90 -0
  232. package/scss/components/_button-verbose.scss +100 -18
  233. package/scss/components/_callout.scss +125 -78
  234. package/scss/components/_captioned-figure.scss +17 -0
  235. package/scss/components/_card-grid.scss +1 -1
  236. package/scss/components/_card.scss +228 -66
  237. package/scss/components/_counter-list.scss +151 -0
  238. package/scss/components/_css-icon.scss +35 -21
  239. package/scss/components/_data-grid.scss +55 -12
  240. package/scss/components/_data-table.scss +39 -3
  241. package/scss/components/_flipcard.scss +8 -3
  242. package/scss/components/_form-theme.scss +119 -108
  243. package/scss/components/_headline-label.scss +83 -0
  244. package/scss/components/_hero.scss +12 -10
  245. package/scss/components/_index.scss +42 -0
  246. package/scss/components/_menu-stack.scss +42 -26
  247. package/scss/components/_modal.scss +58 -29
  248. package/scss/components/_nav-strip.scss +2 -0
  249. package/scss/components/_overlay-section.scss +2 -5
  250. package/scss/components/_panel.scss +246 -0
  251. package/scss/components/_popover.scss +165 -64
  252. package/scss/components/_pull-quote.scss +13 -13
  253. package/scss/components/_rail.scss +120 -0
  254. package/scss/components/_ratio-box.scss +2 -5
  255. package/scss/components/_rule.scss +1 -0
  256. package/scss/components/_scroll-slider.scss +1 -5
  257. package/scss/components/_slider.scss +49 -72
  258. package/scss/components/_spoke-spinner.scss +2 -2
  259. package/scss/components/_sticky-list.scss +206 -0
  260. package/scss/components/_tabs.scss +22 -4
  261. package/scss/components/_vignette.scss +3 -5
  262. package/scss/components/_wysiwyg.scss +21 -13
  263. package/scss/helpers/_display.scss +15 -18
  264. package/scss/helpers/_print.scss +12 -7
  265. package/scss/helpers/_utilities.scss +42 -32
  266. package/types/events/index.d.ts +10 -1
  267. package/types/events/index.d.ts.map +1 -1
  268. package/types/index.d.ts +1 -0
  269. package/types/settings.d.ts +70 -0
  270. package/types/settings.d.ts.map +1 -0
  271. package/types/ui/breakpoints.d.ts +14 -14
  272. package/types/ui/breakpoints.d.ts.map +1 -1
  273. package/types/ui/collapsible.d.ts.map +1 -1
  274. package/types/ui/details-group.d.ts +38 -0
  275. package/types/ui/details-group.d.ts.map +1 -0
  276. package/types/ui/dialog.d.ts +20 -14
  277. package/types/ui/dialog.d.ts.map +1 -1
  278. package/types/ui/flipcard.d.ts +16 -10
  279. package/types/ui/flipcard.d.ts.map +1 -1
  280. package/types/ui/grid.d.ts +4 -6
  281. package/types/ui/grid.d.ts.map +1 -1
  282. package/types/ui/index.d.ts +2 -1
  283. package/types/ui/modal-builder.d.ts +116 -11
  284. package/types/ui/modal-builder.d.ts.map +1 -1
  285. package/types/ui/overflow-scroller.d.ts +2 -2
  286. package/types/ui/overflow-scroller.d.ts.map +1 -1
  287. package/types/ui/popover.d.ts +6 -7
  288. package/types/ui/popover.d.ts.map +1 -1
  289. package/types/ui/print.d.ts +0 -4
  290. package/types/ui/print.d.ts.map +1 -1
  291. package/types/ui/programmatic-modal.d.ts.map +1 -1
  292. package/types/ui/proxy-click.d.ts +19 -3
  293. package/types/ui/proxy-click.d.ts.map +1 -1
  294. package/types/ui/resizer.d.ts +116 -16
  295. package/types/ui/resizer.d.ts.map +1 -1
  296. package/types/ui/scroll-slider.d.ts +5 -7
  297. package/types/ui/scroll-slider.d.ts.map +1 -1
  298. package/types/ui/scrollpoint.d.ts +3 -8
  299. package/types/ui/scrollpoint.d.ts.map +1 -1
  300. package/types/ui/slider.d.ts +33 -14
  301. package/types/ui/slider.d.ts.map +1 -1
  302. package/types/ui/tabs.d.ts +6 -8
  303. package/types/ui/tabs.d.ts.map +1 -1
  304. package/types/ui/theme-toggle.d.ts +51 -7
  305. package/types/ui/theme-toggle.d.ts.map +1 -1
  306. package/types/ui/tooltip.d.ts +3 -5
  307. package/types/ui/tooltip.d.ts.map +1 -1
  308. package/types/utils/css.d.ts +11 -0
  309. package/types/utils/css.d.ts.map +1 -0
  310. package/types/utils/dom.d.ts +12 -32
  311. package/types/utils/dom.d.ts.map +1 -1
  312. package/types/utils/font-awesome.d.ts +5 -0
  313. package/types/utils/font-awesome.d.ts.map +1 -0
  314. package/types/utils/index.d.ts +2 -1
  315. package/types/utils/system.d.ts +113 -0
  316. package/types/utils/system.d.ts.map +1 -0
package/js/ui/resizer.js CHANGED
@@ -1,63 +1,432 @@
1
1
  /**
2
2
  * @module ui/resizer
3
3
  */
4
- // =============================================================================
5
- // Element Resizer
6
- // =============================================================================
7
4
 
8
- // Version: 1.0.1
5
+ // Note: Gzip Test = 1.6kb (7-28-25), which seems appropriate
6
+ // based on how many options/events it handles
9
7
 
10
- // Description: Adds resizing ability to an element (only horizontal currently)
11
-
12
- // Reference: - http://jsfiddle.net/3jMQD/614/
13
-
14
- import { logError } from "../utils/class-logger.js";
8
+ import { createEvent } from "../events/index.js";
9
+ import { logError, log } from "../utils/class-logger.js";
15
10
 
11
+ /**
12
+ * Class for creating/controlling a container size with a handle/control
13
+ */
16
14
  export class Resizer {
17
15
  static defaults = {
18
16
  debug: false,
19
- overrideMaxWidth: false,
20
- fromLeft: false
17
+ /**
18
+ * Amount to increase size by (ie. pointer movement * multiplier)
19
+ */
20
+ multiplier: 1,
21
+ /**
22
+ * Remove max-width, max-height
23
+ */
24
+ overrideMaxDimensions: false,
25
+ /**
26
+ * @type {"left"|"right"|null}
27
+ * Specifies the horizontal edge from which resizing occurs.
28
+ * `null` means no horizontal resizing.
29
+ * - Default null
30
+ */
31
+ fromX: null,
32
+ /**
33
+ * @type {"top"|"bottom"|null}
34
+ * Specifies the vertical edge from which resizing occurs.
35
+ * - `null` means no vertical resizing.
36
+ * - Default null
37
+ */
38
+ fromY: null,
39
+ /**
40
+ * The step in pixels for keyboard resizing with arrow keys.
41
+ */
42
+ keyboardStep: 10,
43
+ /**
44
+ * Debounce time in milliseconds for ending a keyboard resize.
45
+ */
46
+ keyboardDebounceTime: 200,
47
+ /**
48
+ * If true, the Resizer instance will automatically bind its own DOM event listeners
49
+ * (pointerdown, keydown) to the control element. If `false`, the user is
50
+ * responsible for calling `resizerInstance.onPointerdown(event)` and
51
+ * `resizerInstance.onKeydown(event)` from their own listeners.
52
+ * Default: true
53
+ */
54
+ manageEvents: true,
55
+ /**
56
+ * If true, the Resizer instance will automatically manage the `aria-label`
57
+ * attribute of the control element. If `false`, the user is responsible
58
+ * for setting this attribute.
59
+ * Default: false
60
+ */
61
+ manageAriaLabel: false,
62
+ /**
63
+ * If true, pointer events (mouse/touch) will enable resizing.
64
+ * Default: true
65
+ */
66
+ enablePointerResizing: true,
67
+ /**
68
+ * If true, keyboard events (arrow keys) will enable resizing.
69
+ * Default: true
70
+ */
71
+ enableKeyboardResizing: true
21
72
  };
73
+
74
+ // Declare private fields without initial assignments
75
+ #handlerPointerdownInternal;
76
+ #handlerKeydownInternal;
77
+ #keyboardResizeTimeout;
78
+ #initialContainerDimensions;
79
+ #accumulatedKeyboardDeltaX;
80
+ #accumulatedKeyboardDeltaY;
81
+ #isResizingActive;
82
+ #pointerStartX;
83
+ #pointerStartY;
84
+
22
85
  /**
23
- *
24
- * @param {Node} container Container to be resize
25
- * @param {Node} control Resize handle element
26
- * @param {Object} options Defualt can be changed on class
27
- * @param {Boolean} options.debug Enable non-essential debugging logs
28
- * @param {Boolean} options.overrideMaxWidth When script is activated by handle remove the elements max-width and allow the width of the resize to exceed the max (default false)
29
- * @param {Boolean} options.fromLeft The script should assume the handle is on the left side of the element
86
+ * @param {Node} container Container to be resized
87
+ * @param {HTMLElement} control Resize handle element (should be focusable like a button)
88
+ * @param {Object} config Options to configure the resizer.
89
+ * @param {Boolean} [config.debug=false] Enable non-essential debugging logs.
90
+ * @param {Boolean} [config.multiplier=1] Amount to increase size by (ie. pointer movement * multiplier).
91
+ * @param {Boolean} [config.overrideMaxDimensions=false] When script is activated by handle, remove the element's max-width/max-height and allow the resize to exceed them.
92
+ * @param {"left"|"right"|null} [config.fromX=null] Horizontal resizing direction.
93
+ * @param {"top"|"bottom"|null} [config.fromY=null] Vertical resizing direction.
94
+ * @param {number} [config.keyboardStep=10] The step in pixels for keyboard resizing.
95
+ * @param {number} [config.keyboardDebounceTime=200] Debounce time for keyboard resize end.
96
+ * @param {boolean} [config.manageEvents=true] If true, the Resizer will automatically bind its own events.
97
+ * @param {boolean} [config.manageAriaLabel=false] If true, the Resizer will manage the control's aria-label.
98
+ * @param {boolean} [config.enablePointerResizing=true] If true, pointer events will enable resizing.
99
+ * @param {boolean} [config.enableKeyboardResizing=true] If true, keyboard events will enable resizing.
30
100
  */
31
- constructor(container, control, options) {
101
+ constructor(container, control, config) {
32
102
  if (!control || !container) {
33
- logError(this, "Missing required elements 'control' or 'container'");
103
+ logError(this, "Missing required elements: control, container");
104
+ return;
34
105
  }
35
- this.options = Object.assign({}, Resizer.defaults, options);
106
+ const options = Object.assign({}, Resizer.defaults, config);
107
+ this.options = options;
36
108
  this.container = container;
37
109
  this.control = control;
38
- this.handlerMousedown = this.onMousedown.bind(this);
39
- this.control.addEventListener('mousedown', this.handlerMousedown);
110
+ this.debug = options.debug;
111
+
112
+ const validX = ["left", "right"];
113
+ const validY = ["top", "bottom"];
114
+ const { fromX, fromY } = options;
115
+
116
+ if (!validX.includes(fromX) && fromX !== null) {
117
+ logError(this, `Invalid fromX: ${ fromX } (left|right|null)`);
118
+ return;
119
+ }
120
+ if (!validY.includes(fromY) && fromY !== null) {
121
+ logError(this, `Invalid fromY: ${ fromY } (top|bottom|null)`);
122
+ return;
123
+ }
124
+ if (!fromX && !fromY) {
125
+ logError(this, "Invalid fromX/fromY, failed to setup resizer (at least one of fromX or fromY must be set)");
126
+ return;
127
+ }
128
+
129
+ this.resizeHorizontal = options.fromX !== null;
130
+ this.resizeVertical = options.fromY !== null;
131
+
132
+ // Bind internal listeners only if manageEvents is true AND the respective event type is enabled
133
+ if (options.manageEvents) {
134
+ this.#handlerPointerdownInternal = this.onPointerdown.bind(this);
135
+ this.#handlerKeydownInternal = this.onKeydown.bind(this);
136
+
137
+ if (options.enablePointerResizing) {
138
+ control.addEventListener("pointerdown", this.#handlerPointerdownInternal);
139
+ }
140
+ if (options.enableKeyboardResizing) {
141
+ control.addEventListener("keydown", this.#handlerKeydownInternal);
142
+ }
143
+ }
144
+
145
+ this.#resetInternalState();
146
+
147
+ if (options.manageAriaLabel) {
148
+ control.setAttribute("aria-label", this.getAriaLabel());
149
+ }
40
150
  }
151
+
152
+ /**
153
+ * Resets all internal state properties to their default/inactive values.
154
+ * This centralizes state cleanup and initial setup.
155
+ * @private
156
+ */
157
+ #resetInternalState() {
158
+ this.#keyboardResizeTimeout = null;
159
+ this.#initialContainerDimensions = { width: 0, height: 0 };
160
+ this.#accumulatedKeyboardDeltaX = 0;
161
+ this.#accumulatedKeyboardDeltaY = 0;
162
+ this.#isResizingActive = false;
163
+ this.#pointerStartX = 0;
164
+ this.#pointerStartY = 0;
165
+ }
166
+
167
+ /**
168
+ * Cleans up event listeners and internal state to prevent memory leaks.
169
+ */
41
170
  destroy() {
42
- this.control.removeEventListener('mousedown', this.handlerMousedown);
171
+ const { control, options } = this;
172
+
173
+ if (options.manageEvents) {
174
+ if (options.enablePointerResizing) {
175
+ control.removeEventListener("pointerdown", this.#handlerPointerdownInternal);
176
+ }
177
+ if (options.enableKeyboardResizing) {
178
+ control.removeEventListener("keydown", this.#handlerKeydownInternal);
179
+ }
180
+ }
181
+
182
+ if (this.#keyboardResizeTimeout) {
183
+ clearTimeout(this.#keyboardResizeTimeout);
184
+ }
185
+
186
+ this.#resetInternalState();
187
+
188
+ if (options.manageAriaLabel) {
189
+ control.removeAttribute("aria-label");
190
+ }
191
+ log(this, "Resizer destroyed.");
43
192
  }
44
- onMousedown(e) {
45
- const { overrideMaxWidth, fromLeft } = this.options;
46
- const doc = document.documentElement;
193
+
194
+ /**
195
+ * Initiates a resize operation.
196
+ * This sets initial dimensions and dispatches the 'resizer:start' event.
197
+ * @param {Object} eventDetails Additional details about the initiating event.
198
+ * @private
199
+ */
200
+ #startResize(eventDetails) {
201
+ const { container, options } = this;
202
+
203
+ if (this.#isResizingActive) {
204
+ if (options.overrideMaxDimensions) {
205
+ if (this.resizeHorizontal) {
206
+ container.style.maxWidth = "none";
207
+ }
208
+ if (this.resizeVertical) {
209
+ container.style.maxHeight = "none";
210
+ }
211
+ }
212
+ return;
213
+ }
214
+
47
215
  const win = document.defaultView;
48
- const x = e.clientX;
49
- const width = parseInt(win.getComputedStyle(this.container).width, 10);
50
- if (overrideMaxWidth) {
51
- this.container.style.maxWidth = 'none';
52
- }
53
- const mousemove = event => {
54
- const polarity = fromLeft ? -1 : 1;
55
- this.container.style.width = `${ width + ((event.clientX - x) * polarity) }px`;
216
+ const containerStyle = win.getComputedStyle(container);
217
+
218
+ this.#initialContainerDimensions.width = parseInt(containerStyle.width, 10);
219
+ this.#initialContainerDimensions.height = parseInt(containerStyle.height, 10);
220
+
221
+ if (options.overrideMaxDimensions) {
222
+ if (this.resizeHorizontal) {
223
+ container.style.maxWidth = "none";
224
+ }
225
+ if (this.resizeVertical) {
226
+ container.style.maxHeight = "none";
227
+ }
228
+ }
229
+
230
+ this.#isResizingActive = true;
231
+ this.dispatchEvent("resizer:start", eventDetails);
232
+ log(this, "Resize started.", {
233
+ initialWidth: this.#initialContainerDimensions.width,
234
+ initialHeight: this.#initialContainerDimensions.height,
235
+ ...eventDetails
236
+ });
237
+ }
238
+
239
+ /**
240
+ * Ends a resize operation.
241
+ * Dispatches 'resizer:end' event and resets internal state.
242
+ * @private
243
+ */
244
+ #endResize() {
245
+ if (!this.#isResizingActive) return;
246
+
247
+ this.dispatchEvent("resizer:end");
248
+ this.#resetInternalState();
249
+ log(this, "Resize ended.");
250
+ }
251
+
252
+ /**
253
+ * Core logic for calculating and applying the new size of the container.
254
+ * This method is called by both pointer and keyboard event handlers.
255
+ *
256
+ * @param {number} totalDeltaX The total horizontal displacement from the start of the resize.
257
+ * @param {number} totalDeltaY The total vertical displacement from the start of the resize.
258
+ * @param {Event} originalEvent The original DOM event (PointerEvent or KeyboardEvent) that triggered the update.
259
+ * @private
260
+ */
261
+ #updateSize(totalDeltaX, totalDeltaY, originalEvent) {
262
+ let newWidth = this.#initialContainerDimensions.width;
263
+ let newHeight = this.#initialContainerDimensions.height;
264
+ const { fromX, fromY, multiplier } = this.options;
265
+
266
+ if (this.resizeHorizontal) {
267
+ if (fromX === "right") {
268
+ newWidth = (this.#initialContainerDimensions.width + (totalDeltaX * multiplier));
269
+ } else if (fromX === "left") {
270
+ newWidth = (this.#initialContainerDimensions.width - (totalDeltaX * multiplier));
271
+ }
272
+ this.container.style.width = `${ Math.max(0, newWidth) }px`;
273
+ }
274
+
275
+ if (this.resizeVertical) {
276
+ if (fromY === "bottom") {
277
+ newHeight = (this.#initialContainerDimensions.height + (totalDeltaY * multiplier));
278
+ } else if (fromY === "top") {
279
+ newHeight = (this.#initialContainerDimensions.height - (totalDeltaY * multiplier));
280
+ }
281
+ this.container.style.height = `${ Math.max(0, newHeight) }px`;
282
+ }
283
+
284
+ const updateInfo = {
285
+ newWidth: newWidth,
286
+ newHeight: newHeight,
287
+ totalDeltaX: totalDeltaX,
288
+ totalDeltaY: totalDeltaY,
289
+ event: originalEvent
56
290
  };
57
- const cleanup = () => {
58
- doc.removeEventListener('mousemove', mousemove, false);
291
+
292
+ this.dispatchEvent("resizer:update", updateInfo);
293
+ log(this, "Resizing update.", updateInfo);
294
+ }
295
+
296
+ /**
297
+ * Public handler for pointerdown events. Call this method from your own event listeners
298
+ * if `manageEvents` is false. Its logic will only execute if `enablePointerResizing` is true.
299
+ * @param {PointerEvent} e The pointerdown event.
300
+ */
301
+ onPointerdown(e) {
302
+ if (!this.options.enablePointerResizing) {
303
+ log(this, "Pointer resizing disabled. Ignoring pointerdown event.");
304
+ return;
305
+ }
306
+
307
+ e.preventDefault();
308
+ const doc = document.documentElement;
309
+
310
+ this.#pointerStartX = e.clientX;
311
+ this.#pointerStartY = e.clientY;
312
+
313
+ this.#startResize({
314
+ inputType: 'pointer',
315
+ startX: e.clientX,
316
+ startY: e.clientY,
317
+ pointerId: e.pointerId
318
+ });
319
+
320
+ this.control.setPointerCapture(e.pointerId);
321
+
322
+ const pointermove = (event) => {
323
+ const totalDeltaX = event.clientX - this.#pointerStartX;
324
+ const totalDeltaY = event.clientY - this.#pointerStartY;
325
+ this.#updateSize(totalDeltaX, totalDeltaY, event);
326
+ };
327
+
328
+ const cleanup = (event) => {
329
+ doc.removeEventListener("pointermove", pointermove, false);
330
+ doc.removeEventListener("pointerup", cleanup, { capture: true, once: true });
331
+
332
+ if (this.control.hasPointerCapture(event.pointerId)) {
333
+ this.control.releasePointerCapture(event.pointerId);
334
+ }
335
+ this.#endResize();
59
336
  };
60
- doc.addEventListener('mousemove', mousemove, false);
61
- doc.addEventListener('mouseup', cleanup, { capture: true, once: true });
337
+
338
+ doc.addEventListener("pointermove", pointermove, false);
339
+ doc.addEventListener("pointerup", cleanup, { capture: true, once: true });
340
+ }
341
+
342
+ /**
343
+ * Public handler for keydown events. Call this method from your own event listeners
344
+ * if `manageEvents` is false. Its logic will only execute if `enableKeyboardResizing` is true.
345
+ * @param {KeyboardEvent} e The keydown event.
346
+ */
347
+ onKeydown(e) {
348
+ if (!this.options.enableKeyboardResizing) {
349
+ log(this, "Keyboard resizing disabled. Ignoring keydown event.");
350
+ return;
351
+ }
352
+
353
+ const { key } = e;
354
+ const { keyboardStep, keyboardDebounceTime } = this.options;
355
+
356
+ let stepDeltaX = 0;
357
+ let stepDeltaY = 0;
358
+ let isResizeKey = false;
359
+
360
+ if (this.resizeHorizontal) {
361
+ if (key === "ArrowLeft") {
362
+ // ArrowLeft should always move the active horizontal edge to the left
363
+ stepDeltaX = -keyboardStep;
364
+ isResizeKey = true;
365
+ } else if (key === "ArrowRight") {
366
+ // ArrowRight should always move the active horizontal edge to the right
367
+ stepDeltaX = keyboardStep;
368
+ isResizeKey = true;
369
+ }
370
+ }
371
+
372
+ if (this.resizeVertical) {
373
+ if (key === "ArrowUp") {
374
+ // ArrowUp should always move the active vertical edge up
375
+ stepDeltaY = -keyboardStep;
376
+ isResizeKey = true;
377
+ } else if (key === "ArrowDown") {
378
+ // ArrowDown should always move the active vertical edge down
379
+ stepDeltaY = keyboardStep;
380
+ isResizeKey = true;
381
+ }
382
+ }
383
+
384
+ if (isResizeKey) {
385
+ e.preventDefault();
386
+ e.stopPropagation();
387
+
388
+ if (!this.#isResizingActive || this.#keyboardResizeTimeout === null) {
389
+ this.#startResize({ inputType: 'keyboard', keyboardKey: key });
390
+ }
391
+
392
+ this.#accumulatedKeyboardDeltaX += stepDeltaX;
393
+ this.#accumulatedKeyboardDeltaY += stepDeltaY;
394
+
395
+ this.#updateSize(this.#accumulatedKeyboardDeltaX, this.#accumulatedKeyboardDeltaY, e);
396
+
397
+ if (this.#keyboardResizeTimeout) {
398
+ clearTimeout(this.#keyboardResizeTimeout);
399
+ }
400
+ this.#keyboardResizeTimeout = setTimeout(() => {
401
+ this.#endResize();
402
+ this.#keyboardResizeTimeout = null;
403
+ }, keyboardDebounceTime);
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Generates an accessible label for the resize control based on its configuration.
409
+ * This is a convenience function that can be used by the consumer if `manageAriaLabel` is false.
410
+ * @returns {string} The suggested aria-label for the control.
411
+ */
412
+ getAriaLabel() {
413
+ const { fromY, fromX } = this.options;
414
+ const directions = [fromY, fromX].filter(v => v);
415
+
416
+ if (directions.length === 0) {
417
+ return "Resize control"; // Fallback for invalid configuration (should be caught by constructor)
418
+ }
419
+
420
+ // Join all directions with a space and append " edge".
421
+ return `Resize from ${directions.join(' ')} edge`;
422
+ }
423
+
424
+ /**
425
+ * Dispatches a custom event on the container element.
426
+ * @param {string} type The event type (e.g., "resizer:start", "resizer:update", "resizer:end").
427
+ * @param {Object} [data={}] Optional data to attach to the event's detail property.
428
+ */
429
+ dispatchEvent(type, data = {}) {
430
+ this.container.dispatchEvent(createEvent(type, data));
62
431
  }
63
432
  }
@@ -2,29 +2,21 @@
2
2
  * @module ui/scroll-slider
3
3
  */
4
4
 
5
+ import { ComponentInitializer } from "../utils/system.js";
5
6
  import { OverflowScroller } from "./overflow-scroller.js";
6
7
  import { createPager } from "./overflow-scroller-pager.js";
7
- import { getName } from "../events/index.js";
8
- import { getDatasetOptionalJson } from "../utils/dom.js";
9
-
10
8
 
11
9
  /**
12
- * Default data attributes
10
+ * Scroll Slider Component Initializer
13
11
  */
14
- export const attrs = {
15
- init: "data-ulu-scroll-slider-init",
16
- slider: "data-ulu-scroll-slider",
17
- track: "data-ulu-scroll-slider-track",
18
- controls: "data-ulu-scroll-slider-control-context"
19
- };
20
-
21
- // Utils for selecting things based on attributes
22
- const attrSelector = key => `[${ attrs[key] }]`;
23
- const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
24
-
12
+ export const initializer = new ComponentInitializer({
13
+ type: "scroll-slider",
14
+ baseAttribute: "data-ulu-scroll-slider"
15
+ });
25
16
 
17
+ const attrSelectorTrack = initializer.attributeSelector("track");
18
+ const attrSelectorControls = initializer.attributeSelector("control-context");
26
19
  const instances = [];
27
-
28
20
  const defaults = {
29
21
  amount: createPager()
30
22
  };
@@ -34,23 +26,25 @@ const defaults = {
34
26
  * - This will only initialize elements once, it is safe to call on page changes
35
27
  */
36
28
  export function init() {
37
- document.addEventListener(getName("pageModified"), setup);
38
- setup();
29
+ initializer.init({
30
+ withData: true,
31
+ events: ["pageModified"],
32
+ setup({ element, data, initialize }) {
33
+ setupSlider(element, data);
34
+ initialize();
35
+ }
36
+ });
39
37
  }
40
38
 
41
- export function setup() {
42
- const builders = document.querySelectorAll(attrSelectorInitial("slider"));
43
- builders.forEach(setupSlider);
44
- }
45
-
46
- // getDatasetOptionalJson
47
- function setupSlider(container) {
48
- container.setAttribute(attrs.init, "");
49
- const options = getDatasetOptionalJson(container, "uluScrollSlider");
50
- const config = Object.assign({}, defaults, options);
39
+ /**
40
+ * Setup instance of scroll slider based on data-attributes
41
+ * @param {Node} container The scroll slider container
42
+ */
43
+ function setupSlider(container, userOptions) {
44
+ const config = Object.assign({}, defaults, userOptions);
51
45
  const elements = {
52
- track: container.querySelector(attrSelector("track")),
53
- controls: container.querySelector(attrSelector("controls"))
46
+ track: container.querySelector(attrSelectorTrack),
47
+ controls: container.querySelector(attrSelectorControls)
54
48
  };
55
49
  instances.push(new OverflowScroller(elements, config));
56
50
  }
@@ -1,81 +1,46 @@
1
1
  /**
2
2
  * @module ui/scrollpoint
3
+ * @description Module that uses intersection observer to add scrollpoint like behavior.
3
4
  */
4
5
 
5
- // Module that uses intersection observer to add scrollpoint like behavior.
6
- /**
7
- * TODO:
8
- * - Included a group option or attribute (on container)
9
- // for things like anchor menus (one active in group at a time).
10
- *
11
- * How to link elements of group
12
- * <div group={ groupName: test }>
13
- * <div point={ groupName: test, mirror: ["#menu-link-1"] }>
14
- * or
15
- * <div group={ groupName: test, children: [".selector"] }>
16
- * <div class=".selector">
17
- */
18
- import { getName } from "../events/index.js";
19
- import { getDatasetOptionalJson, getElement } from "../utils/dom.js";
6
+ import { ComponentInitializer } from "../utils/system.js";
20
7
  import { logError } from "../utils/class-logger.js";
8
+ import { getElement } from "@ulu/utils/browser/dom.js";
9
+
10
+ // TODO:
11
+ // - Included a group option or attribute (on container), for things like anchor menus (one active in group at a time).
12
+ //
13
+ // How to link elements of group
14
+ // <div group={ groupName: test }>
15
+ // <div point={ groupName: test, mirror: ["#menu-link-1"] }>
16
+ // or
17
+ // <div group={ groupName: test, children: [".selector"] }>
18
+ // <div class=".selector">
21
19
 
22
20
  /**
23
- * Default data attributes
21
+ * Scrollpoint Component Initializer
24
22
  */
25
- export const attrs = {
26
- init: "data-ulu-scrollpoint-init",
27
- /**
28
- * Individual scrollpoint
29
- */
30
- point: "data-ulu-scrollpoint",
31
- group: "data-ulu-scrollpoint-group",
32
- groupAnchors: "data-ulu-scrollpoint-anchors"
33
- // Goes on container for all items
34
- // group: "data-ulu-scrollpoint-group"
35
- };
36
-
37
- // Utils for selecting things based on attributes
38
- const attrSelector = key => `[${ attrs[key] }]`;
39
- const attrSelectorInitial = key => `${ attrSelector(key) }:not([${ attrs.init }])`;
40
- const queryAllInitial = key => document.querySelectorAll(attrSelectorInitial(key));
23
+ export const initializer = new ComponentInitializer({
24
+ type: "scrollpoint",
25
+ baseAttribute: "data-ulu-scrollpoint"
26
+ });
41
27
 
42
28
  /**
43
29
  * Initialize everything in document
44
30
  * - This will only initialize elements once, it is safe to call on page changes
45
31
  */
46
32
  export function init() {
47
- document.addEventListener(getName("pageModified"), setup);
48
- setup();
49
- }
50
-
51
- /**
52
- * Setup all points and groups
53
- */
54
- export function setup() {
55
- const elements = queryAllInitial("point");
56
- // const points = Array.from(elements).map(resolve);
57
- // const groups = points
58
- // .filter(({ config }) => config.groupName)
59
- // .reduce((acc, point) => {
60
- // const { groupName } = point.config;
61
- // if (acc.has(groupName)) {
62
- // acc.get(groupName).push(point);
63
- // } else {
64
- // acc.set(groupName, [point]);
65
- // }
66
- // }, new Map());
67
- // const singles = points.filter(({ config }) => !config.groupName);
68
- // groups.forEach(setupGroup);
69
- elements.forEach(element => {
70
- const elOptions = getDatasetOptionalJson(element, "uluScrollpoint");
71
- const config = Object.assign({}, elOptions);
72
- element.setAttribute(attrs.init, "");
73
- new Scrollpoint(element, config);
33
+ initializer.init({
34
+ withData: true,
35
+ events: ["pageModified"],
36
+ setup({ element, data, initialize }) {
37
+ const config = Object.assign({}, data);
38
+ (new Scrollpoint(element, config));
39
+ initialize();
40
+ }
74
41
  });
75
42
  }
76
43
 
77
-
78
-
79
44
  /**
80
45
  * Single scrollpoint
81
46
  * - Note "forward" and "reverse" refer to scroll directions
@@ -141,7 +106,7 @@ export class Scrollpoint {
141
106
  /**
142
107
  * Attribute name to set state info in
143
108
  */
144
- attributeName: "data-scrollpoint-state",
109
+ attributeName: "data-ulu-scrollpoint-state",
145
110
  /**
146
111
  * Group multiple points, one active at a time (scroll menus)
147
112
  */
@@ -191,7 +156,7 @@ export class Scrollpoint {
191
156
  };
192
157
  this.setupObserver();
193
158
  if (options.debug) {
194
- console.log("Scrollpoint", this);
159
+ initializer.log(this);
195
160
  }
196
161
  }
197
162
  getClassname(suffix) {
@@ -233,7 +198,7 @@ export class Scrollpoint {
233
198
  };
234
199
  const config = this.getObserverOptions();
235
200
  if (this.options.debug) {
236
- console.log("Scrollpoint (IntersectionObserver)", config);
201
+ initializer.log("IntersectionObserver (options)", config);
237
202
  }
238
203
  this.observer = new IntersectionObserver(handler, config);
239
204
  this.observer.observe(this.element);