@dodlhuat/basix 1.1.1 → 1.2.1

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 (352) hide show
  1. package/README.md +706 -482
  2. package/css/accordion.scss +86 -87
  3. package/css/alert.scss +137 -137
  4. package/css/badge.scss +104 -0
  5. package/css/bottom-sheet.scss +192 -0
  6. package/css/breadcrumb.scss +158 -0
  7. package/css/button.scss +48 -0
  8. package/css/calendar.scss +957 -0
  9. package/css/card.scss +65 -65
  10. package/css/chart.scss +270 -157
  11. package/css/chat-bubbles.scss +134 -68
  12. package/css/chips.scss +109 -19
  13. package/css/colors.scss +32 -32
  14. package/css/context-menu.scss +182 -0
  15. package/css/datepicker.scss +336 -336
  16. package/css/defaults.scss +90 -90
  17. package/css/docs.scss +529 -0
  18. package/css/editor.scss +664 -461
  19. package/css/file-uploader.scss +1 -1
  20. package/css/flyout-menu.scss +361 -361
  21. package/css/form.scss +124 -0
  22. package/css/gallery.scss +65 -6
  23. package/css/grid.scss +41 -40
  24. package/css/group-picker.scss +345 -0
  25. package/css/guitar-chords.css +250 -250
  26. package/css/icons.scss +330 -330
  27. package/css/parameters.scss +3 -3
  28. package/css/placeholder.scss +33 -33
  29. package/css/popover.scss +206 -0
  30. package/css/progress.scss +76 -32
  31. package/css/properties.scss +51 -36
  32. package/css/push-menu.scss +302 -174
  33. package/css/reset.scss +39 -39
  34. package/css/scrollbar.scss +62 -5
  35. package/css/sidebar-nav.scss +92 -0
  36. package/css/spinner.scss +65 -65
  37. package/css/stepper.scss +248 -0
  38. package/css/style.css +4603 -273
  39. package/css/style.css.map +1 -1
  40. package/css/style.min.css +1 -1
  41. package/css/style.scss +51 -39
  42. package/css/table.scss +199 -199
  43. package/css/tabs.scss +154 -123
  44. package/css/timeline.scss +83 -38
  45. package/css/timepicker.scss +100 -5
  46. package/css/toast.scss +81 -81
  47. package/css/typography.scss +194 -161
  48. package/css/virtual-dropdown.scss +35 -29
  49. package/js/bottom-sheet.js +173 -0
  50. package/js/bottom-sheet.ts +222 -0
  51. package/js/calendar.js +532 -0
  52. package/js/calendar.ts +706 -0
  53. package/js/carousel.js +26 -13
  54. package/js/chart.js +573 -257
  55. package/js/chart.ts +692 -0
  56. package/js/code-viewer.js +10 -10
  57. package/js/code-viewer.ts +188 -188
  58. package/js/context-menu.js +212 -0
  59. package/js/context-menu.ts +252 -0
  60. package/js/datepicker.ts +627 -627
  61. package/js/docs-nav.js +204 -0
  62. package/js/dropdown.ts +179 -179
  63. package/js/editor.js +96 -38
  64. package/js/editor.ts +483 -425
  65. package/js/file-uploader.js +1 -0
  66. package/js/file-uploader.ts +1 -0
  67. package/js/flyout-menu.js +14 -14
  68. package/js/flyout-menu.ts +249 -249
  69. package/js/form-builder.js +106 -106
  70. package/js/gallery.js +13 -6
  71. package/js/gallery.ts +245 -236
  72. package/js/group-picker.js +342 -0
  73. package/js/group-picker.ts +447 -0
  74. package/js/guitar-chords.js +268 -268
  75. package/js/lazy-loader.js +121 -121
  76. package/js/modal.ts +166 -166
  77. package/js/popover.js +163 -0
  78. package/js/popover.ts +219 -0
  79. package/js/position.js +108 -0
  80. package/js/position.ts +111 -0
  81. package/js/push-menu.js +226 -113
  82. package/js/push-menu.ts +284 -145
  83. package/js/request.js +50 -50
  84. package/js/scroll.ts +47 -47
  85. package/js/scrollbar.js +13 -0
  86. package/js/scrollbar.ts +324 -307
  87. package/js/select.ts +216 -216
  88. package/js/sidebar-nav.js +41 -0
  89. package/js/sidebar-nav.ts +66 -0
  90. package/js/stepper.js +80 -0
  91. package/js/stepper.ts +104 -0
  92. package/js/table.ts +452 -452
  93. package/js/tabs.ts +279 -279
  94. package/js/theme.js +17 -6
  95. package/js/theme.ts +234 -224
  96. package/js/timepicker.js +21 -8
  97. package/js/toast.ts +137 -137
  98. package/js/tooltip.js +6 -60
  99. package/js/tooltip.ts +184 -251
  100. package/js/tsconfig.json +18 -18
  101. package/js/utils.ts +83 -83
  102. package/js/virtual-dropdown.js +25 -25
  103. package/js/virtual-dropdown.ts +365 -365
  104. package/package.json +39 -39
  105. package/fonts/Outfit-VariableFont_wght.woff +0 -0
  106. package/fonts/material-icons.woff2 +0 -0
  107. package/icons/activity-outline.svg +0 -1
  108. package/icons/alert-circle-outline.svg +0 -1
  109. package/icons/alert-triangle-outline.svg +0 -1
  110. package/icons/archive-outline.svg +0 -1
  111. package/icons/arrow-back-outline.svg +0 -1
  112. package/icons/arrow-circle-down-outline.svg +0 -1
  113. package/icons/arrow-circle-left-outline.svg +0 -1
  114. package/icons/arrow-circle-right-outline.svg +0 -1
  115. package/icons/arrow-circle-up-outline.svg +0 -1
  116. package/icons/arrow-down-outline.svg +0 -1
  117. package/icons/arrow-downward-outline.svg +0 -1
  118. package/icons/arrow-forward-outline.svg +0 -1
  119. package/icons/arrow-ios-back-outline.svg +0 -1
  120. package/icons/arrow-ios-downward-outline.svg +0 -1
  121. package/icons/arrow-ios-forward-outline.svg +0 -1
  122. package/icons/arrow-ios-upward-outline.svg +0 -1
  123. package/icons/arrow-left-outline.svg +0 -1
  124. package/icons/arrow-right-outline.svg +0 -1
  125. package/icons/arrow-up-outline.svg +0 -1
  126. package/icons/arrow-upward-outline.svg +0 -1
  127. package/icons/arrowhead-down-outline.svg +0 -1
  128. package/icons/arrowhead-left-outline.svg +0 -1
  129. package/icons/arrowhead-right-outline.svg +0 -1
  130. package/icons/arrowhead-up-outline.svg +0 -1
  131. package/icons/at-outline.svg +0 -1
  132. package/icons/attach-2-outline.svg +0 -1
  133. package/icons/attach-outline.svg +0 -1
  134. package/icons/award-outline.svg +0 -1
  135. package/icons/backspace-outline.svg +0 -1
  136. package/icons/bar-chart-2-outline.svg +0 -1
  137. package/icons/bar-chart-outline.svg +0 -1
  138. package/icons/battery-outline.svg +0 -1
  139. package/icons/behance-outline.svg +0 -1
  140. package/icons/bell-off-outline.svg +0 -1
  141. package/icons/bell-outline.svg +0 -1
  142. package/icons/bluetooth-outline.svg +0 -1
  143. package/icons/book-open-outline.svg +0 -1
  144. package/icons/book-outline.svg +0 -1
  145. package/icons/bookmark-outline.svg +0 -1
  146. package/icons/briefcase-outline.svg +0 -1
  147. package/icons/browser-outline.svg +0 -1
  148. package/icons/brush-outline.svg +0 -1
  149. package/icons/bulb-outline.svg +0 -1
  150. package/icons/calendar-outline.svg +0 -1
  151. package/icons/camera-outline.svg +0 -1
  152. package/icons/car-outline.svg +0 -1
  153. package/icons/cast-outline.svg +0 -1
  154. package/icons/charging-outline.svg +0 -1
  155. package/icons/checkmark-circle-2-outline.svg +0 -1
  156. package/icons/checkmark-circle-outline.svg +0 -1
  157. package/icons/checkmark-outline.svg +0 -1
  158. package/icons/checkmark-square-2-outline.svg +0 -1
  159. package/icons/checkmark-square-outline.svg +0 -1
  160. package/icons/chevron-down-outline.svg +0 -1
  161. package/icons/chevron-left-outline.svg +0 -1
  162. package/icons/chevron-right-outline.svg +0 -1
  163. package/icons/chevron-up-outline.svg +0 -1
  164. package/icons/clipboard-outline.svg +0 -1
  165. package/icons/clock-outline.svg +0 -1
  166. package/icons/close-circle-outline.svg +0 -1
  167. package/icons/close-outline.svg +0 -1
  168. package/icons/close-square-outline.svg +0 -1
  169. package/icons/cloud-download-outline.svg +0 -1
  170. package/icons/cloud-upload-outline.svg +0 -1
  171. package/icons/code-download-outline.svg +0 -1
  172. package/icons/code-outline.svg +0 -1
  173. package/icons/collapse-outline.svg +0 -1
  174. package/icons/color-palette-outline.svg +0 -1
  175. package/icons/color-picker-outline.svg +0 -1
  176. package/icons/compass-outline.svg +0 -1
  177. package/icons/copy-outline.svg +0 -1
  178. package/icons/corner-down-left-outline.svg +0 -1
  179. package/icons/corner-down-right-outline.svg +0 -1
  180. package/icons/corner-left-down-outline.svg +0 -1
  181. package/icons/corner-left-up-outline.svg +0 -1
  182. package/icons/corner-right-down-outline.svg +0 -1
  183. package/icons/corner-right-up-outline.svg +0 -1
  184. package/icons/corner-up-left-outline.svg +0 -1
  185. package/icons/corner-up-right-outline.svg +0 -1
  186. package/icons/credit-card-outline.svg +0 -1
  187. package/icons/crop-outline.svg +0 -1
  188. package/icons/cube-outline.svg +0 -1
  189. package/icons/diagonal-arrow-left-down-outline.svg +0 -1
  190. package/icons/diagonal-arrow-left-up-outline.svg +0 -1
  191. package/icons/diagonal-arrow-right-down-outline.svg +0 -1
  192. package/icons/diagonal-arrow-right-up-outline.svg +0 -1
  193. package/icons/done-all-outline.svg +0 -1
  194. package/icons/download-outline.svg +0 -1
  195. package/icons/droplet-off-outline.svg +0 -1
  196. package/icons/droplet-outline.svg +0 -1
  197. package/icons/edit-2-outline.svg +0 -1
  198. package/icons/edit-outline.svg +0 -1
  199. package/icons/email-outline.svg +0 -1
  200. package/icons/expand-outline.svg +0 -1
  201. package/icons/external-link-outline.svg +0 -1
  202. package/icons/eye-off-2-outline.svg +0 -1
  203. package/icons/eye-off-outline.svg +0 -1
  204. package/icons/eye-outline.svg +0 -1
  205. package/icons/facebook-outline.svg +0 -1
  206. package/icons/file-add-outline.svg +0 -1
  207. package/icons/file-outline.svg +0 -1
  208. package/icons/file-remove-outline.svg +0 -1
  209. package/icons/file-text-outline.svg +0 -1
  210. package/icons/film-outline.svg +0 -1
  211. package/icons/flag-outline.svg +0 -1
  212. package/icons/flash-off-outline.svg +0 -1
  213. package/icons/flash-outline.svg +0 -1
  214. package/icons/flip-2-outline.svg +0 -1
  215. package/icons/flip-outline.svg +0 -1
  216. package/icons/folder-add-outline.svg +0 -1
  217. package/icons/folder-outline.svg +0 -1
  218. package/icons/folder-remove-outline.svg +0 -1
  219. package/icons/funnel-outline.svg +0 -1
  220. package/icons/gift-outline.svg +0 -1
  221. package/icons/github-outline.svg +0 -1
  222. package/icons/globe-2-outline.svg +0 -1
  223. package/icons/globe-outline.svg +0 -1
  224. package/icons/google-outline.svg +0 -1
  225. package/icons/grid-outline.svg +0 -1
  226. package/icons/hard-drive-outline.svg +0 -1
  227. package/icons/hash-outline.svg +0 -1
  228. package/icons/headphones-outline.svg +0 -1
  229. package/icons/heart-outline.svg +0 -1
  230. package/icons/home-outline.svg +0 -1
  231. package/icons/image-outline.svg +0 -1
  232. package/icons/inbox-outline.svg +0 -1
  233. package/icons/info-outline.svg +0 -1
  234. package/icons/keypad-outline.svg +0 -1
  235. package/icons/layers-outline.svg +0 -1
  236. package/icons/layout-outline.svg +0 -1
  237. package/icons/link-2-outline.svg +0 -1
  238. package/icons/link-outline.svg +0 -1
  239. package/icons/linkedin-outline.svg +0 -1
  240. package/icons/list-outline.svg +0 -1
  241. package/icons/loader-outline.svg +0 -1
  242. package/icons/lock-outline.svg +0 -1
  243. package/icons/log-in-outline.svg +0 -1
  244. package/icons/log-out-outline.svg +0 -1
  245. package/icons/map-outline.svg +0 -1
  246. package/icons/maximize-outline.svg +0 -1
  247. package/icons/menu-2-outline.svg +0 -1
  248. package/icons/menu-arrow-outline.svg +0 -1
  249. package/icons/menu-outline.svg +0 -1
  250. package/icons/message-circle-outline.svg +0 -1
  251. package/icons/message-square-outline.svg +0 -1
  252. package/icons/mic-off-outline.svg +0 -1
  253. package/icons/mic-outline.svg +0 -1
  254. package/icons/minimize-outline.svg +0 -1
  255. package/icons/minus-circle-outline.svg +0 -1
  256. package/icons/minus-outline.svg +0 -1
  257. package/icons/minus-square-outline.svg +0 -1
  258. package/icons/monitor-outline.svg +0 -1
  259. package/icons/moon-outline.svg +0 -1
  260. package/icons/more-horizontal-outline.svg +0 -1
  261. package/icons/more-vertical-outline.svg +0 -1
  262. package/icons/move-outline.svg +0 -1
  263. package/icons/music-outline.svg +0 -1
  264. package/icons/navigation-2-outline.svg +0 -1
  265. package/icons/navigation-outline.svg +0 -1
  266. package/icons/npm-outline.svg +0 -1
  267. package/icons/options-2-outline.svg +0 -1
  268. package/icons/options-outline.svg +0 -1
  269. package/icons/pantone-outline.svg +0 -1
  270. package/icons/paper-plane-outline.svg +0 -1
  271. package/icons/pause-circle-outline.svg +0 -1
  272. package/icons/people-outline.svg +0 -1
  273. package/icons/percent-outline.svg +0 -1
  274. package/icons/person-add-outline.svg +0 -1
  275. package/icons/person-delete-outline.svg +0 -1
  276. package/icons/person-done-outline.svg +0 -1
  277. package/icons/person-outline.svg +0 -1
  278. package/icons/person-remove-outline.svg +0 -1
  279. package/icons/phone-call-outline.svg +0 -1
  280. package/icons/phone-missed-outline.svg +0 -1
  281. package/icons/phone-off-outline.svg +0 -1
  282. package/icons/phone-outline.svg +0 -1
  283. package/icons/pie-chart-outline.svg +0 -1
  284. package/icons/pin-outline.svg +0 -1
  285. package/icons/play-circle-outline.svg +0 -1
  286. package/icons/plus-circle-outline.svg +0 -1
  287. package/icons/plus-outline.svg +0 -1
  288. package/icons/plus-square-outline.svg +0 -1
  289. package/icons/power-outline.svg +0 -1
  290. package/icons/pricetags-outline.svg +0 -1
  291. package/icons/printer-outline.svg +0 -1
  292. package/icons/question-mark-circle-outline.svg +0 -1
  293. package/icons/question-mark-outline.svg +0 -1
  294. package/icons/radio-button-off-outline.svg +0 -1
  295. package/icons/radio-button-on-outline.svg +0 -1
  296. package/icons/radio-outline.svg +0 -1
  297. package/icons/recording-outline.svg +0 -1
  298. package/icons/refresh-outline.svg +0 -1
  299. package/icons/repeat-outline.svg +0 -1
  300. package/icons/rewind-left-outline.svg +0 -1
  301. package/icons/rewind-right-outline.svg +0 -1
  302. package/icons/save-outline.svg +0 -1
  303. package/icons/scissors-outline.svg +0 -1
  304. package/icons/search-outline.svg +0 -1
  305. package/icons/settings-2-outline.svg +0 -1
  306. package/icons/settings-outline.svg +0 -1
  307. package/icons/shake-outline.svg +0 -1
  308. package/icons/share-outline.svg +0 -1
  309. package/icons/shield-off-outline.svg +0 -1
  310. package/icons/shield-outline.svg +0 -1
  311. package/icons/shopping-bag-outline.svg +0 -1
  312. package/icons/shopping-cart-outline.svg +0 -1
  313. package/icons/shuffle-2-outline.svg +0 -1
  314. package/icons/shuffle-outline.svg +0 -1
  315. package/icons/skip-back-outline.svg +0 -1
  316. package/icons/skip-forward-outline.svg +0 -1
  317. package/icons/slash-outline.svg +0 -1
  318. package/icons/smartphone-outline.svg +0 -1
  319. package/icons/smiling-face-outline.svg +0 -1
  320. package/icons/speaker-outline.svg +0 -1
  321. package/icons/square-outline.svg +0 -1
  322. package/icons/star-outline.svg +0 -1
  323. package/icons/stop-circle-outline.svg +0 -1
  324. package/icons/sun-outline.svg +0 -1
  325. package/icons/swap-outline.svg +0 -1
  326. package/icons/sync-outline.svg +0 -1
  327. package/icons/text-outline.svg +0 -1
  328. package/icons/thermometer-minus-outline.svg +0 -1
  329. package/icons/thermometer-outline.svg +0 -1
  330. package/icons/thermometer-plus-outline.svg +0 -1
  331. package/icons/toggle-left-outline.svg +0 -1
  332. package/icons/toggle-right-outline.svg +0 -1
  333. package/icons/trash-2-outline.svg +0 -1
  334. package/icons/trash-outline.svg +0 -1
  335. package/icons/trending-down-outline.svg +0 -1
  336. package/icons/trending-up-outline.svg +0 -1
  337. package/icons/tv-outline.svg +0 -1
  338. package/icons/twitter-outline.svg +0 -1
  339. package/icons/umbrella-outline.svg +0 -1
  340. package/icons/undo-outline.svg +0 -1
  341. package/icons/unlock-outline.svg +0 -1
  342. package/icons/upload-outline.svg +0 -1
  343. package/icons/video-off-outline.svg +0 -1
  344. package/icons/video-outline.svg +0 -1
  345. package/icons/volume-down-outline.svg +0 -1
  346. package/icons/volume-mute-outline.svg +0 -1
  347. package/icons/volume-off-outline.svg +0 -1
  348. package/icons/volume-up-outline.svg +0 -1
  349. package/icons/wifi-off-outline.svg +0 -1
  350. package/icons/wifi-outline.svg +0 -1
  351. package/js/index.js +0 -718
  352. package/js/index.ts +0 -873
package/js/select.ts CHANGED
@@ -1,217 +1,217 @@
1
- class Select {
2
- private readonly element: HTMLSelectElement;
3
- private readonly isMultiselect: boolean;
4
-
5
- constructor(elementOrSelector: string | HTMLSelectElement) {
6
- const element = typeof elementOrSelector === 'string'
7
- ? document.querySelector<HTMLSelectElement>(elementOrSelector)
8
- : elementOrSelector;
9
-
10
- if (!element) {
11
- throw new Error(`Select: Element not found for selector "${elementOrSelector}"`);
12
- }
13
-
14
- this.element = element;
15
- const result = Select.initElement(element);
16
-
17
- if (result === null) {
18
- throw new Error(`Select: Failed to initialize select for "${elementOrSelector}"`);
19
- }
20
-
21
- this.isMultiselect = result;
22
- }
23
-
24
- public value(): string | string[] | undefined {
25
- if (!this.element) {
26
- return undefined;
27
- }
28
-
29
- const selectedValues = Array.from(this.element.options)
30
- .filter(option => option.selected)
31
- .map(option => option.value);
32
-
33
- return this.isMultiselect ? selectedValues : selectedValues[0];
34
- }
35
-
36
- public static init(elementOrSelector: string | HTMLSelectElement): boolean | null {
37
- const element = typeof elementOrSelector === 'string'
38
- ? document.querySelector<HTMLSelectElement>(elementOrSelector)
39
- : elementOrSelector;
40
-
41
- if (!element) {
42
- return null;
43
- }
44
-
45
- return Select.initElement(element);
46
- }
47
-
48
- private static initElement(element: HTMLSelectElement): boolean | null {
49
- if (!Select.transformSelect(element)) {
50
- return null;
51
- }
52
-
53
- const selectGroup = element.closest('.select-group');
54
- if (!selectGroup) {
55
- throw new Error(`Select: Parent .select-group not found for "${element}"`);
56
- }
57
-
58
- const dropdown = selectGroup.querySelector('.dropdown') as HTMLElement | null;
59
- if (!dropdown) {
60
- throw new Error(`Select: Dropdown element not found for "${element}"`);
61
- }
62
-
63
- const selected = dropdown.querySelector('.dropdown-selected') as HTMLElement | null;
64
- const options = dropdown.querySelector('.dropdown-options') as HTMLElement | null;
65
-
66
- if (!selected || !options) {
67
- throw new Error(`Select: Required dropdown elements not found for "${element}"`);
68
- }
69
-
70
- const isMulti = dropdown.dataset.multi === 'true';
71
-
72
- // Toggle dropdown on selected element click
73
- selected.addEventListener('click', () => {
74
- Select.closeAllDropdowns(dropdown);
75
- dropdown.classList.toggle('open');
76
- });
77
-
78
- // Handle option selection
79
- options.addEventListener('click', (e: Event) => {
80
- const target = e.target as HTMLElement;
81
-
82
- if (!target.classList.contains('dropdown-option')) {
83
- return;
84
- }
85
-
86
- if (isMulti) {
87
- Select.handleMultiSelect(target, options, selected, element);
88
- } else {
89
- Select.handleSingleSelect(target, options, selected, dropdown, element);
90
- }
91
- });
92
-
93
- // Close dropdown when clicking the close icon
94
- const closeIcon = options.querySelector('.dropdown-options-icon') as HTMLElement | null;
95
- if (closeIcon) {
96
- closeIcon.addEventListener('click', () => {
97
- dropdown.classList.remove('open');
98
- });
99
- }
100
-
101
- // Close dropdown when clicking outside
102
- document.addEventListener('click', (e: Event) => {
103
- if (!dropdown.contains(e.target as Node)) {
104
- dropdown.classList.remove('open');
105
- }
106
- });
107
-
108
- return isMulti;
109
- }
110
-
111
- private static closeAllDropdowns(exceptDropdown?: HTMLElement): void {
112
- document.querySelectorAll('.dropdown').forEach(dropdown => {
113
- if (dropdown !== exceptDropdown) {
114
- dropdown.classList.remove('open');
115
- }
116
- });
117
- }
118
-
119
- private static handleMultiSelect(
120
- option: HTMLElement,
121
- optionsContainer: HTMLElement,
122
- selected: HTMLElement,
123
- selectElement: HTMLSelectElement
124
- ): void {
125
- option.classList.toggle('selected');
126
-
127
- const selectedOptions = Array.from(
128
- optionsContainer.querySelectorAll('.dropdown-option.selected')
129
- ) as HTMLElement[];
130
-
131
- const values = selectedOptions.map(opt => opt.textContent?.trim() || '');
132
- selected.textContent = values.length ? values.join(', ') : 'Select options';
133
-
134
- const selectedValues = selectedOptions.map(opt => opt.dataset.value || '');
135
- Array.from(selectElement.options).forEach(opt => {
136
- opt.selected = selectedValues.includes(opt.value);
137
- });
138
- }
139
-
140
- private static handleSingleSelect(
141
- option: HTMLElement,
142
- optionsContainer: HTMLElement,
143
- selected: HTMLElement,
144
- dropdown: HTMLElement,
145
- selectElement: HTMLSelectElement
146
- ): void {
147
- optionsContainer.querySelectorAll('.dropdown-option').forEach(opt => {
148
- opt.classList.remove('selected');
149
- });
150
-
151
- option.classList.add('selected');
152
- selected.textContent = option.textContent?.trim() || '';
153
- dropdown.classList.remove('open');
154
- selectElement.value = option.dataset.value || '';
155
- }
156
-
157
- private static transformSelect(select: HTMLSelectElement): boolean {
158
- const parent = select.closest('.select-group') as HTMLElement | null;
159
-
160
- if (!parent) {
161
- return false;
162
- }
163
-
164
- const label = parent.querySelector('label');
165
- const isMulti = select.hasAttribute('multiple');
166
- const labelText = label?.textContent?.trim() || 'Select';
167
-
168
- // Create hidden wrapper for original select
169
- const hiddenWrapper = document.createElement('div');
170
- hiddenWrapper.classList.add('hidden');
171
-
172
- if (label) {
173
- hiddenWrapper.appendChild(label);
174
- }
175
- hiddenWrapper.appendChild(select);
176
-
177
- // Create dropdown structure
178
- const dropdown = document.createElement('div');
179
- dropdown.className = 'dropdown';
180
- dropdown.dataset.multi = String(isMulti);
181
-
182
- const dropdownSelected = document.createElement('div');
183
- dropdownSelected.className = 'dropdown-selected';
184
- dropdownSelected.textContent = labelText;
185
-
186
- const dropdownOptions = document.createElement('div');
187
- dropdownOptions.className = 'dropdown-options';
188
-
189
- // Add mobile menu
190
- const optionsMenu = document.createElement('div');
191
- optionsMenu.className = 'dropdown-options-menu hidden';
192
- optionsMenu.innerHTML = 'Select options<span class="dropdown-options-icon icon icon-close"></span>';
193
- dropdownOptions.appendChild(optionsMenu);
194
-
195
- // Create option elements
196
- Array.from(select.options).forEach(opt => {
197
- const optDiv = document.createElement('div');
198
- optDiv.className = 'dropdown-option';
199
- optDiv.dataset.value = opt.value;
200
- optDiv.textContent = opt.textContent;
201
- dropdownOptions.appendChild(optDiv);
202
- });
203
-
204
- // Assemble dropdown
205
- dropdown.appendChild(dropdownSelected);
206
- dropdown.appendChild(dropdownOptions);
207
-
208
- // Replace original content
209
- parent.innerHTML = '';
210
- parent.appendChild(hiddenWrapper);
211
- parent.appendChild(dropdown);
212
-
213
- return true;
214
- }
215
- }
216
-
1
+ class Select {
2
+ private readonly element: HTMLSelectElement;
3
+ private readonly isMultiselect: boolean;
4
+
5
+ constructor(elementOrSelector: string | HTMLSelectElement) {
6
+ const element = typeof elementOrSelector === 'string'
7
+ ? document.querySelector<HTMLSelectElement>(elementOrSelector)
8
+ : elementOrSelector;
9
+
10
+ if (!element) {
11
+ throw new Error(`Select: Element not found for selector "${elementOrSelector}"`);
12
+ }
13
+
14
+ this.element = element;
15
+ const result = Select.initElement(element);
16
+
17
+ if (result === null) {
18
+ throw new Error(`Select: Failed to initialize select for "${elementOrSelector}"`);
19
+ }
20
+
21
+ this.isMultiselect = result;
22
+ }
23
+
24
+ public value(): string | string[] | undefined {
25
+ if (!this.element) {
26
+ return undefined;
27
+ }
28
+
29
+ const selectedValues = Array.from(this.element.options)
30
+ .filter(option => option.selected)
31
+ .map(option => option.value);
32
+
33
+ return this.isMultiselect ? selectedValues : selectedValues[0];
34
+ }
35
+
36
+ public static init(elementOrSelector: string | HTMLSelectElement): boolean | null {
37
+ const element = typeof elementOrSelector === 'string'
38
+ ? document.querySelector<HTMLSelectElement>(elementOrSelector)
39
+ : elementOrSelector;
40
+
41
+ if (!element) {
42
+ return null;
43
+ }
44
+
45
+ return Select.initElement(element);
46
+ }
47
+
48
+ private static initElement(element: HTMLSelectElement): boolean | null {
49
+ if (!Select.transformSelect(element)) {
50
+ return null;
51
+ }
52
+
53
+ const selectGroup = element.closest('.select-group');
54
+ if (!selectGroup) {
55
+ throw new Error(`Select: Parent .select-group not found for "${element}"`);
56
+ }
57
+
58
+ const dropdown = selectGroup.querySelector('.dropdown') as HTMLElement | null;
59
+ if (!dropdown) {
60
+ throw new Error(`Select: Dropdown element not found for "${element}"`);
61
+ }
62
+
63
+ const selected = dropdown.querySelector('.dropdown-selected') as HTMLElement | null;
64
+ const options = dropdown.querySelector('.dropdown-options') as HTMLElement | null;
65
+
66
+ if (!selected || !options) {
67
+ throw new Error(`Select: Required dropdown elements not found for "${element}"`);
68
+ }
69
+
70
+ const isMulti = dropdown.dataset.multi === 'true';
71
+
72
+ // Toggle dropdown on selected element click
73
+ selected.addEventListener('click', () => {
74
+ Select.closeAllDropdowns(dropdown);
75
+ dropdown.classList.toggle('open');
76
+ });
77
+
78
+ // Handle option selection
79
+ options.addEventListener('click', (e: Event) => {
80
+ const target = e.target as HTMLElement;
81
+
82
+ if (!target.classList.contains('dropdown-option')) {
83
+ return;
84
+ }
85
+
86
+ if (isMulti) {
87
+ Select.handleMultiSelect(target, options, selected, element);
88
+ } else {
89
+ Select.handleSingleSelect(target, options, selected, dropdown, element);
90
+ }
91
+ });
92
+
93
+ // Close dropdown when clicking the close icon
94
+ const closeIcon = options.querySelector('.dropdown-options-icon') as HTMLElement | null;
95
+ if (closeIcon) {
96
+ closeIcon.addEventListener('click', () => {
97
+ dropdown.classList.remove('open');
98
+ });
99
+ }
100
+
101
+ // Close dropdown when clicking outside
102
+ document.addEventListener('click', (e: Event) => {
103
+ if (!dropdown.contains(e.target as Node)) {
104
+ dropdown.classList.remove('open');
105
+ }
106
+ });
107
+
108
+ return isMulti;
109
+ }
110
+
111
+ private static closeAllDropdowns(exceptDropdown?: HTMLElement): void {
112
+ document.querySelectorAll('.dropdown').forEach(dropdown => {
113
+ if (dropdown !== exceptDropdown) {
114
+ dropdown.classList.remove('open');
115
+ }
116
+ });
117
+ }
118
+
119
+ private static handleMultiSelect(
120
+ option: HTMLElement,
121
+ optionsContainer: HTMLElement,
122
+ selected: HTMLElement,
123
+ selectElement: HTMLSelectElement
124
+ ): void {
125
+ option.classList.toggle('selected');
126
+
127
+ const selectedOptions = Array.from(
128
+ optionsContainer.querySelectorAll('.dropdown-option.selected')
129
+ ) as HTMLElement[];
130
+
131
+ const values = selectedOptions.map(opt => opt.textContent?.trim() || '');
132
+ selected.textContent = values.length ? values.join(', ') : 'Select options';
133
+
134
+ const selectedValues = selectedOptions.map(opt => opt.dataset.value || '');
135
+ Array.from(selectElement.options).forEach(opt => {
136
+ opt.selected = selectedValues.includes(opt.value);
137
+ });
138
+ }
139
+
140
+ private static handleSingleSelect(
141
+ option: HTMLElement,
142
+ optionsContainer: HTMLElement,
143
+ selected: HTMLElement,
144
+ dropdown: HTMLElement,
145
+ selectElement: HTMLSelectElement
146
+ ): void {
147
+ optionsContainer.querySelectorAll('.dropdown-option').forEach(opt => {
148
+ opt.classList.remove('selected');
149
+ });
150
+
151
+ option.classList.add('selected');
152
+ selected.textContent = option.textContent?.trim() || '';
153
+ dropdown.classList.remove('open');
154
+ selectElement.value = option.dataset.value || '';
155
+ }
156
+
157
+ private static transformSelect(select: HTMLSelectElement): boolean {
158
+ const parent = select.closest('.select-group') as HTMLElement | null;
159
+
160
+ if (!parent) {
161
+ return false;
162
+ }
163
+
164
+ const label = parent.querySelector('label');
165
+ const isMulti = select.hasAttribute('multiple');
166
+ const labelText = label?.textContent?.trim() || 'Select';
167
+
168
+ // Create hidden wrapper for original select
169
+ const hiddenWrapper = document.createElement('div');
170
+ hiddenWrapper.classList.add('hidden');
171
+
172
+ if (label) {
173
+ hiddenWrapper.appendChild(label);
174
+ }
175
+ hiddenWrapper.appendChild(select);
176
+
177
+ // Create dropdown structure
178
+ const dropdown = document.createElement('div');
179
+ dropdown.className = 'dropdown';
180
+ dropdown.dataset.multi = String(isMulti);
181
+
182
+ const dropdownSelected = document.createElement('div');
183
+ dropdownSelected.className = 'dropdown-selected';
184
+ dropdownSelected.textContent = labelText;
185
+
186
+ const dropdownOptions = document.createElement('div');
187
+ dropdownOptions.className = 'dropdown-options';
188
+
189
+ // Add mobile menu
190
+ const optionsMenu = document.createElement('div');
191
+ optionsMenu.className = 'dropdown-options-menu hidden';
192
+ optionsMenu.innerHTML = 'Select options<span class="dropdown-options-icon icon icon-close"></span>';
193
+ dropdownOptions.appendChild(optionsMenu);
194
+
195
+ // Create option elements
196
+ Array.from(select.options).forEach(opt => {
197
+ const optDiv = document.createElement('div');
198
+ optDiv.className = 'dropdown-option';
199
+ optDiv.dataset.value = opt.value;
200
+ optDiv.textContent = opt.textContent;
201
+ dropdownOptions.appendChild(optDiv);
202
+ });
203
+
204
+ // Assemble dropdown
205
+ dropdown.appendChild(dropdownSelected);
206
+ dropdown.appendChild(dropdownOptions);
207
+
208
+ // Replace original content
209
+ parent.innerHTML = '';
210
+ parent.appendChild(hiddenWrapper);
211
+ parent.appendChild(dropdown);
212
+
213
+ return true;
214
+ }
215
+ }
216
+
217
217
  export { Select };
@@ -0,0 +1,41 @@
1
+ class SidebarNav {
2
+ constructor(containerOrSelector, options = {}) {
3
+ const container = typeof containerOrSelector === 'string'
4
+ ? document.querySelector(containerOrSelector)
5
+ : containerOrSelector;
6
+ this.opts = {
7
+ toggleSelector: options.toggleSelector ?? '.sidebar-toggle',
8
+ breakpoint: options.breakpoint ?? 768,
9
+ };
10
+ this.nav = container?.querySelector('.sidebar-nav') ?? null;
11
+ this.backdrop = container?.querySelector('.sidebar-backdrop') ?? null;
12
+ this.toggleBtn = document.querySelector(this.opts.toggleSelector);
13
+ this._onToggle = () => this.toggle();
14
+ this._onBackdrop = () => this.close();
15
+ this._onResize = () => { if (window.innerWidth > this.opts.breakpoint)
16
+ this.close(); };
17
+ this.toggleBtn?.addEventListener('click', this._onToggle);
18
+ this.backdrop?.addEventListener('click', this._onBackdrop);
19
+ window.addEventListener('resize', this._onResize);
20
+ }
21
+ open() {
22
+ this.nav?.classList.add('is-open');
23
+ this.backdrop?.classList.add('is-visible');
24
+ }
25
+ close() {
26
+ this.nav?.classList.remove('is-open');
27
+ this.backdrop?.classList.remove('is-visible');
28
+ }
29
+ toggle() {
30
+ this.nav?.classList.contains('is-open') ? this.close() : this.open();
31
+ }
32
+ isOpen() {
33
+ return this.nav?.classList.contains('is-open') ?? false;
34
+ }
35
+ destroy() {
36
+ this.toggleBtn?.removeEventListener('click', this._onToggle);
37
+ this.backdrop?.removeEventListener('click', this._onBackdrop);
38
+ window.removeEventListener('resize', this._onResize);
39
+ }
40
+ }
41
+ export { SidebarNav };
@@ -0,0 +1,66 @@
1
+ interface SidebarNavOptions {
2
+ /** Selector for the toggle button. Default: '.sidebar-toggle' */
3
+ toggleSelector?: string;
4
+ /** Breakpoint (px) above which the sidebar is always visible. Default: 768 */
5
+ breakpoint?: number;
6
+ }
7
+
8
+ class SidebarNav {
9
+ private nav: HTMLElement | null;
10
+ private backdrop: HTMLElement | null;
11
+ private toggleBtn: HTMLElement | null;
12
+ private opts: Required<SidebarNavOptions>;
13
+ private _onToggle: () => void;
14
+ private _onBackdrop: () => void;
15
+ private _onResize: () => void;
16
+
17
+ constructor(containerOrSelector: string | HTMLElement, options: SidebarNavOptions = {}) {
18
+ const container: HTMLElement | null =
19
+ typeof containerOrSelector === 'string'
20
+ ? (document.querySelector(containerOrSelector) as HTMLElement | null)
21
+ : containerOrSelector;
22
+
23
+ this.opts = {
24
+ toggleSelector: options.toggleSelector ?? '.sidebar-toggle',
25
+ breakpoint: options.breakpoint ?? 768,
26
+ };
27
+
28
+ this.nav = container?.querySelector('.sidebar-nav') ?? null;
29
+ this.backdrop = container?.querySelector('.sidebar-backdrop') ?? null;
30
+ this.toggleBtn = document.querySelector(this.opts.toggleSelector);
31
+
32
+ this._onToggle = () => this.toggle();
33
+ this._onBackdrop = () => this.close();
34
+ this._onResize = () => { if (window.innerWidth > this.opts.breakpoint) this.close(); };
35
+
36
+ this.toggleBtn?.addEventListener('click', this._onToggle);
37
+ this.backdrop?.addEventListener('click', this._onBackdrop);
38
+ window.addEventListener('resize', this._onResize);
39
+ }
40
+
41
+ open(): void {
42
+ this.nav?.classList.add('is-open');
43
+ this.backdrop?.classList.add('is-visible');
44
+ }
45
+
46
+ close(): void {
47
+ this.nav?.classList.remove('is-open');
48
+ this.backdrop?.classList.remove('is-visible');
49
+ }
50
+
51
+ toggle(): void {
52
+ this.nav?.classList.contains('is-open') ? this.close() : this.open();
53
+ }
54
+
55
+ isOpen(): boolean {
56
+ return this.nav?.classList.contains('is-open') ?? false;
57
+ }
58
+
59
+ destroy(): void {
60
+ this.toggleBtn?.removeEventListener('click', this._onToggle);
61
+ this.backdrop?.removeEventListener('click', this._onBackdrop);
62
+ window.removeEventListener('resize', this._onResize);
63
+ }
64
+ }
65
+
66
+ export { SidebarNav, SidebarNavOptions };
package/js/stepper.js ADDED
@@ -0,0 +1,80 @@
1
+ class Stepper {
2
+ constructor(elementOrSelector, options = {}) {
3
+ const element = typeof elementOrSelector === 'string'
4
+ ? document.querySelector(elementOrSelector)
5
+ : elementOrSelector;
6
+ if (!element)
7
+ throw new Error(`Stepper: element not found`);
8
+ this.container = element;
9
+ this.steps = Array.from(this.container.querySelectorAll('.stepper-step'));
10
+ this.connectors = Array.from(this.container.querySelectorAll('.stepper-connector'));
11
+ this.onChange = options.onChange;
12
+ this.current = options.defaultStep ?? 0;
13
+ if (this.steps.length === 0) {
14
+ console.warn('Stepper: no .stepper-step elements found');
15
+ return;
16
+ }
17
+ if (options.clickable) {
18
+ this.container.classList.add('stepper-clickable');
19
+ this.steps.forEach((step, i) => {
20
+ step.addEventListener('click', () => this.goTo(i));
21
+ });
22
+ }
23
+ this.render();
24
+ }
25
+ render() {
26
+ this.steps.forEach((step, i) => {
27
+ step.classList.remove('active', 'completed');
28
+ if (i < this.current)
29
+ step.classList.add('completed');
30
+ else if (i === this.current)
31
+ step.classList.add('active');
32
+ });
33
+ this.connectors.forEach((connector, i) => {
34
+ connector.classList.toggle('completed', i < this.current);
35
+ });
36
+ }
37
+ next() {
38
+ if (this.current < this.steps.length - 1) {
39
+ this.goTo(this.current + 1);
40
+ }
41
+ }
42
+ prev() {
43
+ if (this.current > 0) {
44
+ this.goTo(this.current - 1);
45
+ }
46
+ }
47
+ goTo(index) {
48
+ if (index < 0 || index >= this.steps.length)
49
+ return;
50
+ const previous = this.current;
51
+ this.current = index;
52
+ this.render();
53
+ if (this.onChange && previous !== index) {
54
+ this.onChange(index, previous);
55
+ }
56
+ }
57
+ setError(index) {
58
+ if (index < 0 || index >= this.steps.length)
59
+ return;
60
+ this.steps[index].classList.add('error');
61
+ }
62
+ clearError(index) {
63
+ if (index < 0 || index >= this.steps.length)
64
+ return;
65
+ this.steps[index].classList.remove('error');
66
+ }
67
+ getStep() {
68
+ return this.current;
69
+ }
70
+ getStepCount() {
71
+ return this.steps.length;
72
+ }
73
+ isFirst() {
74
+ return this.current === 0;
75
+ }
76
+ isLast() {
77
+ return this.current === this.steps.length - 1;
78
+ }
79
+ }
80
+ export { Stepper };