@dodlhuat/basix 1.1.0 → 1.2.0

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 (274) hide show
  1. package/README.md +651 -482
  2. package/css/badge.scss +104 -0
  3. package/css/bottom-sheet.scss +192 -0
  4. package/css/breadcrumb.scss +158 -0
  5. package/css/context-menu.scss +182 -0
  6. package/css/editor.scss +628 -461
  7. package/css/form.scss +139 -0
  8. package/css/stepper.scss +212 -0
  9. package/css/style.css +1495 -70
  10. package/css/style.css.map +1 -1
  11. package/css/style.min.css +1 -1
  12. package/css/style.scss +7 -1
  13. package/css/typography.scss +194 -161
  14. package/js/bottom-sheet.js +173 -0
  15. package/js/bottom-sheet.ts +222 -0
  16. package/js/carousel.js +26 -13
  17. package/js/context-menu.js +212 -0
  18. package/js/context-menu.ts +252 -0
  19. package/js/editor.js +46 -32
  20. package/js/editor.ts +56 -37
  21. package/js/gallery.js +11 -10
  22. package/js/index.js +472 -374
  23. package/js/index.ts +116 -2
  24. package/js/push-menu.js +113 -113
  25. package/js/stepper.js +80 -0
  26. package/js/stepper.ts +104 -0
  27. package/js/timepicker.js +21 -8
  28. package/package.json +3 -2
  29. package/fonts/Outfit-VariableFont_wght.woff +0 -0
  30. package/fonts/material-icons.woff2 +0 -0
  31. package/icons/activity-outline.svg +0 -1
  32. package/icons/alert-circle-outline.svg +0 -1
  33. package/icons/alert-triangle-outline.svg +0 -1
  34. package/icons/archive-outline.svg +0 -1
  35. package/icons/arrow-back-outline.svg +0 -1
  36. package/icons/arrow-circle-down-outline.svg +0 -1
  37. package/icons/arrow-circle-left-outline.svg +0 -1
  38. package/icons/arrow-circle-right-outline.svg +0 -1
  39. package/icons/arrow-circle-up-outline.svg +0 -1
  40. package/icons/arrow-down-outline.svg +0 -1
  41. package/icons/arrow-downward-outline.svg +0 -1
  42. package/icons/arrow-forward-outline.svg +0 -1
  43. package/icons/arrow-ios-back-outline.svg +0 -1
  44. package/icons/arrow-ios-downward-outline.svg +0 -1
  45. package/icons/arrow-ios-forward-outline.svg +0 -1
  46. package/icons/arrow-ios-upward-outline.svg +0 -1
  47. package/icons/arrow-left-outline.svg +0 -1
  48. package/icons/arrow-right-outline.svg +0 -1
  49. package/icons/arrow-up-outline.svg +0 -1
  50. package/icons/arrow-upward-outline.svg +0 -1
  51. package/icons/arrowhead-down-outline.svg +0 -1
  52. package/icons/arrowhead-left-outline.svg +0 -1
  53. package/icons/arrowhead-right-outline.svg +0 -1
  54. package/icons/arrowhead-up-outline.svg +0 -1
  55. package/icons/at-outline.svg +0 -1
  56. package/icons/attach-2-outline.svg +0 -1
  57. package/icons/attach-outline.svg +0 -1
  58. package/icons/award-outline.svg +0 -1
  59. package/icons/backspace-outline.svg +0 -1
  60. package/icons/bar-chart-2-outline.svg +0 -1
  61. package/icons/bar-chart-outline.svg +0 -1
  62. package/icons/battery-outline.svg +0 -1
  63. package/icons/behance-outline.svg +0 -1
  64. package/icons/bell-off-outline.svg +0 -1
  65. package/icons/bell-outline.svg +0 -1
  66. package/icons/bluetooth-outline.svg +0 -1
  67. package/icons/book-open-outline.svg +0 -1
  68. package/icons/book-outline.svg +0 -1
  69. package/icons/bookmark-outline.svg +0 -1
  70. package/icons/briefcase-outline.svg +0 -1
  71. package/icons/browser-outline.svg +0 -1
  72. package/icons/brush-outline.svg +0 -1
  73. package/icons/bulb-outline.svg +0 -1
  74. package/icons/calendar-outline.svg +0 -1
  75. package/icons/camera-outline.svg +0 -1
  76. package/icons/car-outline.svg +0 -1
  77. package/icons/cast-outline.svg +0 -1
  78. package/icons/charging-outline.svg +0 -1
  79. package/icons/checkmark-circle-2-outline.svg +0 -1
  80. package/icons/checkmark-circle-outline.svg +0 -1
  81. package/icons/checkmark-outline.svg +0 -1
  82. package/icons/checkmark-square-2-outline.svg +0 -1
  83. package/icons/checkmark-square-outline.svg +0 -1
  84. package/icons/chevron-down-outline.svg +0 -1
  85. package/icons/chevron-left-outline.svg +0 -1
  86. package/icons/chevron-right-outline.svg +0 -1
  87. package/icons/chevron-up-outline.svg +0 -1
  88. package/icons/clipboard-outline.svg +0 -1
  89. package/icons/clock-outline.svg +0 -1
  90. package/icons/close-circle-outline.svg +0 -1
  91. package/icons/close-outline.svg +0 -1
  92. package/icons/close-square-outline.svg +0 -1
  93. package/icons/cloud-download-outline.svg +0 -1
  94. package/icons/cloud-upload-outline.svg +0 -1
  95. package/icons/code-download-outline.svg +0 -1
  96. package/icons/code-outline.svg +0 -1
  97. package/icons/collapse-outline.svg +0 -1
  98. package/icons/color-palette-outline.svg +0 -1
  99. package/icons/color-picker-outline.svg +0 -1
  100. package/icons/compass-outline.svg +0 -1
  101. package/icons/copy-outline.svg +0 -1
  102. package/icons/corner-down-left-outline.svg +0 -1
  103. package/icons/corner-down-right-outline.svg +0 -1
  104. package/icons/corner-left-down-outline.svg +0 -1
  105. package/icons/corner-left-up-outline.svg +0 -1
  106. package/icons/corner-right-down-outline.svg +0 -1
  107. package/icons/corner-right-up-outline.svg +0 -1
  108. package/icons/corner-up-left-outline.svg +0 -1
  109. package/icons/corner-up-right-outline.svg +0 -1
  110. package/icons/credit-card-outline.svg +0 -1
  111. package/icons/crop-outline.svg +0 -1
  112. package/icons/cube-outline.svg +0 -1
  113. package/icons/diagonal-arrow-left-down-outline.svg +0 -1
  114. package/icons/diagonal-arrow-left-up-outline.svg +0 -1
  115. package/icons/diagonal-arrow-right-down-outline.svg +0 -1
  116. package/icons/diagonal-arrow-right-up-outline.svg +0 -1
  117. package/icons/done-all-outline.svg +0 -1
  118. package/icons/download-outline.svg +0 -1
  119. package/icons/droplet-off-outline.svg +0 -1
  120. package/icons/droplet-outline.svg +0 -1
  121. package/icons/edit-2-outline.svg +0 -1
  122. package/icons/edit-outline.svg +0 -1
  123. package/icons/email-outline.svg +0 -1
  124. package/icons/expand-outline.svg +0 -1
  125. package/icons/external-link-outline.svg +0 -1
  126. package/icons/eye-off-2-outline.svg +0 -1
  127. package/icons/eye-off-outline.svg +0 -1
  128. package/icons/eye-outline.svg +0 -1
  129. package/icons/facebook-outline.svg +0 -1
  130. package/icons/file-add-outline.svg +0 -1
  131. package/icons/file-outline.svg +0 -1
  132. package/icons/file-remove-outline.svg +0 -1
  133. package/icons/file-text-outline.svg +0 -1
  134. package/icons/film-outline.svg +0 -1
  135. package/icons/flag-outline.svg +0 -1
  136. package/icons/flash-off-outline.svg +0 -1
  137. package/icons/flash-outline.svg +0 -1
  138. package/icons/flip-2-outline.svg +0 -1
  139. package/icons/flip-outline.svg +0 -1
  140. package/icons/folder-add-outline.svg +0 -1
  141. package/icons/folder-outline.svg +0 -1
  142. package/icons/folder-remove-outline.svg +0 -1
  143. package/icons/funnel-outline.svg +0 -1
  144. package/icons/gift-outline.svg +0 -1
  145. package/icons/github-outline.svg +0 -1
  146. package/icons/globe-2-outline.svg +0 -1
  147. package/icons/globe-outline.svg +0 -1
  148. package/icons/google-outline.svg +0 -1
  149. package/icons/grid-outline.svg +0 -1
  150. package/icons/hard-drive-outline.svg +0 -1
  151. package/icons/hash-outline.svg +0 -1
  152. package/icons/headphones-outline.svg +0 -1
  153. package/icons/heart-outline.svg +0 -1
  154. package/icons/home-outline.svg +0 -1
  155. package/icons/image-outline.svg +0 -1
  156. package/icons/inbox-outline.svg +0 -1
  157. package/icons/info-outline.svg +0 -1
  158. package/icons/keypad-outline.svg +0 -1
  159. package/icons/layers-outline.svg +0 -1
  160. package/icons/layout-outline.svg +0 -1
  161. package/icons/link-2-outline.svg +0 -1
  162. package/icons/link-outline.svg +0 -1
  163. package/icons/linkedin-outline.svg +0 -1
  164. package/icons/list-outline.svg +0 -1
  165. package/icons/loader-outline.svg +0 -1
  166. package/icons/lock-outline.svg +0 -1
  167. package/icons/log-in-outline.svg +0 -1
  168. package/icons/log-out-outline.svg +0 -1
  169. package/icons/map-outline.svg +0 -1
  170. package/icons/maximize-outline.svg +0 -1
  171. package/icons/menu-2-outline.svg +0 -1
  172. package/icons/menu-arrow-outline.svg +0 -1
  173. package/icons/menu-outline.svg +0 -1
  174. package/icons/message-circle-outline.svg +0 -1
  175. package/icons/message-square-outline.svg +0 -1
  176. package/icons/mic-off-outline.svg +0 -1
  177. package/icons/mic-outline.svg +0 -1
  178. package/icons/minimize-outline.svg +0 -1
  179. package/icons/minus-circle-outline.svg +0 -1
  180. package/icons/minus-outline.svg +0 -1
  181. package/icons/minus-square-outline.svg +0 -1
  182. package/icons/monitor-outline.svg +0 -1
  183. package/icons/moon-outline.svg +0 -1
  184. package/icons/more-horizontal-outline.svg +0 -1
  185. package/icons/more-vertical-outline.svg +0 -1
  186. package/icons/move-outline.svg +0 -1
  187. package/icons/music-outline.svg +0 -1
  188. package/icons/navigation-2-outline.svg +0 -1
  189. package/icons/navigation-outline.svg +0 -1
  190. package/icons/npm-outline.svg +0 -1
  191. package/icons/options-2-outline.svg +0 -1
  192. package/icons/options-outline.svg +0 -1
  193. package/icons/pantone-outline.svg +0 -1
  194. package/icons/paper-plane-outline.svg +0 -1
  195. package/icons/pause-circle-outline.svg +0 -1
  196. package/icons/people-outline.svg +0 -1
  197. package/icons/percent-outline.svg +0 -1
  198. package/icons/person-add-outline.svg +0 -1
  199. package/icons/person-delete-outline.svg +0 -1
  200. package/icons/person-done-outline.svg +0 -1
  201. package/icons/person-outline.svg +0 -1
  202. package/icons/person-remove-outline.svg +0 -1
  203. package/icons/phone-call-outline.svg +0 -1
  204. package/icons/phone-missed-outline.svg +0 -1
  205. package/icons/phone-off-outline.svg +0 -1
  206. package/icons/phone-outline.svg +0 -1
  207. package/icons/pie-chart-outline.svg +0 -1
  208. package/icons/pin-outline.svg +0 -1
  209. package/icons/play-circle-outline.svg +0 -1
  210. package/icons/plus-circle-outline.svg +0 -1
  211. package/icons/plus-outline.svg +0 -1
  212. package/icons/plus-square-outline.svg +0 -1
  213. package/icons/power-outline.svg +0 -1
  214. package/icons/pricetags-outline.svg +0 -1
  215. package/icons/printer-outline.svg +0 -1
  216. package/icons/question-mark-circle-outline.svg +0 -1
  217. package/icons/question-mark-outline.svg +0 -1
  218. package/icons/radio-button-off-outline.svg +0 -1
  219. package/icons/radio-button-on-outline.svg +0 -1
  220. package/icons/radio-outline.svg +0 -1
  221. package/icons/recording-outline.svg +0 -1
  222. package/icons/refresh-outline.svg +0 -1
  223. package/icons/repeat-outline.svg +0 -1
  224. package/icons/rewind-left-outline.svg +0 -1
  225. package/icons/rewind-right-outline.svg +0 -1
  226. package/icons/save-outline.svg +0 -1
  227. package/icons/scissors-outline.svg +0 -1
  228. package/icons/search-outline.svg +0 -1
  229. package/icons/settings-2-outline.svg +0 -1
  230. package/icons/settings-outline.svg +0 -1
  231. package/icons/shake-outline.svg +0 -1
  232. package/icons/share-outline.svg +0 -1
  233. package/icons/shield-off-outline.svg +0 -1
  234. package/icons/shield-outline.svg +0 -1
  235. package/icons/shopping-bag-outline.svg +0 -1
  236. package/icons/shopping-cart-outline.svg +0 -1
  237. package/icons/shuffle-2-outline.svg +0 -1
  238. package/icons/shuffle-outline.svg +0 -1
  239. package/icons/skip-back-outline.svg +0 -1
  240. package/icons/skip-forward-outline.svg +0 -1
  241. package/icons/slash-outline.svg +0 -1
  242. package/icons/smartphone-outline.svg +0 -1
  243. package/icons/smiling-face-outline.svg +0 -1
  244. package/icons/speaker-outline.svg +0 -1
  245. package/icons/square-outline.svg +0 -1
  246. package/icons/star-outline.svg +0 -1
  247. package/icons/stop-circle-outline.svg +0 -1
  248. package/icons/sun-outline.svg +0 -1
  249. package/icons/swap-outline.svg +0 -1
  250. package/icons/sync-outline.svg +0 -1
  251. package/icons/text-outline.svg +0 -1
  252. package/icons/thermometer-minus-outline.svg +0 -1
  253. package/icons/thermometer-outline.svg +0 -1
  254. package/icons/thermometer-plus-outline.svg +0 -1
  255. package/icons/toggle-left-outline.svg +0 -1
  256. package/icons/toggle-right-outline.svg +0 -1
  257. package/icons/trash-2-outline.svg +0 -1
  258. package/icons/trash-outline.svg +0 -1
  259. package/icons/trending-down-outline.svg +0 -1
  260. package/icons/trending-up-outline.svg +0 -1
  261. package/icons/tv-outline.svg +0 -1
  262. package/icons/twitter-outline.svg +0 -1
  263. package/icons/umbrella-outline.svg +0 -1
  264. package/icons/undo-outline.svg +0 -1
  265. package/icons/unlock-outline.svg +0 -1
  266. package/icons/upload-outline.svg +0 -1
  267. package/icons/video-off-outline.svg +0 -1
  268. package/icons/video-outline.svg +0 -1
  269. package/icons/volume-down-outline.svg +0 -1
  270. package/icons/volume-mute-outline.svg +0 -1
  271. package/icons/volume-off-outline.svg +0 -1
  272. package/icons/volume-up-outline.svg +0 -1
  273. package/icons/wifi-off-outline.svg +0 -1
  274. package/icons/wifi-outline.svg +0 -1
package/js/index.ts CHANGED
@@ -18,6 +18,10 @@ import {Dropdown, DropdownSelectDetail} from "./dropdown.js";
18
18
  import {VirtualDropdown} from "./virtual-dropdown.js";
19
19
  import {TimeSpanPicker} from "./timepicker.js";
20
20
  import {RangeSlider} from "./range-slider.js";
21
+ import {BottomSheet} from "./bottom-sheet.js";
22
+ import {Editor} from "./editor.js";
23
+ import {Stepper} from "./stepper.js";
24
+ import {ContextMenu} from "./context-menu.js";
21
25
 
22
26
  // Generate sample table data
23
27
  const generateData = (count: number): TableRow[] => {
@@ -284,7 +288,7 @@ utils.ready(() => {
284
288
  let indexNumber = 1;
285
289
  const gallery = new MasonryGallery("gallery", {
286
290
  minColumnWidth: 300,
287
- fetchFunction: new Promise((resolve) => {
291
+ fetchFunction: () => new Promise<ImageData[]>((resolve) => {
288
292
  setTimeout(() => {
289
293
  const images: ImageData[] = [];
290
294
 
@@ -350,11 +354,56 @@ utils.ready(() => {
350
354
  },
351
355
  });
352
356
 
357
+ // Initialize bottom sheet
358
+ const bottomSheetTrigger = document.querySelector('.show-bottom-sheet');
359
+ if (bottomSheetTrigger) {
360
+ bottomSheetTrigger.addEventListener('click', () => {
361
+ const buttons = '<div class="buttons"><button class="button-light">Cancel</button>&nbsp;<button>Confirm</button></div>';
362
+ const sheet = new BottomSheet({
363
+ content: '<p>This is the bottom sheet content. It slides up from the bottom and can be dismissed by dragging down, tapping the backdrop, or pressing Escape.</p>',
364
+ header: 'Bottom Sheet',
365
+ footer: buttons,
366
+ closeable: true,
367
+ snapHeight: 'auto',
368
+ });
369
+ sheet.show();
370
+ });
371
+ }
372
+
373
+ // Initialize context menu demo
374
+ new ContextMenu('.context-menu-target', [
375
+ { group: 'File' },
376
+ { label: 'Open', icon: 'folder_open', shortcut: '⌘O', action: () => {} },
377
+ { label: 'Rename', icon: 'edit', shortcut: 'F2', action: () => {} },
378
+ { label: 'Duplicate', icon: 'library_add', action: () => {} },
379
+ 'separator',
380
+ {
381
+ label: 'Share',
382
+ icon: 'send',
383
+ submenu: [
384
+ { label: 'Copy link', icon: 'attachment', action: () => {} },
385
+ { label: 'Send by mail', icon: 'mail', action: () => {} },
386
+ ]
387
+ },
388
+ 'separator',
389
+ { label: 'Delete', icon: 'delete', shortcut: '⌫', destructive: true, action: () => {} },
390
+ ]);
391
+
392
+ // Initialize stepper demo
393
+ const stepperEl = document.querySelector<HTMLElement>('#stepper-demo');
394
+ if (stepperEl) {
395
+ const stepper = new Stepper(stepperEl, { defaultStep: 1 });
396
+ document.querySelector('#stepper-next')?.addEventListener('click', () => stepper.next());
397
+ document.querySelector('#stepper-prev')?.addEventListener('click', () => stepper.prev());
398
+ }
399
+
353
400
  // Initialize range sliders
354
401
  RangeSlider.initAll();
355
402
 
356
403
  Tooltip.initializeAll();
357
404
 
405
+ new Editor({ simple: true });
406
+
358
407
  const timeSpanPicker = new TimeSpanPicker('timespan-1', {
359
408
  onChange: (start, end) => {
360
409
  console.log(`Start: ${start}, Ende: ${end}`);
@@ -532,6 +581,18 @@ dropdownElement?.addEventListener("dropdown-select", ((
532
581
  }) as EventListener);`,
533
582
  "js",
534
583
  );
584
+ new CodeViewer(
585
+ "#usage-bottom-sheet-demo",
586
+ `const sheet = new BottomSheet({
587
+ content: '<p>Sheet content here.</p>',
588
+ header: 'Title',
589
+ footer: '<div class="buttons"><button>Confirm</button></div>',
590
+ closeable: true,
591
+ snapHeight: 'auto',
592
+ });
593
+ sheet.show();`,
594
+ "js",
595
+ );
535
596
  new CodeViewer(
536
597
  "#usage-modal-demo",
537
598
  `const modal = new Modal(
@@ -586,6 +647,40 @@ new CodeViewer(
586
647
  </div>`,
587
648
  "html",
588
649
  );
650
+ new CodeViewer(
651
+ "#usage-stepper-demo",
652
+ `<div class="stepper">
653
+ <div class="stepper-step completed">
654
+ <div class="stepper-indicator">
655
+ <svg class="icon-svg"><use href="svg-icons/icons.svg#check"/></svg>
656
+ </div>
657
+ <div class="stepper-label">
658
+ <span class="stepper-title">Account</span>
659
+ </div>
660
+ </div>
661
+ <div class="stepper-connector completed"></div>
662
+ <div class="stepper-step active">
663
+ <div class="stepper-indicator">2</div>
664
+ <div class="stepper-label">
665
+ <span class="stepper-title">Profile</span>
666
+ </div>
667
+ </div>
668
+ <div class="stepper-connector"></div>
669
+ <div class="stepper-step">
670
+ <div class="stepper-indicator">3</div>
671
+ <div class="stepper-label">
672
+ <span class="stepper-title">Review</span>
673
+ </div>
674
+ </div>
675
+ </div>
676
+
677
+ const stepper = new Stepper('#my-stepper');
678
+ stepper.next();
679
+ stepper.prev();
680
+ stepper.goTo(2);
681
+ stepper.setError(1);`,
682
+ "html",
683
+ );
589
684
  new CodeViewer(
590
685
  "#usage-accordion-demo",
591
686
  `<div class="accordion">
@@ -690,6 +785,25 @@ new CodeViewer(
690
785
  `<span class="placeholder w-6">`,
691
786
  "html"
692
787
  );
788
+ new CodeViewer(
789
+ "#usage-context-menu-demo",
790
+ `new ContextMenu('.my-element', [
791
+ { group: 'File' },
792
+ { label: 'Open', icon: 'folder_open', shortcut: '⌘O', action: (t) => {} },
793
+ { label: 'Rename', icon: 'edit', shortcut: 'F2', action: (t) => {} },
794
+ 'separator',
795
+ {
796
+ label: 'Share', icon: 'send',
797
+ submenu: [
798
+ { label: 'Copy link', icon: 'attachment', action: (t) => {} },
799
+ { label: 'Send by mail', icon: 'mail', action: (t) => {} },
800
+ ]
801
+ },
802
+ 'separator',
803
+ { label: 'Delete', icon: 'delete', destructive: true, action: (t) => {} },
804
+ ]);`,
805
+ "javascript",
806
+ );
693
807
  new CodeViewer(
694
808
  "#usage-table-demo",
695
809
  `const columns: TableColumn[] = [
@@ -849,7 +963,7 @@ new CodeViewer("#usage-gallery-demo-html", `<div id="gallery" class="masonry-con
849
963
  </div>`, "html");
850
964
  new CodeViewer("#usage-gallery-demo-js", `const gallery = new MasonryGallery("gallery", {
851
965
  minColumnWidth: 300,
852
- fetchFunction: new Promise((resolve) => {
966
+ fetchFunction: () => new Promise((resolve) => {
853
967
  setTimeout(() => {
854
968
  const images: ImageData[] = [];
855
969
 
package/js/push-menu.js CHANGED
@@ -1,113 +1,113 @@
1
- class PushMenu {
2
- static init() {
3
- if (this.initialized) {
4
- console.warn('PushMenu: Already initialized');
5
- return;
6
- }
7
- this.refresh();
8
- if (!this.elements.navigation || !this.elements.content) {
9
- throw new Error('PushMenu: Required elements not found (.navigation, .push-content)');
10
- }
11
- this.elements.navigation.addEventListener('change', this.handleNavigationChange.bind(this));
12
- this.elements.backdrop?.addEventListener('click', this.handleBackdropClick);
13
- this.initialized = true;
14
- }
15
- static handleNavigationChange() {
16
- const isPushed = this.elements.content?.classList.contains('pushed') ?? false;
17
- if (!isPushed) {
18
- this.elements.content?.addEventListener('click', this.clickNav);
19
- }
20
- else {
21
- this.elements.content?.removeEventListener('click', this.clickNav);
22
- }
23
- this.pushToggle();
24
- }
25
- static pushToggle() {
26
- if (!this.elements.content || !this.elements.menu) {
27
- throw new Error('PushMenu: Required elements not found (.push-content, .push-menu)');
28
- }
29
- const isPushed = this.elements.content.classList.contains('pushed');
30
- this.toggleClass(this.elements.content, 'pushed', !isPushed);
31
- this.toggleClass(this.elements.menu, 'pushed', !isPushed);
32
- this.toggleClass(this.elements.header, 'pushed', !isPushed);
33
- this.toggleClass(this.elements.backdrop, 'pushed', !isPushed);
34
- if (this.elements.controlIcon) {
35
- if (isPushed) {
36
- this.elements.controlIcon.classList.remove('icon-menu_open');
37
- this.elements.controlIcon.classList.add('icon-menu');
38
- }
39
- else {
40
- this.elements.controlIcon.classList.add('icon-menu_open');
41
- this.elements.controlIcon.classList.remove('icon-menu');
42
- }
43
- }
44
- }
45
- static toggleClass(element, className, add) {
46
- if (!element)
47
- return;
48
- if (add) {
49
- element.classList.add(className);
50
- }
51
- else {
52
- element.classList.remove(className);
53
- }
54
- }
55
- static open() {
56
- if (!this.elements.content?.classList.contains('pushed')) {
57
- this.pushToggle();
58
- }
59
- }
60
- static close() {
61
- if (this.elements.content?.classList.contains('pushed')) {
62
- this.pushToggle();
63
- }
64
- }
65
- static isOpen() {
66
- return this.elements.content?.classList.contains('pushed') ?? false;
67
- }
68
- static destroy() {
69
- if (!this.initialized)
70
- return;
71
- this.elements.navigation?.removeEventListener('change', this.handleNavigationChange);
72
- this.elements.content?.removeEventListener('click', this.clickNav);
73
- this.elements.backdrop?.removeEventListener('click', this.handleBackdropClick);
74
- this.close();
75
- this.elements = {
76
- navigation: null,
77
- content: null,
78
- menu: null,
79
- header: null,
80
- controlIcon: null,
81
- backdrop: null
82
- };
83
- this.initialized = false;
84
- }
85
- static refresh() {
86
- this.elements.navigation = document.querySelector('.navigation');
87
- this.elements.content = document.querySelector('.push-content');
88
- this.elements.menu = document.querySelector('.push-menu');
89
- this.elements.header = document.querySelector('.main-header');
90
- this.elements.controlIcon = document.querySelector('.navigation-controls .icon');
91
- this.elements.backdrop = document.querySelector('.push-menu-backdrop');
92
- }
93
- }
94
- PushMenu.elements = {
95
- navigation: null,
96
- content: null,
97
- menu: null,
98
- header: null,
99
- controlIcon: null,
100
- backdrop: null
101
- };
102
- PushMenu.initialized = false;
103
- PushMenu.clickNav = () => {
104
- const navigation = PushMenu.elements.navigation;
105
- navigation?.click();
106
- };
107
- PushMenu.handleBackdropClick = () => {
108
- if (PushMenu.isOpen()) {
109
- const navigation = PushMenu.elements.navigation;
110
- navigation?.click();
111
- }
112
- };
113
- export { PushMenu };
1
+ class PushMenu {
2
+ static init() {
3
+ if (this.initialized) {
4
+ console.warn('PushMenu: Already initialized');
5
+ return;
6
+ }
7
+ this.refresh();
8
+ if (!this.elements.navigation || !this.elements.content) {
9
+ throw new Error('PushMenu: Required elements not found (.navigation, .push-content)');
10
+ }
11
+ this.elements.navigation.addEventListener('change', this.handleNavigationChange.bind(this));
12
+ this.elements.backdrop?.addEventListener('click', this.handleBackdropClick);
13
+ this.initialized = true;
14
+ }
15
+ static handleNavigationChange() {
16
+ const isPushed = this.elements.content?.classList.contains('pushed') ?? false;
17
+ if (!isPushed) {
18
+ this.elements.content?.addEventListener('click', this.clickNav);
19
+ }
20
+ else {
21
+ this.elements.content?.removeEventListener('click', this.clickNav);
22
+ }
23
+ this.pushToggle();
24
+ }
25
+ static pushToggle() {
26
+ if (!this.elements.content || !this.elements.menu) {
27
+ throw new Error('PushMenu: Required elements not found (.push-content, .push-menu)');
28
+ }
29
+ const isPushed = this.elements.content.classList.contains('pushed');
30
+ this.toggleClass(this.elements.content, 'pushed', !isPushed);
31
+ this.toggleClass(this.elements.menu, 'pushed', !isPushed);
32
+ this.toggleClass(this.elements.header, 'pushed', !isPushed);
33
+ this.toggleClass(this.elements.backdrop, 'pushed', !isPushed);
34
+ if (this.elements.controlIcon) {
35
+ if (isPushed) {
36
+ this.elements.controlIcon.classList.remove('icon-menu_open');
37
+ this.elements.controlIcon.classList.add('icon-menu');
38
+ }
39
+ else {
40
+ this.elements.controlIcon.classList.add('icon-menu_open');
41
+ this.elements.controlIcon.classList.remove('icon-menu');
42
+ }
43
+ }
44
+ }
45
+ static toggleClass(element, className, add) {
46
+ if (!element)
47
+ return;
48
+ if (add) {
49
+ element.classList.add(className);
50
+ }
51
+ else {
52
+ element.classList.remove(className);
53
+ }
54
+ }
55
+ static open() {
56
+ if (!this.elements.content?.classList.contains('pushed')) {
57
+ this.pushToggle();
58
+ }
59
+ }
60
+ static close() {
61
+ if (this.elements.content?.classList.contains('pushed')) {
62
+ this.pushToggle();
63
+ }
64
+ }
65
+ static isOpen() {
66
+ return this.elements.content?.classList.contains('pushed') ?? false;
67
+ }
68
+ static destroy() {
69
+ if (!this.initialized)
70
+ return;
71
+ this.elements.navigation?.removeEventListener('change', this.handleNavigationChange);
72
+ this.elements.content?.removeEventListener('click', this.clickNav);
73
+ this.elements.backdrop?.removeEventListener('click', this.handleBackdropClick);
74
+ this.close();
75
+ this.elements = {
76
+ navigation: null,
77
+ content: null,
78
+ menu: null,
79
+ header: null,
80
+ controlIcon: null,
81
+ backdrop: null
82
+ };
83
+ this.initialized = false;
84
+ }
85
+ static refresh() {
86
+ this.elements.navigation = document.querySelector('.navigation');
87
+ this.elements.content = document.querySelector('.push-content');
88
+ this.elements.menu = document.querySelector('.push-menu');
89
+ this.elements.header = document.querySelector('.main-header');
90
+ this.elements.controlIcon = document.querySelector('.navigation-controls .icon');
91
+ this.elements.backdrop = document.querySelector('.push-menu-backdrop');
92
+ }
93
+ }
94
+ PushMenu.elements = {
95
+ navigation: null,
96
+ content: null,
97
+ menu: null,
98
+ header: null,
99
+ controlIcon: null,
100
+ backdrop: null
101
+ };
102
+ PushMenu.initialized = false;
103
+ PushMenu.clickNav = () => {
104
+ const navigation = PushMenu.elements.navigation;
105
+ navigation?.click();
106
+ };
107
+ PushMenu.handleBackdropClick = () => {
108
+ if (PushMenu.isOpen()) {
109
+ const navigation = PushMenu.elements.navigation;
110
+ navigation?.click();
111
+ }
112
+ };
113
+ export { PushMenu };
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 };
package/js/stepper.ts ADDED
@@ -0,0 +1,104 @@
1
+ interface StepperOptions {
2
+ defaultStep?: number;
3
+ clickable?: boolean;
4
+ onChange?: (current: number, previous: number) => void;
5
+ }
6
+
7
+ class Stepper {
8
+ private container: HTMLElement;
9
+ private steps: HTMLElement[];
10
+ private connectors: HTMLElement[];
11
+ private current: number;
12
+ private readonly onChange?: (current: number, previous: number) => void;
13
+
14
+ constructor(elementOrSelector: string | HTMLElement, options: StepperOptions = {}) {
15
+ const element = typeof elementOrSelector === 'string'
16
+ ? document.querySelector<HTMLElement>(elementOrSelector)
17
+ : elementOrSelector;
18
+
19
+ if (!element) throw new Error(`Stepper: element not found`);
20
+
21
+ this.container = element;
22
+ this.steps = Array.from(this.container.querySelectorAll<HTMLElement>('.stepper-step'));
23
+ this.connectors = Array.from(this.container.querySelectorAll<HTMLElement>('.stepper-connector'));
24
+ this.onChange = options.onChange;
25
+ this.current = options.defaultStep ?? 0;
26
+
27
+ if (this.steps.length === 0) {
28
+ console.warn('Stepper: no .stepper-step elements found');
29
+ return;
30
+ }
31
+
32
+ if (options.clickable) {
33
+ this.container.classList.add('stepper-clickable');
34
+ this.steps.forEach((step, i) => {
35
+ step.addEventListener('click', () => this.goTo(i));
36
+ });
37
+ }
38
+
39
+ this.render();
40
+ }
41
+
42
+ private render(): void {
43
+ this.steps.forEach((step, i) => {
44
+ step.classList.remove('active', 'completed');
45
+
46
+ if (i < this.current) step.classList.add('completed');
47
+ else if (i === this.current) step.classList.add('active');
48
+ });
49
+
50
+ this.connectors.forEach((connector, i) => {
51
+ connector.classList.toggle('completed', i < this.current);
52
+ });
53
+ }
54
+
55
+ public next(): void {
56
+ if (this.current < this.steps.length - 1) {
57
+ this.goTo(this.current + 1);
58
+ }
59
+ }
60
+
61
+ public prev(): void {
62
+ if (this.current > 0) {
63
+ this.goTo(this.current - 1);
64
+ }
65
+ }
66
+
67
+ public goTo(index: number): void {
68
+ if (index < 0 || index >= this.steps.length) return;
69
+ const previous = this.current;
70
+ this.current = index;
71
+ this.render();
72
+ if (this.onChange && previous !== index) {
73
+ this.onChange(index, previous);
74
+ }
75
+ }
76
+
77
+ public setError(index: number): void {
78
+ if (index < 0 || index >= this.steps.length) return;
79
+ this.steps[index].classList.add('error');
80
+ }
81
+
82
+ public clearError(index: number): void {
83
+ if (index < 0 || index >= this.steps.length) return;
84
+ this.steps[index].classList.remove('error');
85
+ }
86
+
87
+ public getStep(): number {
88
+ return this.current;
89
+ }
90
+
91
+ public getStepCount(): number {
92
+ return this.steps.length;
93
+ }
94
+
95
+ public isFirst(): boolean {
96
+ return this.current === 0;
97
+ }
98
+
99
+ public isLast(): boolean {
100
+ return this.current === this.steps.length - 1;
101
+ }
102
+ }
103
+
104
+ export { Stepper, type StepperOptions };
package/js/timepicker.js CHANGED
@@ -16,6 +16,7 @@ class TimeSpanPicker {
16
16
  this.endTimeInput.value = options.defaultEnd;
17
17
  }
18
18
  this.attachEventListeners();
19
+ // Render initial state if defaults provided
19
20
  if (options?.defaultStart || options?.defaultEnd) {
20
21
  this.updateUI();
21
22
  }
@@ -69,8 +70,10 @@ class TimeSpanPicker {
69
70
  formatDuration(minutes) {
70
71
  const h = Math.floor(minutes / 60);
71
72
  const m = minutes % 60;
72
- if (h && m) return `${h}h ${m}m`;
73
- if (h) return `${h}h`;
73
+ if (h && m)
74
+ return `${h}h ${m}m`;
75
+ if (h)
76
+ return `${h}h`;
74
77
  return `${m}m`;
75
78
  }
76
79
  updateUI() {
@@ -83,7 +86,8 @@ class TimeSpanPicker {
83
86
  picker?.classList.toggle('is-error', isError);
84
87
  if (isError) {
85
88
  this.endTimeInput.setCustomValidity('End time must be after start time');
86
- if (durationEl) durationEl.textContent = '!';
89
+ if (durationEl)
90
+ durationEl.textContent = '!';
87
91
  return;
88
92
  }
89
93
  this.endTimeInput.setCustomValidity('');
@@ -96,9 +100,14 @@ class TimeSpanPicker {
96
100
  const widthPct = ((duration / 1440) * 100).toFixed(2);
97
101
  barFill.style.left = `${startPct}%`;
98
102
  barFill.style.width = `${widthPct}%`;
99
- } else {
100
- if (durationEl) durationEl.textContent = '';
101
- if (barFill) { barFill.style.left = '0'; barFill.style.width = '0'; }
103
+ }
104
+ else {
105
+ if (durationEl)
106
+ durationEl.textContent = '';
107
+ if (barFill) {
108
+ barFill.style.left = '0';
109
+ barFill.style.width = '0';
110
+ }
102
111
  }
103
112
  }
104
113
  handleChange() {
@@ -127,8 +136,12 @@ class TimeSpanPicker {
127
136
  const durationEl = this.container.querySelector('.timespan-duration');
128
137
  const barFill = this.container.querySelector('.timespan-bar-fill');
129
138
  picker?.classList.remove('is-error');
130
- if (durationEl) durationEl.textContent = '';
131
- if (barFill) { barFill.style.left = '0'; barFill.style.width = '0'; }
139
+ if (durationEl)
140
+ durationEl.textContent = '';
141
+ if (barFill) {
142
+ barFill.style.left = '0';
143
+ barFill.style.width = '0';
144
+ }
132
145
  }
133
146
  isValid() {
134
147
  const { start, end } = this.getValue();
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@dodlhuat/basix",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Basix is intended as a starter for the rapid development of a design. Each design element can be added individually to include only the data required. It is using plain javascript / typescript and therefore is not dependent on any plugin.",
5
5
  "main": "js/index.js",
6
6
  "exports": {
7
7
  ".": "./js/index.js",
8
- "./css/*": "./css/*"
8
+ "./css/*": "./css/*",
9
+ "./js/*": "./js/*"
9
10
  },
10
11
  "files": [
11
12
  "js/",
Binary file
Binary file
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="activity"><rect width="24" height="24" transform="rotate(90 12 12)" opacity="0"/><path d="M14.33 20h-.21a2 2 0 0 1-1.76-1.58L9.68 6l-2.76 6.4A1 1 0 0 1 6 13H3a1 1 0 0 1 0-2h2.34l2.51-5.79a2 2 0 0 1 3.79.38L14.32 18l2.76-6.38A1 1 0 0 1 18 11h3a1 1 0 0 1 0 2h-2.34l-2.51 5.79A2 2 0 0 1 14.33 20z"/></g></g></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="alert-circle"><rect width="24" height="24" opacity="0"/><path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 8-8 8 8 0 0 1-8 8z"/><circle cx="12" cy="16" r="1"/><path d="M12 7a1 1 0 0 0-1 1v5a1 1 0 0 0 2 0V8a1 1 0 0 0-1-1z"/></g></g></svg>
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g data-name="Layer 2"><g data-name="alert-triangle"><rect width="24" height="24" transform="rotate(90 12 12)" opacity="0"/><path d="M22.56 16.3L14.89 3.58a3.43 3.43 0 0 0-5.78 0L1.44 16.3a3 3 0 0 0-.05 3A3.37 3.37 0 0 0 4.33 21h15.34a3.37 3.37 0 0 0 2.94-1.66 3 3 0 0 0-.05-3.04zm-1.7 2.05a1.31 1.31 0 0 1-1.19.65H4.33a1.31 1.31 0 0 1-1.19-.65 1 1 0 0 1 0-1l7.68-12.73a1.48 1.48 0 0 1 2.36 0l7.67 12.72a1 1 0 0 1 .01 1.01z"/><circle cx="12" cy="16" r="1"/><path d="M12 8a1 1 0 0 0-1 1v4a1 1 0 0 0 2 0V9a1 1 0 0 0-1-1z"/></g></g></svg>