@dodlhuat/basix 1.3.4 → 1.4.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 (82) hide show
  1. package/README.md +160 -18
  2. package/css/checkbox.scss +15 -2
  3. package/css/color-picker.scss +278 -0
  4. package/css/datepicker.scss +5 -3
  5. package/css/push-menu.scss +7 -0
  6. package/css/stepper.scss +1 -1
  7. package/css/style.css +291 -6
  8. package/css/style.css.map +1 -1
  9. package/css/style.min.css +1 -1
  10. package/css/style.min.css.map +1 -1
  11. package/css/style.scss +1 -0
  12. package/css/table.scss +33 -0
  13. package/js/bottom-sheet.d.ts +0 -2
  14. package/js/bottom-sheet.js +0 -2
  15. package/js/calendar.d.ts +9 -17
  16. package/js/calendar.js +4 -7
  17. package/js/carousel.d.ts +0 -2
  18. package/js/carousel.js +1 -3
  19. package/js/chart.d.ts +6 -14
  20. package/js/chart.js +3 -5
  21. package/js/code-viewer.d.ts +2 -1
  22. package/js/code-viewer.js +8 -2
  23. package/js/color-picker.d.ts +50 -0
  24. package/js/color-picker.js +291 -0
  25. package/js/context-menu.d.ts +0 -3
  26. package/js/context-menu.js +0 -3
  27. package/js/datepicker.d.ts +0 -4
  28. package/js/datepicker.js +0 -1
  29. package/js/docs-nav.js +1 -0
  30. package/js/dropdown.d.ts +1 -4
  31. package/js/dropdown.js +0 -1
  32. package/js/editor.d.ts +4 -3
  33. package/js/editor.js +50 -35
  34. package/js/file-uploader.d.ts +0 -4
  35. package/js/file-uploader.js +0 -1
  36. package/js/flyout-menu.d.ts +0 -2
  37. package/js/flyout-menu.js +0 -1
  38. package/js/gallery.d.ts +1 -4
  39. package/js/gallery.js +18 -23
  40. package/js/group-picker.d.ts +0 -5
  41. package/js/group-picker.js +6 -8
  42. package/js/lightbox.d.ts +1 -4
  43. package/js/lightbox.js +6 -10
  44. package/js/modal.d.ts +0 -2
  45. package/js/modal.js +0 -1
  46. package/js/popover.d.ts +0 -3
  47. package/js/popover.js +0 -2
  48. package/js/position.d.ts +0 -13
  49. package/js/position.js +0 -12
  50. package/js/push-menu.d.ts +0 -3
  51. package/js/push-menu.js +6 -11
  52. package/js/range-slider.d.ts +0 -1
  53. package/js/range-slider.js +2 -3
  54. package/js/scroll.d.ts +0 -2
  55. package/js/scroll.js +5 -6
  56. package/js/scrollbar.d.ts +2 -10
  57. package/js/scrollbar.js +25 -42
  58. package/js/select.d.ts +2 -3
  59. package/js/select.js +6 -9
  60. package/js/sidebar-nav.d.ts +4 -15
  61. package/js/sidebar-nav.js +21 -35
  62. package/js/stepper.d.ts +5 -2
  63. package/js/stepper.js +42 -6
  64. package/js/table.d.ts +1 -56
  65. package/js/table.js +4 -56
  66. package/js/tabs.d.ts +1 -32
  67. package/js/tabs.js +7 -39
  68. package/js/theme.d.ts +0 -44
  69. package/js/theme.js +0 -44
  70. package/js/timepicker.d.ts +1 -4
  71. package/js/timepicker.js +1 -2
  72. package/js/toast.d.ts +0 -2
  73. package/js/toast.js +0 -1
  74. package/js/tooltip.d.ts +0 -4
  75. package/js/tooltip.js +0 -1
  76. package/js/tree.d.ts +0 -3
  77. package/js/tree.js +9 -11
  78. package/js/utils.d.ts +0 -10
  79. package/js/utils.js +2 -42
  80. package/js/virtual-dropdown.d.ts +3 -5
  81. package/js/virtual-dropdown.js +17 -66
  82. package/package.json +1 -1
package/js/utils.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /** Shape of the `utils` helper object. */
2
1
  interface Utils {
3
2
  ready(fn: () => void): void;
4
3
  value(element: HTMLElement): string;
@@ -8,15 +7,6 @@ interface Utils {
8
7
  isHidden(element: HTMLElement): boolean;
9
8
  }
10
9
  declare const utils: Utils;
11
- /**
12
- * Escape a plain-text string so it is safe to inject into innerHTML.
13
- * Use this whenever inserting user-controlled strings into HTML templates.
14
- */
15
10
  declare function escapeHtml(text: string): string;
16
- /**
17
- * Sanitize an HTML string by removing dangerous elements and attributes
18
- * (script, iframe, on* handlers, javascript: hrefs) while preserving safe markup.
19
- * Use this when a component intentionally accepts rich HTML from callers.
20
- */
21
11
  declare function sanitizeHtml(html: string): string;
22
12
  export { utils, escapeHtml, sanitizeHtml };
package/js/utils.js CHANGED
@@ -1,22 +1,12 @@
1
1
  const utils = {
2
- /**
3
- * Execute a function when the DOM is ready
4
- * @param fn - Callback function to execute
5
- */
6
2
  ready(fn) {
7
- if (document.readyState === "complete" || document.readyState === "interactive") {
3
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
8
4
  setTimeout(fn, 1);
9
5
  }
10
6
  else {
11
- document.addEventListener("DOMContentLoaded", fn);
7
+ document.addEventListener('DOMContentLoaded', fn);
12
8
  }
13
9
  },
14
- /**
15
- * Get the value of an element from various sources
16
- * Priority: value attribute > data-value attribute > innerText
17
- * @param element - HTML element to get value from
18
- * @returns The element's value as a string
19
- */
20
10
  value(element) {
21
11
  if (element.hasAttribute('value')) {
22
12
  return element.getAttribute('value') || '';
@@ -26,57 +16,27 @@ const utils = {
26
16
  }
27
17
  return element.innerText;
28
18
  },
29
- /**
30
- * Get the text content of an element
31
- * @param element - HTML element to get text from
32
- * @returns The element's inner text
33
- */
34
19
  text(element) {
35
20
  return element.innerText;
36
21
  },
37
- /**
38
- * Get an attribute value from an element
39
- * @param element - HTML element to get attribute from
40
- * @param attribute - Name of the attribute to retrieve
41
- * @returns The attribute value or undefined if not present
42
- */
43
22
  attribute(element, attribute) {
44
23
  if (element.hasAttribute(attribute)) {
45
24
  return element.getAttribute(attribute) || undefined;
46
25
  }
47
26
  return undefined;
48
27
  },
49
- /**
50
- * Check if an element is a NodeList
51
- * @param element - Element or NodeList to check
52
- * @returns True if the element is a NodeList
53
- */
54
28
  isList(element) {
55
29
  return NodeList.prototype.isPrototypeOf(element);
56
30
  },
57
- /**
58
- * Check if an element is hidden
59
- * @param element - HTML element to check
60
- * @returns True if the element is hidden
61
- */
62
31
  isHidden(element) {
63
32
  return element.offsetParent === null;
64
33
  }
65
34
  };
66
- /**
67
- * Escape a plain-text string so it is safe to inject into innerHTML.
68
- * Use this whenever inserting user-controlled strings into HTML templates.
69
- */
70
35
  function escapeHtml(text) {
71
36
  const div = document.createElement('div');
72
37
  div.textContent = text;
73
38
  return div.innerHTML;
74
39
  }
75
- /**
76
- * Sanitize an HTML string by removing dangerous elements and attributes
77
- * (script, iframe, on* handlers, javascript: hrefs) while preserving safe markup.
78
- * Use this when a component intentionally accepts rich HTML from callers.
79
- */
80
40
  function sanitizeHtml(html) {
81
41
  const parser = new DOMParser();
82
42
  const doc = parser.parseFromString(html, 'text/html');
@@ -1,9 +1,7 @@
1
- /** A single selectable option for a VirtualDropdown. */
2
1
  interface DropdownOption {
3
2
  label: string;
4
3
  value: string | number;
5
4
  }
6
- /** Configuration for a VirtualDropdown instance. */
7
5
  interface VirtualDropdownConfig {
8
6
  container: string | HTMLElement;
9
7
  options: DropdownOption[];
@@ -14,7 +12,6 @@ interface VirtualDropdownConfig {
14
12
  itemHeight?: number;
15
13
  onSelect?: (selectedValues: Array<string | number>) => void;
16
14
  }
17
- /** Virtualised dropdown that renders only visible items for performance with large option lists. */
18
15
  declare class VirtualDropdown {
19
16
  private readonly container;
20
17
  private readonly options;
@@ -37,7 +34,7 @@ declare class VirtualDropdown {
37
34
  private filteredOptions;
38
35
  private isOpen;
39
36
  private scrollTop;
40
- private boundHandlers;
37
+ private abortController;
41
38
  constructor(config: VirtualDropdownConfig);
42
39
  private init;
43
40
  private renderBase;
@@ -55,4 +52,5 @@ declare class VirtualDropdown {
55
52
  clearSelection(): void;
56
53
  destroy(): void;
57
54
  }
58
- export { VirtualDropdown, DropdownOption, VirtualDropdownConfig };
55
+ export { VirtualDropdown };
56
+ export type { DropdownOption, VirtualDropdownConfig };
@@ -1,5 +1,4 @@
1
1
  import { escapeHtml } from './utils.js';
2
- /** Virtualised dropdown that renders only visible items for performance with large option lists. */
3
2
  class VirtualDropdown {
4
3
  container;
5
4
  options;
@@ -9,8 +8,6 @@ class VirtualDropdown {
9
8
  renderLimit;
10
9
  itemHeight;
11
10
  onSelect;
12
- // Unique CSS anchor name for this instance — prevents conflicts when
13
- // multiple dropdowns exist on the same page.
14
11
  anchorName;
15
12
  trigger;
16
13
  triggerText;
@@ -24,7 +21,7 @@ class VirtualDropdown {
24
21
  filteredOptions;
25
22
  isOpen;
26
23
  scrollTop;
27
- boundHandlers;
24
+ abortController = new AbortController();
28
25
  constructor(config) {
29
26
  const containerElement = typeof config.container === 'string'
30
27
  ? document.querySelector(config.container)
@@ -45,7 +42,6 @@ class VirtualDropdown {
45
42
  this.filteredOptions = [...this.options];
46
43
  this.isOpen = false;
47
44
  this.scrollTop = 0;
48
- this.boundHandlers = new Map();
49
45
  this.init();
50
46
  }
51
47
  init() {
@@ -77,8 +73,6 @@ class VirtualDropdown {
77
73
  this.scroller = this.querySelector('.dropdown-list-scroller');
78
74
  this.spacer = this.querySelector('.virtual-spacer');
79
75
  this.content = this.querySelector('.virtual-content');
80
- // Wire up anchor positioning: each instance gets a unique anchor name
81
- // so multiple dropdowns on the same page don't interfere.
82
76
  this.trigger.style.setProperty('anchor-name', this.anchorName);
83
77
  this.menu.style.setProperty('position-anchor', this.anchorName);
84
78
  if (this.searchable) {
@@ -93,10 +87,9 @@ class VirtualDropdown {
93
87
  return element;
94
88
  }
95
89
  bindEvents() {
96
- const handleTriggerClick = () => this.toggle();
97
- this.trigger.addEventListener('click', handleTriggerClick);
98
- this.boundHandlers.set('triggerClick', handleTriggerClick);
99
- const handleTriggerKeydown = (e) => {
90
+ const sig = { signal: this.abortController.signal };
91
+ this.trigger.addEventListener('click', () => this.toggle(), sig);
92
+ this.trigger.addEventListener('keydown', (e) => {
100
93
  if (e.key === 'Enter' || e.key === ' ') {
101
94
  e.preventDefault();
102
95
  this.toggle();
@@ -104,46 +97,29 @@ class VirtualDropdown {
104
97
  else if (e.key === 'Escape' && this.isOpen) {
105
98
  this.close();
106
99
  }
107
- };
108
- this.trigger.addEventListener('keydown', handleTriggerKeydown);
109
- this.boundHandlers.set('triggerKeydown', handleTriggerKeydown);
110
- // Close when clicking outside. Still needed because popover="manual"
111
- // does not auto-dismiss on outside clicks.
112
- const handleDocumentClick = (e) => {
100
+ }, sig);
101
+ document.addEventListener('click', (e) => {
113
102
  if (!this.container.contains(e.target) && !this.menu.contains(e.target)) {
114
103
  this.close();
115
104
  }
116
- };
117
- document.addEventListener('click', handleDocumentClick);
118
- this.boundHandlers.set('documentClick', handleDocumentClick);
105
+ }, sig);
119
106
  if (this.searchable && this.searchInput) {
120
- const handleSearchInput = (e) => {
121
- const target = e.target;
122
- this.handleSearch(target.value);
123
- };
124
- this.searchInput.addEventListener('input', handleSearchInput);
125
- this.boundHandlers.set('searchInput', handleSearchInput);
107
+ this.searchInput.addEventListener('input', (e) => {
108
+ this.handleSearch(e.target.value);
109
+ }, sig);
126
110
  }
127
- const handleScroll = (e) => {
128
- const target = e.target;
129
- this.scrollTop = target.scrollTop;
111
+ this.listWrapper.addEventListener('scroll', (e) => {
112
+ this.scrollTop = e.target.scrollTop;
130
113
  this.renderList();
131
- };
132
- this.listWrapper.addEventListener('scroll', handleScroll);
133
- this.boundHandlers.set('scroll', handleScroll);
134
- // Sync isOpen if the browser closes the popover externally (e.g. another
135
- // popover="auto" element stealing focus — not typical for "manual" but
136
- // good defensive practice).
137
- const handlePopoverToggle = (e) => {
114
+ }, sig);
115
+ this.menu.addEventListener('toggle', (e) => {
138
116
  const te = e;
139
117
  if (te.newState === 'closed' && this.isOpen) {
140
118
  this.isOpen = false;
141
119
  this.container.classList.remove('open');
142
120
  this.trigger.setAttribute('aria-expanded', 'false');
143
121
  }
144
- };
145
- this.menu.addEventListener('toggle', handlePopoverToggle);
146
- this.boundHandlers.set('popoverToggle', handlePopoverToggle);
122
+ }, sig);
147
123
  }
148
124
  toggle() {
149
125
  this.isOpen ? this.close() : this.open();
@@ -290,34 +266,9 @@ class VirtualDropdown {
290
266
  }
291
267
  }
292
268
  destroy() {
293
- if (this.isOpen) {
269
+ if (this.isOpen)
294
270
  this.menu.hidePopover();
295
- }
296
- const triggerClick = this.boundHandlers.get('triggerClick');
297
- if (triggerClick) {
298
- this.trigger.removeEventListener('click', triggerClick);
299
- }
300
- const triggerKeydown = this.boundHandlers.get('triggerKeydown');
301
- if (triggerKeydown) {
302
- this.trigger.removeEventListener('keydown', triggerKeydown);
303
- }
304
- const documentClick = this.boundHandlers.get('documentClick');
305
- if (documentClick) {
306
- document.removeEventListener('click', documentClick);
307
- }
308
- const searchInput = this.boundHandlers.get('searchInput');
309
- if (searchInput && this.searchInput) {
310
- this.searchInput.removeEventListener('input', searchInput);
311
- }
312
- const scroll = this.boundHandlers.get('scroll');
313
- if (scroll) {
314
- this.listWrapper.removeEventListener('scroll', scroll);
315
- }
316
- const popoverToggle = this.boundHandlers.get('popoverToggle');
317
- if (popoverToggle) {
318
- this.menu.removeEventListener('toggle', popoverToggle);
319
- }
320
- this.boundHandlers.clear();
271
+ this.abortController.abort();
321
272
  this.container.innerHTML = '';
322
273
  this.container.classList.remove('custom-dropdown', 'open');
323
274
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dodlhuat/basix",
3
- "version": "1.3.4",
3
+ "version": "1.4.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
  "exports": {
6
6
  "./css/*": "./css/*",