@dodlhuat/basix 1.2.0 → 1.2.2

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 (93) hide show
  1. package/README.md +266 -6
  2. package/css/accordion.scss +86 -87
  3. package/css/alert.scss +137 -137
  4. package/css/button.scss +48 -0
  5. package/css/calendar.scss +957 -0
  6. package/css/card.scss +65 -65
  7. package/css/chart.scss +270 -157
  8. package/css/chat-bubbles.scss +134 -68
  9. package/css/chips.scss +109 -19
  10. package/css/colors.scss +32 -32
  11. package/css/datepicker.scss +336 -336
  12. package/css/defaults.scss +90 -90
  13. package/css/docs.scss +529 -0
  14. package/css/editor.scss +36 -0
  15. package/css/file-uploader.scss +1 -1
  16. package/css/flyout-menu.scss +361 -361
  17. package/css/form.scss +0 -15
  18. package/css/gallery.scss +65 -6
  19. package/css/grid.scss +41 -40
  20. package/css/group-picker.scss +345 -0
  21. package/css/guitar-chords.css +250 -250
  22. package/css/icons.scss +330 -330
  23. package/css/parameters.scss +3 -3
  24. package/css/placeholder.scss +33 -33
  25. package/css/popover.scss +206 -0
  26. package/css/progress.scss +76 -32
  27. package/css/properties.scss +51 -36
  28. package/css/push-menu.scss +302 -174
  29. package/css/reset.scss +39 -39
  30. package/css/scrollbar.scss +62 -5
  31. package/css/sidebar-nav.scss +92 -0
  32. package/css/spinner.scss +65 -65
  33. package/css/stepper.scss +48 -12
  34. package/css/style.css +3155 -254
  35. package/css/style.css.map +1 -1
  36. package/css/style.min.css +1 -1
  37. package/css/style.scss +51 -45
  38. package/css/table.scss +199 -199
  39. package/css/tabs.scss +154 -123
  40. package/css/timeline.scss +83 -38
  41. package/css/timepicker.scss +100 -5
  42. package/css/toast.scss +81 -81
  43. package/css/virtual-dropdown.scss +35 -29
  44. package/js/calendar.js +532 -0
  45. package/js/calendar.ts +706 -0
  46. package/js/chart.js +573 -257
  47. package/js/chart.ts +692 -0
  48. package/js/code-viewer.js +10 -10
  49. package/js/code-viewer.ts +188 -188
  50. package/js/datepicker.ts +627 -627
  51. package/js/docs-nav.js +204 -0
  52. package/js/dropdown.ts +179 -179
  53. package/js/editor.js +50 -6
  54. package/js/editor.ts +483 -444
  55. package/js/file-uploader.js +1 -0
  56. package/js/file-uploader.ts +1 -0
  57. package/js/flyout-menu.js +14 -14
  58. package/js/flyout-menu.ts +249 -249
  59. package/js/form-builder.js +106 -106
  60. package/js/gallery.js +14 -8
  61. package/js/gallery.ts +245 -236
  62. package/js/group-picker.js +342 -0
  63. package/js/group-picker.ts +447 -0
  64. package/js/guitar-chords.js +268 -268
  65. package/js/lazy-loader.js +121 -121
  66. package/js/modal.ts +166 -166
  67. package/js/popover.js +163 -0
  68. package/js/popover.ts +219 -0
  69. package/js/position.js +108 -0
  70. package/js/position.ts +111 -0
  71. package/js/push-menu.js +113 -0
  72. package/js/push-menu.ts +284 -145
  73. package/js/request.js +50 -50
  74. package/js/scroll.ts +47 -47
  75. package/js/scrollbar.js +13 -0
  76. package/js/scrollbar.ts +324 -307
  77. package/js/select.ts +216 -216
  78. package/js/sidebar-nav.js +41 -0
  79. package/js/sidebar-nav.ts +66 -0
  80. package/js/table.ts +452 -452
  81. package/js/tabs.ts +279 -279
  82. package/js/theme.js +17 -6
  83. package/js/theme.ts +234 -224
  84. package/js/toast.ts +137 -137
  85. package/js/tooltip.js +6 -60
  86. package/js/tooltip.ts +184 -251
  87. package/js/tsconfig.json +18 -18
  88. package/js/utils.ts +83 -83
  89. package/js/virtual-dropdown.js +25 -25
  90. package/js/virtual-dropdown.ts +365 -365
  91. package/package.json +37 -39
  92. package/js/index.js +0 -816
  93. package/js/index.ts +0 -987
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Basix 1.2.0
1
+ # Basix 1.2.1
2
2
 
3
3
  Basix is intended as a starter for the rapid development of a design. Each design element can be added individually to
4
4
  include only the data required. It is using plain javascript / typescript and therefore is not dependent on any plugin.
@@ -16,12 +16,23 @@ A demo can be found here: <a href="http://www.andibauer.at/basix/" target="_blan
16
16
  Take a look at style.scss for a glimpse on a full import. reset, parameters, colors & defaults are mandatory, anything
17
17
  else can be added as needed.
18
18
 
19
- To use the import functionality of javascript files you need to import your main script as a module. And either build
20
- your own css or include the existing full style.css (or min)
19
+ Include the stylesheet and import individual components as ES modules. There is no bundled entry point only the components you use are loaded.
21
20
 
22
21
  ``` html
23
22
  <link rel="stylesheet" href="css/style.css" type="text/css">
24
- <script src="js/index.js" type="module"></script>
23
+ <script type="module">
24
+ import { Chart } from './js/chart.js';
25
+ import { Modal } from './js/modal.js';
26
+ import { Stepper } from './js/stepper.js';
27
+ // … add only what you need
28
+ </script>
29
+ ```
30
+
31
+ When installed via npm, import from the package:
32
+
33
+ ``` js
34
+ import { Chart } from '@dodlhuat/basix/js/chart.js';
35
+ import { Modal } from '@dodlhuat/basix/js/modal.js';
25
36
  ```
26
37
 
27
38
  ---
@@ -125,10 +136,20 @@ The Switch component creates styled toggle switches based on checkboxes.
125
136
 
126
137
  ### Range Slider
127
138
 
128
- The Range Slider component creates a simple styled slider.
139
+ The Range Slider component creates a styled slider with a CSS custom property `--range-fill` that tracks the current value for fill styling. Use the JS class to initialise fill tracking automatically.
129
140
 
130
141
  ``` html
131
- <input type="range" min="1" max="100" value="50" />
142
+ <div class="range-slider">
143
+ <input type="range" min="1" max="100" value="50" />
144
+ </div>
145
+ ```
146
+
147
+ ``` js
148
+ // Initialise a single slider
149
+ new RangeSlider(document.querySelector('.range-slider input'));
150
+
151
+ // Or initialise all sliders on the page at once
152
+ RangeSlider.initAll();
132
153
  ```
133
154
 
134
155
  ---
@@ -155,6 +176,37 @@ The Flyout Menu component creates slide-in navigation menus with nested submenus
155
176
  | `footerText` | string | `'© 2025 Brand Inc.'` | Shown in the footer if enabled |
156
177
  | `enableFooter` | boolean | `true` | Shows the menu footer |
157
178
 
179
+ ### Popover
180
+
181
+ The Popover component attaches a floating content panel to any trigger element. Supports click and hover trigger modes, four placement directions, optional arrow, and stacks correctly when multiple popovers exist.
182
+
183
+ | Option | Type | Default | Description |
184
+ |---|---|---|---|
185
+ | `content` | string | — | HTML content rendered inside the popover |
186
+ | `placement` | string | `'top'` | Preferred placement: `'top'`, `'bottom'`, `'left'`, `'right'`, or `'auto'` |
187
+ | `align` | string | `'center'` | Alignment along the axis: `'start'`, `'center'`, `'end'` |
188
+ | `offset` | number | `8` | Distance in px between the trigger and the popover |
189
+ | `arrow` | boolean | `true` | Shows a directional arrow |
190
+ | `triggerMode` | string | `'click'` | `'click'` or `'hover'` |
191
+ | `closeOnOutsideClick` | boolean | `true` | Closes when clicking outside |
192
+ | `closeOnEscape` | boolean | `true` | Closes on Escape key |
193
+ | `className` | string | — | Extra CSS class on the popover element |
194
+ | `onOpen` | function | — | Callback fired when the popover opens |
195
+ | `onClose` | function | — | Callback fired when the popover closes |
196
+
197
+ ``` js
198
+ const pop = new Popover('#my-trigger', {
199
+ content: '<p>Popover content</p>',
200
+ placement: 'bottom',
201
+ triggerMode: 'click',
202
+ });
203
+
204
+ pop.open();
205
+ pop.close();
206
+ pop.toggle();
207
+ pop.destroy();
208
+ ```
209
+
158
210
  ### Dropdown Menu
159
211
 
160
212
  The Dropdown Menu allows to create multi-level dropdown menus with nested submenus. The menu fires custom events `CustomEvent<DropdownSelectDetail>` that can be listened to in order to react to user selections.
@@ -426,6 +478,91 @@ The Placeholder component creates skeleton loading states. Use `.placeholder` wi
426
478
 
427
479
  ## Advanced Components
428
480
 
481
+ ### Chart
482
+
483
+ The Chart component renders SVG-based charts with no external dependencies. Supports line, area, column, bar, and pie chart types. Animates on first render and redraws on container resize.
484
+
485
+ ``` js
486
+ const chart = new Chart('#chart-container', {
487
+ type: 'line',
488
+ title: 'Monthly Revenue',
489
+ series: [
490
+ {
491
+ name: 'Product A',
492
+ data: [
493
+ { label: 'Jan', value: 120 },
494
+ { label: 'Feb', value: 180 },
495
+ { label: 'Mar', value: 150 },
496
+ ],
497
+ },
498
+ ],
499
+ });
500
+
501
+ chart.update(newSeries); // replace data and redraw
502
+ chart.setType('bar'); // switch chart type
503
+ chart.destroy(); // remove listeners and DOM
504
+ ```
505
+
506
+ | Option | Type | Default | Description |
507
+ |---|---|---|---|
508
+ | `type` | ChartType | — | `'line'`, `'area'`, `'column'`, `'bar'`, or `'pie'` |
509
+ | `series` | ChartSeries[] | — | Array of `{ name, data, color? }` objects |
510
+ | `title` | string | — | Optional chart title |
511
+ | `subtitle` | string | — | Optional subtitle below the title |
512
+ | `height` | number | `280` | Inner chart height in px |
513
+ | `showLegend` | boolean | `true` | Renders the series legend |
514
+ | `showGrid` | boolean | `true` | Renders background grid lines |
515
+ | `animate` | boolean | `true` | Animates on first render |
516
+ | `curve` | string | `'smooth'` | Line interpolation for line/area: `'smooth'`, `'linear'`, `'step'` |
517
+ | `yMin` | number | `0` | Fixed y-axis minimum |
518
+ | `yMax` | number | auto | Fixed y-axis maximum (defaults to max value × 1.1) |
519
+ | `onPointClick` | function | — | Callback `(series, point, index) => void` fired on data point click |
520
+
521
+ ### Calendar
522
+
523
+ The Calendar component renders a full interactive calendar with month, week, and agenda views. Supports event display, keyboard navigation, and locale configuration.
524
+
525
+ ``` js
526
+ const cal = new Calendar({
527
+ container: '#my-calendar',
528
+ view: 'month',
529
+ events: [
530
+ {
531
+ id: '1',
532
+ title: 'Team Meeting',
533
+ start: new Date(2026, 3, 20, 10, 0),
534
+ end: new Date(2026, 3, 20, 11, 0),
535
+ className: 'badge-success',
536
+ },
537
+ ],
538
+ onEventClick: (event) => console.log(event),
539
+ onDayClick: (date) => console.log(date),
540
+ onChange: (date, view) => console.log(date, view),
541
+ });
542
+
543
+ cal.next();
544
+ cal.prev();
545
+ cal.today();
546
+ cal.setView('week');
547
+ cal.addEvent({ id: '2', title: 'Lunch', start: new Date(), end: new Date() });
548
+ cal.removeEvent('2');
549
+ cal.setEvents(events);
550
+ cal.getEvents();
551
+ cal.destroy();
552
+ ```
553
+
554
+ | Option | Type | Default | Description |
555
+ |---|---|---|---|
556
+ | `container` | HTMLElement \| string | — | Target container element or CSS selector |
557
+ | `events` | CalendarEvent[] | `[]` | Initial events |
558
+ | `view` | string | `'month'` | Initial view: `'month'`, `'week'`, or `'agenda'` |
559
+ | `showOutsideDays` | boolean | `true` | Show days from adjacent months in the month grid |
560
+ | `locale` | object | — | Override locale strings (day names, month names, labels) |
561
+ | `onDayClick` | function | — | Callback `(date: Date) => void` |
562
+ | `onEventClick` | function | — | Callback `(event: CalendarEvent) => void` |
563
+ | `onChange` | function | — | Callback `(date: Date, view: CalendarView) => void` |
564
+ | `className` | string | — | Extra CSS class on the root element |
565
+
429
566
  ### Context Menu
430
567
 
431
568
  The Context Menu component shows a custom right-click menu on any target element. Supports icons, keyboard shortcuts, group labels, separators, submenus, destructive items, and disabled items. Automatically flips to avoid viewport overflow and animates in from the click origin.
@@ -539,6 +676,129 @@ The FileUploader component provides drag-and-drop file upload functionality with
539
676
 
540
677
  Virtual Dropdown is a performant, virtualized dropdown component that efficiently renders large option lists by only drawing visible items in the DOM. Supports single and multi-select modes, built-in search/filtering, keyboard navigation, and configurable item height and render limits — making it ideal for scenarios with hundreds or thousands of selectable options.
541
678
 
679
+ ### Group Picker
680
+
681
+ The GroupPicker component enables hierarchical group and subgroup selection. Users can either select an entire parent group (covering all subgroups) or pick individual subgroups. Groups without children are directly selectable. Selecting all subgroups automatically promotes to a parent selection. Includes debounced search with match highlighting, expand/collapse, and a chip-based selection summary.
682
+
683
+ ``` html
684
+ <div id="group-picker-demo"></div>
685
+ ```
686
+
687
+ ``` js
688
+ const data: GroupData[] = [
689
+ {
690
+ id: 'gruppenspiele', label: 'Gruppenspiele',
691
+ subgroups: [
692
+ { id: 'grossgruppe', label: 'Grossgruppenspiele' },
693
+ { id: 'trinkspiele', label: 'Trinkspiele' },
694
+ ]
695
+ },
696
+ { id: 'schach', label: 'Schach' }, // no subgroups — directly selectable
697
+ ];
698
+
699
+ const picker = new GroupPicker('#group-picker-demo', data, {
700
+ onSelectionChange: (selection) => console.log(selection),
701
+ });
702
+ ```
703
+
704
+ #### GroupData
705
+
706
+ | Property | Type | Description |
707
+ |---|---|---|
708
+ | `id` | string | Unique identifier for the group |
709
+ | `label` | string | Display name |
710
+ | `subgroups` | SubgroupData[] | Optional array of `{ id, label }` child items |
711
+
712
+ #### GroupPickerOptions
713
+
714
+ | Option | Type | Default | Description |
715
+ |---|---|---|---|
716
+ | `onSelectionChange` | function | — | Callback fired on selection change with `GroupPickerSelection` |
717
+ | `searchPlaceholder` | string | `'Gruppen durchsuchen...'` | Placeholder text for the search input |
718
+ | `selectAllLabel` | string | `'Alle'` | Label for the select-all button |
719
+ | `deselectLabel` | string | `'Abwahlen'` | Label shown when a parent group is selected |
720
+ | `emptyLabel` | string | `'Keine Ergebnisse'` | Shown when search yields no results |
721
+ | `selectionPlaceholder` | string | `'Noch keine Auswahl getroffen'` | Placeholder in the selection summary area |
722
+
723
+ #### Public API
724
+
725
+ | Method | Description |
726
+ |---|---|
727
+ | `getSelection()` | Returns `{ parentGroups: string[], subgroups: { groupId, subgroupId }[] }` |
728
+ | `setSelection(selection)` | Programmatically set the selection state |
729
+ | `clearSelection()` | Clear all selections |
730
+ | `expandAll()` | Expand all groups |
731
+ | `collapseAll()` | Collapse all groups |
732
+ | `destroy()` | Remove event listeners and clear the DOM |
733
+
734
+ ### Time Span Picker
735
+
736
+ The TimeSpanPicker component provides a paired start/end time input for selecting a time range.
737
+
738
+ ``` js
739
+ const picker = new TimeSpanPicker('my-container', {
740
+ defaultStart: '09:00',
741
+ defaultEnd: '17:00',
742
+ onChange: (start, end) => console.log(start, end),
743
+ });
744
+
745
+ picker.getValue(); // { start: '09:00', end: '17:00' }
746
+ picker.setValue('10:00', '18:00');
747
+ picker.reset();
748
+ picker.isValid(); // boolean
749
+ picker.destroy();
750
+ ```
751
+
752
+ ### Select
753
+
754
+ The Select component wraps a native `<select>` element with custom Basix styling. Supports single and multi-select.
755
+
756
+ ``` html
757
+ <select id="my-select">
758
+ <option value="a">Option A</option>
759
+ <option value="b">Option B</option>
760
+ </select>
761
+ ```
762
+
763
+ ``` js
764
+ const sel = new Select('#my-select');
765
+ sel.value(); // returns selected value string, or string[] for multi-select
766
+
767
+ // Or initialise by passing the element directly
768
+ Select.init(document.querySelector('#my-select'));
769
+ ```
770
+
771
+ ### Code Viewer
772
+
773
+ The CodeViewer component renders syntax-highlighted code blocks inside any container. Supports JavaScript, HTML, and CSS.
774
+
775
+ ``` js
776
+ new CodeViewer('#output', '<div class="card">Hello</div>', 'html');
777
+ new CodeViewer('#output', 'const x = 42;', 'javascript');
778
+ new CodeViewer('#output', '.card { padding: 1rem; }', 'css');
779
+ ```
780
+
781
+ ### Editor
782
+
783
+ The Editor component provides a contenteditable rich-text editing area with undo/redo, word count, and an optional side panel showing the raw HTML source and a live preview. Requires a `#editable` element in the DOM.
784
+
785
+ ``` html
786
+ <div id="editable" contenteditable="true"></div>
787
+ <!-- Optional side panel elements -->
788
+ <textarea id="code"></textarea>
789
+ <div id="preview"></div>
790
+ <div id="sidePanel"></div>
791
+ <span id="wordCount"></span>
792
+ ```
793
+
794
+ ``` js
795
+ // Full editor with side panel
796
+ new Editor();
797
+
798
+ // Simple mode — hides the side panel permanently
799
+ new Editor({ simple: true });
800
+ ```
801
+
542
802
  ### Custom Scrollbar
543
803
 
544
804
  The Scrollbar component creates custom-styled scrollbars. Supports pointer/touch dragging, track clicking, and automatic thumb sizing. Can be used with any class.
@@ -1,87 +1,86 @@
1
- @use "properties";
2
- @use "parameters" as *;
3
-
4
- .accordion {
5
- margin: 0 auto;
6
- border: 1px solid var(--divider);
7
- border-radius: $border-radius;
8
- overflow: hidden;
9
- }
10
-
11
- .accordion-item {
12
- border-bottom: 1px solid var(--divider);
13
- }
14
-
15
- .accordion-item:last-child {
16
- border-bottom: none;
17
- }
18
-
19
- .accordion-input {
20
- display: none;
21
- }
22
-
23
- .accordion-label {
24
- display: flex;
25
- justify-content: space-between;
26
- align-items: center;
27
- padding: calc($spacing * 0.85) calc($spacing * 1.25);
28
- background: transparent;
29
- font-weight: 500;
30
- cursor: pointer;
31
- transition: background 160ms ease,
32
- color 160ms ease;
33
- user-select: none;
34
- -webkit-tap-highlight-color: transparent;
35
-
36
- &:hover {
37
- background: var(--hover);
38
- }
39
-
40
- &:active {
41
- background: var(--hover);
42
- }
43
- }
44
-
45
- .accordion-label::after {
46
- content: '';
47
- width: 8px;
48
- height: 8px;
49
- border-right: 1.5px solid var(--secondary-text);
50
- border-bottom: 1.5px solid var(--secondary-text);
51
- transform: rotate(45deg);
52
- transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
53
- border-color 160ms ease;
54
- margin-left: $spacing;
55
- flex-shrink: 0;
56
- }
57
-
58
- .accordion-input:checked + .accordion-label {
59
- color: var(--accent-color);
60
-
61
- &::after {
62
- transform: rotate(-135deg);
63
- border-color: var(--accent-color);
64
- }
65
- }
66
-
67
- .accordion-content {
68
- display: grid;
69
- grid-template-rows: 0fr;
70
- transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);
71
- overflow: hidden;
72
- }
73
-
74
- .accordion-body {
75
- min-height: 0;
76
- }
77
-
78
- .accordion-body > div {
79
- padding: 0 calc($spacing * 1.25) calc($spacing * 1.25);
80
- color: var(--secondary-text);
81
- font-size: 0.9rem;
82
- line-height: 1.6;
83
- }
84
-
85
- .accordion-input:checked ~ .accordion-content {
86
- grid-template-rows: 1fr;
87
- }
1
+ @use "properties";
2
+ @use "parameters" as *;
3
+
4
+ .accordion {
5
+ margin: 0 auto;
6
+ border: 1px solid var(--divider);
7
+ border-radius: $border-radius;
8
+ overflow: hidden;
9
+ }
10
+
11
+ .accordion-item {
12
+ border-bottom: 1px solid var(--divider);
13
+
14
+ &:last-child { border-bottom: none; }
15
+ }
16
+
17
+ // Hidden checkbox toggle
18
+ .accordion-toggle {
19
+ display: none;
20
+ }
21
+
22
+ // Clickable header / trigger
23
+ .accordion-header {
24
+ display: flex;
25
+ justify-content: space-between;
26
+ align-items: center;
27
+ padding: calc($spacing * 0.85) calc($spacing * 1.25);
28
+ background: transparent;
29
+ font-weight: 500;
30
+ cursor: pointer;
31
+ transition: background 160ms ease, color 160ms ease;
32
+ user-select: none;
33
+ -webkit-tap-highlight-color: transparent;
34
+
35
+ &:hover { background: var(--hover); }
36
+ &:active { background: var(--hover); }
37
+
38
+ &::after {
39
+ content: '';
40
+ width: 8px;
41
+ height: 8px;
42
+ border-right: 1.5px solid var(--secondary-text);
43
+ border-bottom: 1.5px solid var(--secondary-text);
44
+ transform: rotate(45deg);
45
+ transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
46
+ border-color 160ms ease;
47
+ margin-left: $spacing;
48
+ flex-shrink: 0;
49
+ }
50
+ }
51
+
52
+ // Active state
53
+ .accordion-toggle:checked + .accordion-header {
54
+ color: var(--accent-color);
55
+
56
+ &::after {
57
+ transform: rotate(-135deg);
58
+ border-color: var(--accent-color);
59
+ }
60
+ }
61
+
62
+ // Grid wrapper — animates height via grid-template-rows
63
+ .accordion-content {
64
+ display: grid;
65
+ grid-template-rows: 0fr;
66
+ transition: grid-template-rows 300ms cubic-bezier(0.4, 0, 0.2, 1);
67
+ overflow: hidden;
68
+ }
69
+
70
+ .accordion-toggle:checked ~ .accordion-content {
71
+ grid-template-rows: 1fr;
72
+ }
73
+
74
+ // Inner body — min-height:0 is required for grid 0fr to collapse
75
+ .accordion-body {
76
+ min-height: 0;
77
+ padding: 0;
78
+ overflow: hidden;
79
+
80
+ > * {
81
+ padding: 0 calc($spacing * 1.25) calc($spacing * 1.25);
82
+ color: var(--secondary-text);
83
+ font-size: 0.9rem;
84
+ line-height: 1.6;
85
+ }
86
+ }