@ulu/frontend 0.1.0-beta.10 → 0.1.0-beta.100

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 (324) hide show
  1. package/CHANGELOG.md +641 -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 +7184 -0
  12. package/docs-dev/demos/accordion/index.html +1277 -365
  13. package/docs-dev/demos/badge/index.html +5655 -0
  14. package/docs-dev/demos/badge-stack/index.html +5636 -0
  15. package/docs-dev/demos/{list-inline.1 → badge.1}/index.html +1231 -363
  16. package/docs-dev/demos/basic-hero/index.html +111 -0
  17. package/docs-dev/demos/breakpoints-manager/index.html +5666 -0
  18. package/docs-dev/demos/button/index.html +1309 -355
  19. package/docs-dev/demos/button-group/index.html +5652 -0
  20. package/docs-dev/demos/button-verbose/index.html +5658 -0
  21. package/docs-dev/demos/callout/index.html +1300 -347
  22. package/docs-dev/demos/captioned-figure/index.html +1271 -358
  23. package/docs-dev/demos/card/index.html +1374 -822
  24. package/docs-dev/demos/card-grid/index.html +5777 -0
  25. package/docs-dev/demos/counter-list/index.html +5660 -0
  26. package/docs-dev/demos/css-icons/index.html +1292 -356
  27. package/docs-dev/demos/data-grid/index.html +1271 -358
  28. package/docs-dev/demos/data-table/index.html +1405 -359
  29. package/docs-dev/demos/details-group/index.html +5687 -0
  30. package/docs-dev/demos/file-save/index.html +1271 -358
  31. package/docs-dev/demos/flipcard/index.html +1271 -358
  32. package/docs-dev/demos/form-theme/index.html +1295 -395
  33. package/docs-dev/demos/headline-label/index.html +5622 -0
  34. package/docs-dev/demos/hero/index.html +12 -4
  35. package/docs-dev/demos/image-grid/index.html +12 -4
  36. package/docs-dev/demos/index.html +1272 -359
  37. package/docs-dev/demos/list-inline/index.html +1271 -358
  38. package/docs-dev/demos/list-lines/index.html +1271 -358
  39. package/docs-dev/demos/menu-stack/index.html +1303 -375
  40. package/docs-dev/demos/modals/index.html +1382 -346
  41. package/docs-dev/demos/nav-strip/index.html +1271 -358
  42. package/docs-dev/demos/overlay-section/index.html +1335 -352
  43. package/docs-dev/demos/panel/index.html +5682 -0
  44. package/docs-dev/demos/popovers/index.html +1562 -407
  45. package/docs-dev/demos/print/index.html +1271 -358
  46. package/docs-dev/demos/pull-quote/index.html +1271 -358
  47. package/docs-dev/demos/rail/index.html +5730 -0
  48. package/docs-dev/demos/rule/index.html +1288 -363
  49. package/docs-dev/demos/scroll-slider/index.html +72 -106
  50. package/docs-dev/demos/scrollpoints/index.html +1272 -359
  51. package/docs-dev/demos/skeleton/index.html +5678 -0
  52. package/docs-dev/demos/slider/index.html +12 -4
  53. package/docs-dev/demos/spoke-spinner/index.html +1271 -358
  54. package/docs-dev/demos/sticky-list/index.html +5643 -0
  55. package/docs-dev/demos/tabs/index.html +1301 -352
  56. package/docs-dev/demos/tag/index.html +1271 -358
  57. package/docs-dev/demos/theme-toggle/index.html +5699 -0
  58. package/docs-dev/demos/tile-grid-overlay/index.html +12 -4
  59. package/docs-dev/demos/tiles/index.html +1271 -358
  60. package/docs-dev/demos/tooltip/index.html +1271 -358
  61. package/docs-dev/demos/wysiwyg/index.html +5672 -0
  62. package/docs-dev/guide/building-stylesheet/index.html +1271 -358
  63. package/docs-dev/guide/developing-ulu-scss-module/index.html +1271 -358
  64. package/docs-dev/guide/index.html +1271 -358
  65. package/docs-dev/index.html +1271 -358
  66. package/docs-dev/javascript/events/index.html +1303 -352
  67. package/docs-dev/javascript/index.html +1271 -358
  68. package/docs-dev/javascript/settings/index.html +5825 -0
  69. package/docs-dev/javascript/ui-breakpoints/index.html +1285 -374
  70. package/docs-dev/javascript/ui-collapsible/index.html +1270 -359
  71. package/docs-dev/javascript/ui-details-group/index.html +5742 -0
  72. package/docs-dev/javascript/ui-dialog/index.html +1302 -376
  73. package/docs-dev/javascript/ui-flipcard/index.html +1331 -364
  74. package/docs-dev/javascript/ui-grid/index.html +1274 -389
  75. package/docs-dev/javascript/ui-modal-builder/index.html +1497 -446
  76. package/docs-dev/javascript/ui-overflow-scroller/index.html +1270 -359
  77. package/docs-dev/javascript/ui-overflow-scroller-pager/index.html +1270 -359
  78. package/docs-dev/javascript/ui-page/index.html +1270 -359
  79. package/docs-dev/javascript/ui-popover/index.html +1280 -373
  80. package/docs-dev/javascript/ui-print/index.html +1268 -365
  81. package/docs-dev/javascript/ui-print-details/index.html +1270 -359
  82. package/docs-dev/javascript/ui-programmatic-modal/index.html +1270 -359
  83. package/docs-dev/javascript/ui-proxy-click/index.html +1331 -335
  84. package/docs-dev/javascript/ui-resizer/index.html +1588 -412
  85. package/docs-dev/javascript/ui-scroll-slider/index.html +1310 -367
  86. package/docs-dev/javascript/ui-scrollpoint/index.html +1280 -376
  87. package/docs-dev/javascript/ui-slider/index.html +1454 -352
  88. package/docs-dev/javascript/ui-tabs/index.html +1261 -387
  89. package/docs-dev/javascript/ui-theme-toggle/index.html +5830 -0
  90. package/docs-dev/javascript/ui-tooltip/index.html +1273 -366
  91. package/docs-dev/javascript/utils-class-logger/index.html +1271 -360
  92. package/docs-dev/javascript/utils-css/index.html +5644 -0
  93. package/docs-dev/javascript/utils-dom/index.html +1269 -438
  94. package/docs-dev/javascript/utils-file-save/index.html +1270 -359
  95. package/docs-dev/javascript/utils-floating-ui/index.html +1270 -359
  96. package/docs-dev/javascript/utils-id/index.html +1270 -359
  97. package/docs-dev/javascript/utils-pause-youtube-video/index.html +1270 -359
  98. package/docs-dev/javascript/utils-system/index.html +5947 -0
  99. package/docs-dev/sass/base/color/index.html +1270 -359
  100. package/docs-dev/sass/base/elements/index.html +1271 -360
  101. package/docs-dev/sass/base/index/index.html +1271 -360
  102. package/docs-dev/sass/base/index.html +1271 -358
  103. package/docs-dev/sass/base/keyframes/index.html +1271 -360
  104. package/docs-dev/sass/base/layout/index.html +1271 -360
  105. package/docs-dev/sass/base/normalize/index.html +1270 -359
  106. package/docs-dev/sass/base/print/index.html +1271 -360
  107. package/docs-dev/sass/base/root/index.html +1274 -363
  108. package/docs-dev/sass/base/typography/index.html +1270 -359
  109. package/docs-dev/sass/components/accordion/index.html +1293 -375
  110. package/docs-dev/sass/components/adaptive-spacing/index.html +1270 -359
  111. package/docs-dev/sass/components/badge/index.html +1295 -366
  112. package/docs-dev/sass/components/badge-stack/index.html +5811 -0
  113. package/docs-dev/sass/components/basic-hero/index.html +5805 -0
  114. package/docs-dev/sass/components/button/index.html +1270 -359
  115. package/docs-dev/sass/components/button-group/index.html +5803 -0
  116. package/docs-dev/sass/components/button-verbose/index.html +1342 -356
  117. package/docs-dev/sass/components/callout/index.html +1352 -422
  118. package/docs-dev/sass/components/captioned-figure/index.html +1373 -347
  119. package/docs-dev/sass/components/card/index.html +1339 -356
  120. package/docs-dev/sass/components/card-grid/index.html +1270 -359
  121. package/docs-dev/sass/components/counter-list/index.html +5887 -0
  122. package/docs-dev/sass/components/css-icon/index.html +1271 -360
  123. package/docs-dev/sass/components/data-grid/index.html +1290 -372
  124. package/docs-dev/sass/components/data-table/index.html +1449 -348
  125. package/docs-dev/sass/components/fill-context/index.html +1270 -359
  126. package/docs-dev/sass/components/flipcard/index.html +1305 -363
  127. package/docs-dev/sass/components/flipcard-grid/index.html +1270 -359
  128. package/docs-dev/sass/components/form-theme/index.html +1449 -442
  129. package/docs-dev/sass/components/headline-label/index.html +5833 -0
  130. package/docs-dev/sass/components/hero/index.html +1316 -357
  131. package/docs-dev/sass/components/horizontal-rule/index.html +1270 -359
  132. package/docs-dev/sass/components/image-grid/index.html +1270 -359
  133. package/docs-dev/sass/components/index/index.html +1289 -369
  134. package/docs-dev/sass/components/index.html +1271 -358
  135. package/docs-dev/sass/components/links/index.html +1270 -359
  136. package/docs-dev/sass/components/list-inline/index.html +1270 -359
  137. package/docs-dev/sass/components/list-lines/index.html +1270 -359
  138. package/docs-dev/sass/components/list-ordered/index.html +1270 -359
  139. package/docs-dev/sass/components/list-unordered/index.html +1270 -359
  140. package/docs-dev/sass/components/menu-stack/index.html +1294 -369
  141. package/docs-dev/sass/components/modal/index.html +1306 -360
  142. package/docs-dev/sass/components/nav-strip/index.html +1278 -367
  143. package/docs-dev/sass/components/overlay-section/index.html +1278 -367
  144. package/docs-dev/sass/components/pager/index.html +1270 -359
  145. package/docs-dev/sass/components/panel/index.html +6033 -0
  146. package/docs-dev/sass/components/placeholder-block/index.html +1270 -359
  147. package/docs-dev/sass/components/popover/index.html +1323 -376
  148. package/docs-dev/sass/components/pull-quote/index.html +1282 -371
  149. package/docs-dev/sass/components/rail/index.html +5823 -0
  150. package/docs-dev/sass/components/ratio-box/index.html +1278 -367
  151. package/docs-dev/sass/components/rule/index.html +1271 -360
  152. package/docs-dev/sass/components/scroll-slider/index.html +1280 -381
  153. package/docs-dev/sass/components/skeleton/index.html +5861 -0
  154. package/docs-dev/sass/components/skip-link/index.html +1270 -359
  155. package/docs-dev/sass/components/slider/index.html +1310 -411
  156. package/docs-dev/sass/components/spoke-spinner/index.html +1272 -361
  157. package/docs-dev/sass/components/sticky-list/index.html +6023 -0
  158. package/docs-dev/sass/components/table-sticky/index.html +5677 -0
  159. package/docs-dev/sass/components/tabs/index.html +1291 -365
  160. package/docs-dev/sass/components/tag/index.html +1272 -361
  161. package/docs-dev/sass/components/tile-button/index.html +1270 -359
  162. package/docs-dev/sass/components/tile-grid/index.html +1270 -359
  163. package/docs-dev/sass/components/tile-grid-overlay/index.html +1270 -359
  164. package/docs-dev/sass/components/vignette/index.html +1282 -365
  165. package/docs-dev/sass/components/wysiwyg/index.html +1296 -367
  166. package/docs-dev/sass/core/breakpoint/index.html +1349 -386
  167. package/docs-dev/sass/core/button/index.html +1302 -389
  168. package/docs-dev/sass/core/color/index.html +1414 -370
  169. package/docs-dev/sass/core/cssvar/index.html +1270 -359
  170. package/docs-dev/sass/core/element/index.html +1641 -448
  171. package/docs-dev/sass/core/index.html +1270 -359
  172. package/docs-dev/sass/core/layout/index.html +1318 -388
  173. package/docs-dev/sass/core/path/index.html +1270 -359
  174. package/docs-dev/sass/core/selector/index.html +1270 -359
  175. package/docs-dev/sass/core/typography/index.html +1270 -359
  176. package/docs-dev/sass/core/units/index.html +1278 -361
  177. package/docs-dev/sass/core/utils/index.html +2580 -520
  178. package/docs-dev/sass/helpers/color/index.html +1270 -359
  179. package/docs-dev/sass/helpers/display/index.html +1271 -360
  180. package/docs-dev/sass/helpers/index/index.html +1270 -359
  181. package/docs-dev/sass/helpers/index.html +1271 -358
  182. package/docs-dev/sass/helpers/print/index.html +759 -298
  183. package/docs-dev/sass/helpers/typography/index.html +1270 -359
  184. package/docs-dev/sass/helpers/units/index.html +1270 -359
  185. package/docs-dev/sass/helpers/utilities/index.html +1272 -361
  186. package/docs-dev/sass/index.html +1271 -358
  187. package/js/events/index.js +17 -5
  188. package/js/index.js +1 -0
  189. package/js/settings.js +97 -0
  190. package/js/ui/breakpoints.js +19 -16
  191. package/js/ui/collapsible.js +8 -1
  192. package/js/ui/details-group.js +112 -0
  193. package/js/ui/dialog.js +103 -44
  194. package/js/ui/dialog.todo +2 -36
  195. package/js/ui/flipcard.js +37 -57
  196. package/js/ui/grid.js +15 -13
  197. package/js/ui/index.js +1 -0
  198. package/js/ui/modal-builder.js +127 -70
  199. package/js/ui/overflow-scroller.js +6 -4
  200. package/js/ui/page.js +2 -2
  201. package/js/ui/popover.js +38 -38
  202. package/js/ui/print.js +16 -25
  203. package/js/ui/programmatic-modal.js +9 -3
  204. package/js/ui/proxy-click.js +50 -36
  205. package/js/ui/resizer.js +408 -39
  206. package/js/ui/scroll-slider.js +24 -30
  207. package/js/ui/scrollpoint.js +29 -64
  208. package/js/ui/slider.js +108 -63
  209. package/js/ui/tabs.js +23 -36
  210. package/js/ui/theme-toggle.js +332 -94
  211. package/js/ui/tooltip.js +27 -32
  212. package/js/utils/class-logger.js +3 -3
  213. package/js/utils/css.js +13 -0
  214. package/js/utils/dom.js +23 -64
  215. package/js/utils/font-awesome.js +19 -0
  216. package/js/utils/index.js +2 -1
  217. package/js/utils/system.js +155 -0
  218. package/package.json +23 -8
  219. package/scss/README.md +9 -0
  220. package/scss/_breakpoint.scss +39 -5
  221. package/scss/_button.scss +7 -5
  222. package/scss/_color.scss +42 -10
  223. package/scss/_element.scss +124 -2
  224. package/scss/_layout.scss +7 -8
  225. package/scss/_units.scss +3 -2
  226. package/scss/_utils.scss +387 -16
  227. package/scss/base/_elements.scss +0 -1
  228. package/scss/base/_index.scss +1 -1
  229. package/scss/base/_keyframes.scss +15 -0
  230. package/scss/base/_layout.scss +1 -0
  231. package/scss/base/_print.scss +2 -0
  232. package/scss/base/_root.scss +2 -0
  233. package/scss/components/README.todos +14 -0
  234. package/scss/components/_accordion.scss +33 -19
  235. package/scss/components/_badge-stack.scss +84 -0
  236. package/scss/components/_badge.scss +30 -7
  237. package/scss/components/_basic-hero.scss +112 -0
  238. package/scss/components/_button-group.scss +90 -0
  239. package/scss/components/_button-verbose.scss +100 -18
  240. package/scss/components/_callout.scss +125 -78
  241. package/scss/components/_captioned-figure.scss +17 -0
  242. package/scss/components/_card-grid.scss +1 -1
  243. package/scss/components/_card.scss +229 -67
  244. package/scss/components/_counter-list.scss +151 -0
  245. package/scss/components/_css-icon.scss +27 -17
  246. package/scss/components/_data-grid.scss +55 -12
  247. package/scss/components/_data-table.scss +39 -3
  248. package/scss/components/_flipcard.scss +8 -3
  249. package/scss/components/_form-theme.scss +119 -108
  250. package/scss/components/_headline-label.scss +83 -0
  251. package/scss/components/_hero.scss +12 -10
  252. package/scss/components/_index.scss +54 -0
  253. package/scss/components/_menu-stack.scss +42 -25
  254. package/scss/components/_modal.scss +51 -23
  255. package/scss/components/_nav-strip.scss +2 -0
  256. package/scss/components/_overlay-section.scss +2 -5
  257. package/scss/components/_panel.scss +246 -0
  258. package/scss/components/_popover.scss +165 -64
  259. package/scss/components/_pull-quote.scss +13 -13
  260. package/scss/components/_rail.scss +127 -0
  261. package/scss/components/_ratio-box.scss +2 -5
  262. package/scss/components/_rule.scss +1 -0
  263. package/scss/components/_scroll-slider.scss +1 -5
  264. package/scss/components/_skeleton.scss +126 -0
  265. package/scss/components/_slider.scss +49 -72
  266. package/scss/components/_spoke-spinner.scss +2 -2
  267. package/scss/components/_sticky-list.scss +206 -0
  268. package/scss/components/_tabs.scss +22 -4
  269. package/scss/components/_vignette.scss +3 -5
  270. package/scss/components/_wysiwyg.scss +21 -13
  271. package/scss/helpers/_display.scss +15 -18
  272. package/scss/helpers/_print.scss +12 -7
  273. package/scss/helpers/_utilities.scss +41 -31
  274. package/types/events/index.d.ts +10 -1
  275. package/types/events/index.d.ts.map +1 -1
  276. package/types/index.d.ts +1 -0
  277. package/types/settings.d.ts +70 -0
  278. package/types/settings.d.ts.map +1 -0
  279. package/types/ui/breakpoints.d.ts +14 -14
  280. package/types/ui/breakpoints.d.ts.map +1 -1
  281. package/types/ui/collapsible.d.ts.map +1 -1
  282. package/types/ui/details-group.d.ts +38 -0
  283. package/types/ui/details-group.d.ts.map +1 -0
  284. package/types/ui/dialog.d.ts +20 -14
  285. package/types/ui/dialog.d.ts.map +1 -1
  286. package/types/ui/flipcard.d.ts +16 -10
  287. package/types/ui/flipcard.d.ts.map +1 -1
  288. package/types/ui/grid.d.ts +4 -6
  289. package/types/ui/grid.d.ts.map +1 -1
  290. package/types/ui/index.d.ts +2 -1
  291. package/types/ui/modal-builder.d.ts +116 -11
  292. package/types/ui/modal-builder.d.ts.map +1 -1
  293. package/types/ui/overflow-scroller.d.ts +2 -2
  294. package/types/ui/overflow-scroller.d.ts.map +1 -1
  295. package/types/ui/popover.d.ts +6 -7
  296. package/types/ui/popover.d.ts.map +1 -1
  297. package/types/ui/print.d.ts +0 -4
  298. package/types/ui/print.d.ts.map +1 -1
  299. package/types/ui/programmatic-modal.d.ts.map +1 -1
  300. package/types/ui/proxy-click.d.ts +19 -3
  301. package/types/ui/proxy-click.d.ts.map +1 -1
  302. package/types/ui/resizer.d.ts +116 -16
  303. package/types/ui/resizer.d.ts.map +1 -1
  304. package/types/ui/scroll-slider.d.ts +5 -7
  305. package/types/ui/scroll-slider.d.ts.map +1 -1
  306. package/types/ui/scrollpoint.d.ts +3 -8
  307. package/types/ui/scrollpoint.d.ts.map +1 -1
  308. package/types/ui/slider.d.ts +33 -14
  309. package/types/ui/slider.d.ts.map +1 -1
  310. package/types/ui/tabs.d.ts +6 -8
  311. package/types/ui/tabs.d.ts.map +1 -1
  312. package/types/ui/theme-toggle.d.ts +51 -7
  313. package/types/ui/theme-toggle.d.ts.map +1 -1
  314. package/types/ui/tooltip.d.ts +3 -5
  315. package/types/ui/tooltip.d.ts.map +1 -1
  316. package/types/utils/css.d.ts +11 -0
  317. package/types/utils/css.d.ts.map +1 -0
  318. package/types/utils/dom.d.ts +12 -32
  319. package/types/utils/dom.d.ts.map +1 -1
  320. package/types/utils/font-awesome.d.ts +5 -0
  321. package/types/utils/font-awesome.d.ts.map +1 -0
  322. package/types/utils/index.d.ts +2 -1
  323. package/types/utils/system.d.ts +113 -0
  324. 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);