@dodlhuat/basix 1.2.1 → 1.2.3
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.
- package/README.md +252 -5
- package/css/lightbox.scss +272 -0
- package/css/style.css +256 -0
- package/css/style.css.map +1 -1
- package/css/style.scss +1 -0
- package/js/bottom-sheet.js +4 -3
- package/js/bottom-sheet.ts +5 -3
- package/js/calendar.js +9 -5
- package/js/calendar.ts +7 -2
- package/js/carousel.js +15 -11
- package/js/carousel.ts +16 -11
- package/js/chart.js +4 -4
- package/js/chart.ts +5 -3
- package/js/datepicker.js +11 -3
- package/js/datepicker.ts +13 -3
- package/js/docs-nav.js +1 -0
- package/js/editor.js +28 -20
- package/js/editor.ts +28 -20
- package/js/file-uploader.js +6 -10
- package/js/file-uploader.ts +7 -11
- package/js/flyout-menu.js +8 -2
- package/js/flyout-menu.ts +7 -2
- package/js/gallery.js +6 -13
- package/js/gallery.ts +8 -16
- package/js/group-picker.js +10 -7
- package/js/group-picker.ts +11 -7
- package/js/lightbox.js +277 -0
- package/js/lightbox.ts +331 -0
- package/js/modal.js +5 -4
- package/js/modal.ts +6 -4
- package/js/popover.js +4 -2
- package/js/popover.ts +4 -2
- package/js/push-menu.js +3 -2
- package/js/push-menu.ts +4 -2
- package/js/scrollbar.js +31 -23
- package/js/scrollbar.ts +36 -26
- package/js/select.js +23 -9
- package/js/select.ts +29 -11
- package/js/stepper.js +5 -1
- package/js/stepper.ts +6 -1
- package/js/table.js +8 -3
- package/js/table.ts +9 -3
- package/js/timepicker.js +20 -21
- package/js/timepicker.ts +23 -21
- package/js/toast.js +3 -7
- package/js/toast.ts +4 -8
- package/js/tooltip.js +13 -4
- package/js/tooltip.ts +16 -4
- package/js/tree.js +4 -0
- package/js/tree.ts +5 -0
- package/js/utils.js +29 -1
- package/js/utils.ts +36 -1
- package/js/virtual-dropdown.js +4 -8
- package/js/virtual-dropdown.ts +5 -9
- package/package.json +1 -3
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
|
-
|
|
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
package/js/tree.ts
CHANGED
package/js/utils.js
CHANGED
|
@@ -66,4 +66,32 @@ const utils = {
|
|
|
66
66
|
return element.offsetParent === null;
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
|
-
|
|
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
|
-
|
|
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 };
|
package/js/virtual-dropdown.js
CHANGED
|
@@ -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">${
|
|
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="${
|
|
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">${
|
|
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
|
}
|
package/js/virtual-dropdown.ts
CHANGED
|
@@ -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">${
|
|
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="${
|
|
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">${
|
|
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,10 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dodlhuat/basix",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
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
|
-
"main": "js/index.js",
|
|
6
5
|
"exports": {
|
|
7
|
-
".": "./js/index.js",
|
|
8
6
|
"./css/*": "./css/*",
|
|
9
7
|
"./js/*": "./js/*"
|
|
10
8
|
},
|