@dodlhuat/basix 1.2.2 → 1.2.4

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 (55) hide show
  1. package/README.md +45 -1
  2. package/css/lightbox.scss +272 -0
  3. package/css/style.css +263 -3
  4. package/css/style.css.map +1 -1
  5. package/css/style.scss +1 -0
  6. package/js/bottom-sheet.js +4 -3
  7. package/js/bottom-sheet.ts +5 -3
  8. package/js/calendar.js +9 -5
  9. package/js/calendar.ts +7 -2
  10. package/js/carousel.js +15 -11
  11. package/js/carousel.ts +16 -11
  12. package/js/chart.js +4 -4
  13. package/js/chart.ts +5 -3
  14. package/js/datepicker.js +11 -3
  15. package/js/datepicker.ts +13 -3
  16. package/js/docs-nav.js +1 -0
  17. package/js/editor.js +28 -20
  18. package/js/editor.ts +28 -20
  19. package/js/file-uploader.js +6 -10
  20. package/js/file-uploader.ts +7 -11
  21. package/js/flyout-menu.js +8 -2
  22. package/js/flyout-menu.ts +7 -2
  23. package/js/gallery.js +6 -13
  24. package/js/gallery.ts +8 -16
  25. package/js/group-picker.js +10 -7
  26. package/js/group-picker.ts +11 -7
  27. package/js/lightbox.js +277 -0
  28. package/js/lightbox.ts +331 -0
  29. package/js/modal.js +5 -4
  30. package/js/modal.ts +6 -4
  31. package/js/popover.js +4 -2
  32. package/js/popover.ts +4 -2
  33. package/js/push-menu.js +3 -2
  34. package/js/push-menu.ts +4 -2
  35. package/js/scrollbar.js +31 -23
  36. package/js/scrollbar.ts +36 -26
  37. package/js/select.js +23 -9
  38. package/js/select.ts +29 -11
  39. package/js/stepper.js +5 -1
  40. package/js/stepper.ts +6 -1
  41. package/js/table.js +8 -3
  42. package/js/table.ts +9 -3
  43. package/js/timepicker.js +32 -21
  44. package/js/timepicker.ts +29 -21
  45. package/js/toast.js +3 -7
  46. package/js/toast.ts +4 -8
  47. package/js/tooltip.js +13 -4
  48. package/js/tooltip.ts +16 -4
  49. package/js/tree.js +4 -0
  50. package/js/tree.ts +5 -0
  51. package/js/utils.js +29 -1
  52. package/js/utils.ts +36 -1
  53. package/js/virtual-dropdown.js +4 -8
  54. package/js/virtual-dropdown.ts +5 -9
  55. package/package.json +1 -1
package/js/timepicker.js CHANGED
@@ -1,11 +1,18 @@
1
1
  class TimeSpanPicker {
2
- constructor(containerId, options) {
3
- const element = document.getElementById(containerId);
2
+ constructor(elementOrSelector, options) {
3
+ this.handleStartChange = () => { this.handleChange(); };
4
+ this.handleEndChange = () => { this.handleChange(); };
5
+ const element = typeof elementOrSelector === 'string'
6
+ ? (elementOrSelector.startsWith('#') || elementOrSelector.startsWith('.')
7
+ ? document.querySelector(elementOrSelector)
8
+ : document.getElementById(elementOrSelector))
9
+ : elementOrSelector;
4
10
  if (!element) {
5
- throw new Error(`Container with id "${containerId}" not found`);
11
+ throw new Error(`TimeSpanPicker: Element not found for "${elementOrSelector}"`);
6
12
  }
7
13
  this.container = element;
8
14
  this.onChange = options?.onChange;
15
+ this.uid = `tsp-${Math.random().toString(36).slice(2, 9)}`;
9
16
  this.render();
10
17
  this.startTimeInput = this.queryInput('.timespan-start');
11
18
  this.endTimeInput = this.queryInput('.timespan-end');
@@ -15,6 +22,18 @@ class TimeSpanPicker {
15
22
  if (options?.defaultEnd) {
16
23
  this.endTimeInput.value = options.defaultEnd;
17
24
  }
25
+ if (options?.fromString) {
26
+ this.fromString = options.fromString;
27
+ }
28
+ else {
29
+ this.fromString = 'From';
30
+ }
31
+ if (options?.toString) {
32
+ this.toString = options.toString;
33
+ }
34
+ else {
35
+ this.toString = 'To';
36
+ }
18
37
  this.attachEventListeners();
19
38
  // Render initial state if defaults provided
20
39
  if (options?.defaultStart || options?.defaultEnd) {
@@ -29,15 +48,13 @@ class TimeSpanPicker {
29
48
  return input;
30
49
  }
31
50
  render() {
51
+ const startId = `${this.uid}-start`;
52
+ const endId = `${this.uid}-end`;
32
53
  this.container.innerHTML = `
33
54
  <div class="timespan-picker">
34
55
  <div class="timespan-field timespan-field-start">
35
- <label for="timespan-start">From</label>
36
- <input
37
- type="time"
38
- class="timespan-start"
39
- id="timespan-start"
40
- />
56
+ <label for="${startId}">${this.fromString}</label>
57
+ <input type="time" class="timespan-start" id="${startId}"/>
41
58
  </div>
42
59
 
43
60
  <div class="timespan-center">
@@ -46,12 +63,8 @@ class TimeSpanPicker {
46
63
  </div>
47
64
 
48
65
  <div class="timespan-field timespan-field-end">
49
- <label for="timespan-end">To</label>
50
- <input
51
- type="time"
52
- class="timespan-end"
53
- id="timespan-end"
54
- />
66
+ <label for="${endId}">${this.toString}</label>
67
+ <input type="time" class="timespan-end" id="${endId}"/>
55
68
  </div>
56
69
  </div>
57
70
  <div class="timespan-bar" aria-hidden="true">
@@ -60,8 +73,8 @@ class TimeSpanPicker {
60
73
  `;
61
74
  }
62
75
  attachEventListeners() {
63
- this.startTimeInput.addEventListener('change', () => this.handleChange());
64
- this.endTimeInput.addEventListener('change', () => this.handleChange());
76
+ this.startTimeInput.addEventListener('change', this.handleStartChange);
77
+ this.endTimeInput.addEventListener('change', this.handleEndChange);
65
78
  }
66
79
  toMinutes(time) {
67
80
  const [h, m] = time.split(':').map(Number);
@@ -148,10 +161,8 @@ class TimeSpanPicker {
148
161
  return !!(start && end && start < end);
149
162
  }
150
163
  destroy() {
151
- const startHandler = () => this.handleChange();
152
- const endHandler = () => this.handleChange();
153
- this.startTimeInput.removeEventListener('change', startHandler);
154
- this.endTimeInput.removeEventListener('change', endHandler);
164
+ this.startTimeInput.removeEventListener('change', this.handleStartChange);
165
+ this.endTimeInput.removeEventListener('change', this.handleEndChange);
155
166
  }
156
167
  }
157
168
  export { TimeSpanPicker };
package/js/timepicker.ts CHANGED
@@ -7,6 +7,8 @@ interface TimeSpanPickerOptions {
7
7
  onChange?: (start: string, end: string) => void;
8
8
  defaultStart?: string;
9
9
  defaultEnd?: string;
10
+ fromString?: string;
11
+ toString?: string;
10
12
  }
11
13
 
12
14
  class TimeSpanPicker {
@@ -14,15 +16,26 @@ class TimeSpanPicker {
14
16
  private startTimeInput: HTMLInputElement;
15
17
  private endTimeInput: HTMLInputElement;
16
18
  private onChange?: (start: string, end: string) => void;
19
+ private readonly uid: string;
20
+ private fromString: string;
21
+ private toString: string;
22
+
23
+ constructor(elementOrSelector: string | HTMLElement, options?: TimeSpanPickerOptions) {
24
+ const element = typeof elementOrSelector === 'string'
25
+ ? (elementOrSelector.startsWith('#') || elementOrSelector.startsWith('.')
26
+ ? document.querySelector<HTMLElement>(elementOrSelector)
27
+ : document.getElementById(elementOrSelector))
28
+ : elementOrSelector;
17
29
 
18
- constructor(containerId: string, options?: TimeSpanPickerOptions) {
19
- const element = document.getElementById(containerId);
20
30
  if (!element) {
21
- throw new Error(`Container with id "${containerId}" not found`);
31
+ throw new Error(`TimeSpanPicker: Element not found for "${elementOrSelector}"`);
22
32
  }
23
33
 
24
34
  this.container = element;
25
35
  this.onChange = options?.onChange;
36
+ this.uid = `tsp-${Math.random().toString(36).slice(2, 9)}`;
37
+ this.fromString = options?.fromString ?? 'From';
38
+ this.toString = options?.toString ?? 'To';
26
39
 
27
40
  this.render();
28
41
 
@@ -53,15 +66,13 @@ class TimeSpanPicker {
53
66
  }
54
67
 
55
68
  private render(): void {
69
+ const startId = `${this.uid}-start`;
70
+ const endId = `${this.uid}-end`;
56
71
  this.container.innerHTML = `
57
72
  <div class="timespan-picker">
58
73
  <div class="timespan-field timespan-field-start">
59
- <label for="timespan-start">From</label>
60
- <input
61
- type="time"
62
- class="timespan-start"
63
- id="timespan-start"
64
- />
74
+ <label for="${startId}">${this.fromString}</label>
75
+ <input type="time" class="timespan-start" id="${startId}"/>
65
76
  </div>
66
77
 
67
78
  <div class="timespan-center">
@@ -70,12 +81,8 @@ class TimeSpanPicker {
70
81
  </div>
71
82
 
72
83
  <div class="timespan-field timespan-field-end">
73
- <label for="timespan-end">To</label>
74
- <input
75
- type="time"
76
- class="timespan-end"
77
- id="timespan-end"
78
- />
84
+ <label for="${endId}">${this.toString}</label>
85
+ <input type="time" class="timespan-end" id="${endId}"/>
79
86
  </div>
80
87
  </div>
81
88
  <div class="timespan-bar" aria-hidden="true">
@@ -84,9 +91,12 @@ class TimeSpanPicker {
84
91
  `;
85
92
  }
86
93
 
94
+ private readonly handleStartChange = (): void => { this.handleChange(); };
95
+ private readonly handleEndChange = (): void => { this.handleChange(); };
96
+
87
97
  private attachEventListeners(): void {
88
- this.startTimeInput.addEventListener('change', () => this.handleChange());
89
- this.endTimeInput.addEventListener('change', () => this.handleChange());
98
+ this.startTimeInput.addEventListener('change', this.handleStartChange);
99
+ this.endTimeInput.addEventListener('change', this.handleEndChange);
90
100
  }
91
101
 
92
102
  private toMinutes(time: string): number {
@@ -183,10 +193,8 @@ class TimeSpanPicker {
183
193
  }
184
194
 
185
195
  public destroy(): void {
186
- const startHandler = () => this.handleChange();
187
- const endHandler = () => this.handleChange();
188
- this.startTimeInput.removeEventListener('change', startHandler);
189
- this.endTimeInput.removeEventListener('change', endHandler);
196
+ this.startTimeInput.removeEventListener('change', this.handleStartChange);
197
+ this.endTimeInput.removeEventListener('change', this.handleEndChange);
190
198
  }
191
199
  }
192
200
 
package/js/toast.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { escapeHtml } from './utils.js';
1
2
  class Toast {
2
3
  constructor(contentOrOptions, header = '', type, closeable = true) {
3
4
  this.closureIcon = '<div class="icon icon-close close"></div>';
@@ -79,15 +80,10 @@ class Toast {
79
80
  parts.push(this.closureIcon);
80
81
  }
81
82
  if (this.header) {
82
- parts.push(`<div class="header">${this.escapeHtml(this.header)}</div>`);
83
+ parts.push(`<div class="header">${escapeHtml(this.header)}</div>`);
83
84
  }
84
- parts.push(`<div class="content">${this.escapeHtml(this.content)}</div>`);
85
+ parts.push(`<div class="content">${escapeHtml(this.content)}</div>`);
85
86
  return parts.join('');
86
87
  }
87
- escapeHtml(text) {
88
- const div = document.createElement('div');
89
- div.textContent = text;
90
- return div.innerHTML;
91
- }
92
88
  }
93
89
  export { Toast };
package/js/toast.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { escapeHtml } from './utils.js';
2
+
1
3
  type ToastType = 'success' | 'error' | 'warning' | 'info';
2
4
 
3
5
  interface ToastOptions {
@@ -119,19 +121,13 @@ class Toast {
119
121
  }
120
122
 
121
123
  if (this.header) {
122
- parts.push(`<div class="header">${this.escapeHtml(this.header)}</div>`);
124
+ parts.push(`<div class="header">${escapeHtml(this.header)}</div>`);
123
125
  }
124
126
 
125
- parts.push(`<div class="content">${this.escapeHtml(this.content)}</div>`);
127
+ parts.push(`<div class="content">${escapeHtml(this.content)}</div>`);
126
128
 
127
129
  return parts.join('');
128
130
  }
129
-
130
- private escapeHtml(text: string): string {
131
- const div = document.createElement('div');
132
- div.textContent = text;
133
- return div.innerHTML;
134
- }
135
131
  }
136
132
 
137
133
  export { Toast };
package/js/tooltip.js CHANGED
@@ -23,7 +23,8 @@ class Tooltip {
23
23
  position: options.position ?? 'auto',
24
24
  offset: options.offset ?? 8,
25
25
  delay: options.delay ?? 0,
26
- className: options.className ?? ''
26
+ className: options.className ?? '',
27
+ isHtml: options.isHtml ?? false,
27
28
  };
28
29
  this.attachEvents();
29
30
  }
@@ -34,7 +35,7 @@ class Tooltip {
34
35
  const position = trigger.getAttribute('data-tooltip-position') ?? 'auto';
35
36
  const className = trigger.getAttribute('data-tooltip-class') ?? '';
36
37
  if (content) {
37
- new Tooltip(trigger, content, { position, className });
38
+ new Tooltip(trigger, content, { position, className, isHtml: false });
38
39
  }
39
40
  });
40
41
  // Also support content from separate elements
@@ -47,7 +48,7 @@ class Tooltip {
47
48
  const contentElement = document.getElementById(contentId);
48
49
  if (contentElement) {
49
50
  const content = contentElement.innerHTML;
50
- new Tooltip(trigger, content, { position, className });
51
+ new Tooltip(trigger, content, { position, className, isHtml: true });
51
52
  }
52
53
  }
53
54
  });
@@ -94,7 +95,15 @@ class Tooltip {
94
95
  tooltip.className = 'tooltip';
95
96
  tooltip.id = `tooltip-${++Tooltip.idCounter}`;
96
97
  tooltip.setAttribute('role', 'tooltip');
97
- tooltip.innerHTML = `<div class="tooltip-content">${this.content}</div>`;
98
+ const tooltipContent = document.createElement('div');
99
+ tooltipContent.className = 'tooltip-content';
100
+ if (this.options.isHtml) {
101
+ tooltipContent.innerHTML = this.content;
102
+ }
103
+ else {
104
+ tooltipContent.textContent = this.content;
105
+ }
106
+ tooltip.appendChild(tooltipContent);
98
107
  if (this.options.className) {
99
108
  tooltip.classList.add(this.options.className);
100
109
  }
package/js/tooltip.ts CHANGED
@@ -7,6 +7,9 @@ interface TooltipOptions {
7
7
  offset?: number;
8
8
  delay?: number;
9
9
  className?: string;
10
+ /** Set to true when content is trusted HTML (e.g. from data-tooltip-id).
11
+ * Defaults to false — content is treated as plain text and escaped. */
12
+ isHtml?: boolean;
10
13
  }
11
14
 
12
15
  class Tooltip {
@@ -27,7 +30,8 @@ class Tooltip {
27
30
  position: options.position ?? 'auto',
28
31
  offset: options.offset ?? 8,
29
32
  delay: options.delay ?? 0,
30
- className: options.className ?? ''
33
+ className: options.className ?? '',
34
+ isHtml: options.isHtml ?? false,
31
35
  };
32
36
 
33
37
  this.attachEvents();
@@ -41,7 +45,7 @@ class Tooltip {
41
45
  const className = trigger.getAttribute('data-tooltip-class') ?? '';
42
46
 
43
47
  if (content) {
44
- new Tooltip(trigger, content, { position, className });
48
+ new Tooltip(trigger, content, { position, className, isHtml: false });
45
49
  }
46
50
  });
47
51
 
@@ -56,7 +60,7 @@ class Tooltip {
56
60
  const contentElement = document.getElementById(contentId);
57
61
  if (contentElement) {
58
62
  const content = contentElement.innerHTML;
59
- new Tooltip(trigger, content, { position, className });
63
+ new Tooltip(trigger, content, { position, className, isHtml: true });
60
64
  }
61
65
  }
62
66
  });
@@ -113,7 +117,15 @@ class Tooltip {
113
117
  tooltip.className = 'tooltip';
114
118
  tooltip.id = `tooltip-${++Tooltip.idCounter}`;
115
119
  tooltip.setAttribute('role', 'tooltip');
116
- tooltip.innerHTML = `<div class="tooltip-content">${this.content}</div>`;
120
+
121
+ const tooltipContent = document.createElement('div');
122
+ tooltipContent.className = 'tooltip-content';
123
+ if (this.options.isHtml) {
124
+ tooltipContent.innerHTML = this.content;
125
+ } else {
126
+ tooltipContent.textContent = this.content;
127
+ }
128
+ tooltip.appendChild(tooltipContent);
117
129
 
118
130
  if (this.options.className) {
119
131
  tooltip.classList.add(this.options.className);
package/js/tree.js CHANGED
@@ -168,6 +168,10 @@ class TreeComponent {
168
168
  }
169
169
  });
170
170
  }
171
+ destroy() {
172
+ this.container.innerHTML = '';
173
+ this.selectedNode = null;
174
+ }
171
175
  getSelectedNode() {
172
176
  return this.selectedNode;
173
177
  }
package/js/tree.ts CHANGED
@@ -215,6 +215,11 @@ class TreeComponent {
215
215
  });
216
216
  }
217
217
 
218
+ public destroy(): void {
219
+ this.container.innerHTML = '';
220
+ this.selectedNode = null;
221
+ }
222
+
218
223
  public getSelectedNode(): TreeNode | null {
219
224
  return this.selectedNode;
220
225
  }
package/js/utils.js CHANGED
@@ -66,4 +66,32 @@ const utils = {
66
66
  return element.offsetParent === null;
67
67
  }
68
68
  };
69
- export { utils };
69
+ /**
70
+ * Escape a plain-text string so it is safe to inject into innerHTML.
71
+ * Use this whenever inserting user-controlled strings into HTML templates.
72
+ */
73
+ function escapeHtml(text) {
74
+ const div = document.createElement('div');
75
+ div.textContent = text;
76
+ return div.innerHTML;
77
+ }
78
+ /**
79
+ * Sanitize an HTML string by removing dangerous elements and attributes
80
+ * (script, iframe, on* handlers, javascript: hrefs) while preserving safe markup.
81
+ * Use this when a component intentionally accepts rich HTML from callers.
82
+ */
83
+ function sanitizeHtml(html) {
84
+ const parser = new DOMParser();
85
+ const doc = parser.parseFromString(html, 'text/html');
86
+ doc.querySelectorAll('script, style, iframe, object, embed').forEach(el => el.remove());
87
+ doc.querySelectorAll('*').forEach(el => {
88
+ for (const attr of Array.from(el.attributes)) {
89
+ if (attr.name.startsWith('on') ||
90
+ attr.value.trim().toLowerCase().startsWith('javascript:')) {
91
+ el.removeAttribute(attr.name);
92
+ }
93
+ }
94
+ });
95
+ return doc.body.innerHTML;
96
+ }
97
+ export { utils, escapeHtml, sanitizeHtml };
package/js/utils.ts CHANGED
@@ -81,4 +81,39 @@ const utils: Utils = {
81
81
  }
82
82
  };
83
83
 
84
- export { utils };
84
+ /**
85
+ * Escape a plain-text string so it is safe to inject into innerHTML.
86
+ * Use this whenever inserting user-controlled strings into HTML templates.
87
+ */
88
+ function escapeHtml(text: string): string {
89
+ const div = document.createElement('div');
90
+ div.textContent = text;
91
+ return div.innerHTML;
92
+ }
93
+
94
+ /**
95
+ * Sanitize an HTML string by removing dangerous elements and attributes
96
+ * (script, iframe, on* handlers, javascript: hrefs) while preserving safe markup.
97
+ * Use this when a component intentionally accepts rich HTML from callers.
98
+ */
99
+ function sanitizeHtml(html: string): string {
100
+ const parser = new DOMParser();
101
+ const doc = parser.parseFromString(html, 'text/html');
102
+
103
+ doc.querySelectorAll('script, style, iframe, object, embed').forEach(el => el.remove());
104
+
105
+ doc.querySelectorAll('*').forEach(el => {
106
+ for (const attr of Array.from(el.attributes)) {
107
+ if (
108
+ attr.name.startsWith('on') ||
109
+ attr.value.trim().toLowerCase().startsWith('javascript:')
110
+ ) {
111
+ el.removeAttribute(attr.name);
112
+ }
113
+ }
114
+ });
115
+
116
+ return doc.body.innerHTML;
117
+ }
118
+
119
+ export { utils, escapeHtml, sanitizeHtml };
@@ -1,3 +1,4 @@
1
+ import { escapeHtml } from './utils.js';
1
2
  class VirtualDropdown {
2
3
  constructor(config) {
3
4
  const containerElement = typeof config.container === 'string'
@@ -30,7 +31,7 @@ class VirtualDropdown {
30
31
  renderBase() {
31
32
  this.container.innerHTML = `
32
33
  <div class="dropdown-trigger" tabindex="0" role="button" aria-haspopup="listbox" aria-expanded="false">
33
- <span class="trigger-text">${this.escapeHtml(this.placeholder)}</span>
34
+ <span class="trigger-text">${escapeHtml(this.placeholder)}</span>
34
35
  <span class="trigger-arrow" aria-hidden="true">▼</span>
35
36
  </div>
36
37
  <div class="dropdown-menu" role="listbox">
@@ -146,14 +147,14 @@ class VirtualDropdown {
146
147
  const isSelected = this.selectedValues.has(opt.value);
147
148
  return `
148
149
  <div class="dropdown-item ${isSelected ? 'selected' : ''}"
149
- data-value="${this.escapeHtml(String(opt.value))}"
150
+ data-value="${escapeHtml(String(opt.value))}"
150
151
  data-idx="${realIdx}"
151
152
  role="option"
152
153
  aria-selected="${isSelected}"
153
154
  tabindex="0"
154
155
  style="height: ${this.itemHeight}px; line-height: ${this.itemHeight}px;">
155
156
  ${this.multiSelect ? `<input type="checkbox" ${isSelected ? 'checked' : ''} tabindex="-1" aria-hidden="true">` : ''}
156
- <span class="item-label">${this.escapeHtml(opt.label)}</span>
157
+ <span class="item-label">${escapeHtml(opt.label)}</span>
157
158
  </div>
158
159
  `;
159
160
  })
@@ -221,11 +222,6 @@ class VirtualDropdown {
221
222
  }
222
223
  }
223
224
  }
224
- escapeHtml(text) {
225
- const div = document.createElement('div');
226
- div.textContent = text;
227
- return div.innerHTML;
228
- }
229
225
  getValue() {
230
226
  return Array.from(this.selectedValues);
231
227
  }
@@ -1,3 +1,5 @@
1
+ import { escapeHtml } from './utils.js';
2
+
1
3
  interface DropdownOption {
2
4
  label: string;
3
5
  value: string | number;
@@ -77,7 +79,7 @@ class VirtualDropdown {
77
79
  private renderBase(): void {
78
80
  this.container.innerHTML = `
79
81
  <div class="dropdown-trigger" tabindex="0" role="button" aria-haspopup="listbox" aria-expanded="false">
80
- <span class="trigger-text">${this.escapeHtml(this.placeholder)}</span>
82
+ <span class="trigger-text">${escapeHtml(this.placeholder)}</span>
81
83
  <span class="trigger-arrow" aria-hidden="true">▼</span>
82
84
  </div>
83
85
  <div class="dropdown-menu" role="listbox">
@@ -215,14 +217,14 @@ class VirtualDropdown {
215
217
  const isSelected = this.selectedValues.has(opt.value);
216
218
  return `
217
219
  <div class="dropdown-item ${isSelected ? 'selected' : ''}"
218
- data-value="${this.escapeHtml(String(opt.value))}"
220
+ data-value="${escapeHtml(String(opt.value))}"
219
221
  data-idx="${realIdx}"
220
222
  role="option"
221
223
  aria-selected="${isSelected}"
222
224
  tabindex="0"
223
225
  style="height: ${this.itemHeight}px; line-height: ${this.itemHeight}px;">
224
226
  ${this.multiSelect ? `<input type="checkbox" ${isSelected ? 'checked' : ''} tabindex="-1" aria-hidden="true">` : ''}
225
- <span class="item-label">${this.escapeHtml(opt.label)}</span>
227
+ <span class="item-label">${escapeHtml(opt.label)}</span>
226
228
  </div>
227
229
  `;
228
230
  })
@@ -299,12 +301,6 @@ class VirtualDropdown {
299
301
  }
300
302
  }
301
303
 
302
- private escapeHtml(text: string): string {
303
- const div = document.createElement('div');
304
- div.textContent = text;
305
- return div.innerHTML;
306
- }
307
-
308
304
  public getValue(): Array<string | number> {
309
305
  return Array.from(this.selectedValues);
310
306
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dodlhuat/basix",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
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/*",