@vanilla-bean/components 1.1.1 → 2.0.1
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/Component/Component.js +222 -36
- package/Component/Component.test.js +425 -38
- package/Component/README.md +480 -0
- package/Elem/README.md +373 -0
- package/README.md +1 -1
- package/components/BottomSheet/BottomSheet.js +8 -16
- package/components/Button/Button.js +12 -18
- package/components/Calendar/Calendar.js +139 -59
- package/components/Calendar/CalendarEvent.js +9 -4
- package/components/Calendar/Toolbar.js +28 -20
- package/components/Calendar/index.js +1 -0
- package/components/Code/Code.js +26 -30
- package/components/ColorPicker/ColorPicker.js +57 -57
- package/components/Dialog/Dialog.js +78 -72
- package/components/Form/Form.js +12 -8
- package/components/Icon/Icon.js +19 -11
- package/components/Input/Input.js +85 -67
- package/components/Input/README.md +0 -2
- package/components/Keyboard/Key.js +7 -10
- package/components/Keyboard/Keyboard.js +38 -46
- package/components/Label/Label.js +52 -50
- package/components/Link/Link.js +14 -20
- package/components/List/List.js +28 -30
- package/components/Menu/Menu.js +19 -10
- package/components/Menu/Menu.lld.md +2 -2
- package/components/Notify/Notify.js +29 -19
- package/components/Popover/Popover.js +49 -44
- package/components/RadioButton/RadioButton.js +33 -29
- package/components/Router/Router.js +19 -21
- package/components/Select/Select.js +24 -30
- package/components/Table/Table.js +55 -36
- package/components/TagList/Tag.js +16 -14
- package/components/TagList/TagList.js +15 -8
- package/components/Tooltip/Tooltip.js +12 -25
- package/components/TooltipWrapper/TooltipWrapper.js +55 -49
- package/components/Whiteboard/Whiteboard.js +45 -43
- package/devTools/build.js +43 -0
- package/devTools/buildTypes.js +322 -0
- package/devTools/createComponent.js +155 -0
- package/devTools/extractJSDoc.js +395 -0
- package/devTools/processTemplate.js +500 -0
- package/devTools/updateComponentIndex.js +16 -0
- package/devTools/updateDemoViewIndex.js +90 -0
- package/eslint.config.cjs +6 -3
- package/index.d.ts +117 -59
- package/package.json +67 -22
- package/spellcheck.config.cjs +4 -0
- package/styled/README.md +329 -0
- package/theme/colors.js +15 -12
- package/theme/colors.test.js +28 -0
- package/utils/element.js +2 -2
- package/FontWithASyntaxHighlighter-Regular.woff2 +0 -0
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
import { Elem } from '../../Elem';
|
|
2
2
|
import { Input } from '../Input';
|
|
3
3
|
|
|
4
|
-
const defaultOptions = {
|
|
5
|
-
tag: 'select',
|
|
6
|
-
get priorityOptions() {
|
|
7
|
-
return new Set(['textContent', 'content', 'appendTo', 'prependTo', 'options']);
|
|
8
|
-
},
|
|
9
|
-
};
|
|
10
|
-
|
|
11
4
|
/**
|
|
12
5
|
* Select dropdown component extending Input with dynamic option management.
|
|
13
6
|
*
|
|
@@ -21,33 +14,34 @@ const defaultOptions = {
|
|
|
21
14
|
* @returns {Select} Select component instance
|
|
22
15
|
*/
|
|
23
16
|
class Select extends Input {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
static schema = {
|
|
18
|
+
tag: { default: 'select' },
|
|
19
|
+
autocomplete: { default: 'off' },
|
|
20
|
+
options: {
|
|
21
|
+
set(value) {
|
|
22
|
+
this.empty();
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
options(value) {
|
|
32
|
-
this.empty();
|
|
24
|
+
if (!value) return;
|
|
33
25
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
for (const option of value) {
|
|
27
|
+
// Optgroup: { label: 'Group', options: [...] }
|
|
28
|
+
if (typeof option === 'object' && Array.isArray(option.options)) {
|
|
29
|
+
const group = document.createElement('optgroup');
|
|
30
|
+
if (option.label) group.label = option.label;
|
|
31
|
+
for (const o of option.options) {
|
|
32
|
+
group.append(new Elem({ tag: 'option', ...(typeof o === 'object' ? o : { label: o, value: o }) }).elem);
|
|
33
|
+
}
|
|
34
|
+
this.elem.append(group);
|
|
35
|
+
} else {
|
|
36
|
+
this.append(
|
|
37
|
+
new Elem({ tag: 'option', ...(typeof option === 'object' ? option : { label: option, value: option }) }),
|
|
38
|
+
);
|
|
43
39
|
}
|
|
44
|
-
this.elem.append(group);
|
|
45
|
-
} else {
|
|
46
|
-
this.append(
|
|
47
|
-
new Elem({ tag: 'option', ...(typeof option === 'object' ? option : { label: option, value: option }) }),
|
|
48
|
-
);
|
|
49
40
|
}
|
|
50
|
-
|
|
41
|
+
|
|
42
|
+
// Re-apply the current value - option elements may not have existed when value was processed
|
|
43
|
+
if (this.options.value !== undefined) this.elem.value = this.options.value;
|
|
44
|
+
},
|
|
51
45
|
},
|
|
52
46
|
};
|
|
53
47
|
|
|
@@ -4,8 +4,6 @@ import { Elem } from '../../Elem';
|
|
|
4
4
|
import { Component } from '../../Component';
|
|
5
5
|
import { Icon } from '../Icon';
|
|
6
6
|
|
|
7
|
-
const defaultOptions = { tag: 'table' };
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* Data table component with sorting, column configuration, and footer support.
|
|
11
9
|
*
|
|
@@ -23,37 +21,55 @@ const defaultOptions = { tag: 'table' };
|
|
|
23
21
|
* @returns {Table} Table component instance
|
|
24
22
|
*/
|
|
25
23
|
class Table extends Component {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
footer: options.footer?.map(column => (typeof column === 'string' ? { content: capitalize(column) } : column)),
|
|
24
|
+
static schema = {
|
|
25
|
+
tag: { default: 'table' },
|
|
26
|
+
sortDirection: {
|
|
27
|
+
enum: ['asc', 'desc'],
|
|
28
|
+
set(value) {
|
|
29
|
+
if (!this.rendered) return;
|
|
30
|
+
if (this.options.onSort) this.options.onSort(this.options.sortProperty, value);
|
|
31
|
+
else
|
|
32
|
+
this.options.data = this.options.data.sort(
|
|
33
|
+
orderBy({ property: this.options.sortProperty, direction: value }),
|
|
34
|
+
);
|
|
38
35
|
},
|
|
39
|
-
...children,
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static handlers = {
|
|
44
|
-
sortDirection(value) {
|
|
45
|
-
if (this.rendered) this.options.onSort(this.options.sortProperty, value);
|
|
46
36
|
},
|
|
47
|
-
data
|
|
48
|
-
|
|
37
|
+
data: {
|
|
38
|
+
set() {
|
|
39
|
+
this._renderTable();
|
|
40
|
+
},
|
|
49
41
|
},
|
|
50
|
-
selection
|
|
51
|
-
|
|
42
|
+
selection: {
|
|
43
|
+
set() {
|
|
44
|
+
this._renderTable();
|
|
45
|
+
},
|
|
52
46
|
},
|
|
47
|
+
columns: {
|
|
48
|
+
set() {
|
|
49
|
+
if (this.rendered) this._renderTable();
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
footer: {
|
|
53
|
+
set() {
|
|
54
|
+
if (this.rendered) this._renderTable();
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// Read from this.options at sort time; sortProperty changes are always followed
|
|
58
|
+
// by a sortDirection change, which drives the re-render
|
|
59
|
+
sortProperty: {},
|
|
60
|
+
onSort: {},
|
|
53
61
|
};
|
|
54
62
|
|
|
55
63
|
_renderTable() {
|
|
56
64
|
const value = this.options.data;
|
|
65
|
+
// Columns and footer accept string shorthand - normalized at read time so
|
|
66
|
+
// construction and reactive assignment take the same path
|
|
67
|
+
const columns = (this.options.columns || []).map(column =>
|
|
68
|
+
typeof column === 'string' ? { key: column, content: capitalize(column) } : column,
|
|
69
|
+
);
|
|
70
|
+
const footer = this.options.footer?.map(column =>
|
|
71
|
+
typeof column === 'string' ? { content: capitalize(column) } : column,
|
|
72
|
+
);
|
|
57
73
|
|
|
58
74
|
this._sortSubscribers?.forEach(sub => sub.destroy?.());
|
|
59
75
|
this._sortSubscribers = null;
|
|
@@ -75,19 +91,22 @@ class Table extends Component {
|
|
|
75
91
|
this.thead.append(
|
|
76
92
|
new Component(
|
|
77
93
|
{ tag: 'tr' },
|
|
78
|
-
|
|
79
|
-
|
|
94
|
+
columns.map(column => {
|
|
95
|
+
// key/sort/dataColumn are column config for the Table itself - keep them off the th elem
|
|
96
|
+
const { key, sort, ...columnOptions } = column;
|
|
97
|
+
delete columnOptions.dataColumn;
|
|
98
|
+
const th = new Component({ tag: 'th', ...columnOptions, scope: 'col' });
|
|
80
99
|
|
|
81
|
-
if (
|
|
100
|
+
if (sort) {
|
|
82
101
|
const iconSub = this.options.subscriber('sortDirection', () => {
|
|
83
|
-
if (this.options.sortProperty !==
|
|
102
|
+
if (this.options.sortProperty !== key) return 'sort';
|
|
84
103
|
|
|
85
104
|
return this.options.sortDirection === 'asc' ? 'sort-down' : 'sort-up';
|
|
86
105
|
});
|
|
87
106
|
const styleSub = this.options.subscriber('sortDirection', () => ({
|
|
88
107
|
display: 'inline',
|
|
89
108
|
marginLeft: '6px',
|
|
90
|
-
...(this.options.sortProperty !==
|
|
109
|
+
...(this.options.sortProperty !== key
|
|
91
110
|
? { color: theme.colors.dark(theme.colors.gray) }
|
|
92
111
|
: { color: theme.colors.white }),
|
|
93
112
|
}));
|
|
@@ -96,7 +115,7 @@ class Table extends Component {
|
|
|
96
115
|
|
|
97
116
|
const updateAriaSort = () => {
|
|
98
117
|
let ariaSort = 'none';
|
|
99
|
-
if (this.options.sortProperty ===
|
|
118
|
+
if (this.options.sortProperty === key) {
|
|
100
119
|
ariaSort = this.options.sortDirection === 'asc' ? 'ascending' : 'descending';
|
|
101
120
|
}
|
|
102
121
|
th.elem.setAttribute('aria-sort', ariaSort);
|
|
@@ -121,12 +140,12 @@ class Table extends Component {
|
|
|
121
140
|
});
|
|
122
141
|
|
|
123
142
|
th.onPointerPress(() => {
|
|
124
|
-
if (this.options.sortProperty ===
|
|
143
|
+
if (this.options.sortProperty === key) {
|
|
125
144
|
this.options.sortDirection = this.options.sortDirection === 'asc' ? 'desc' : 'asc';
|
|
126
145
|
return;
|
|
127
146
|
}
|
|
128
147
|
|
|
129
|
-
this.options.sortProperty =
|
|
148
|
+
this.options.sortProperty = key;
|
|
130
149
|
this.options.sortDirection = 'desc';
|
|
131
150
|
});
|
|
132
151
|
}
|
|
@@ -141,7 +160,7 @@ class Table extends Component {
|
|
|
141
160
|
rowData =>
|
|
142
161
|
new Component(
|
|
143
162
|
{ tag: 'tr' },
|
|
144
|
-
|
|
163
|
+
columns.map(
|
|
145
164
|
column =>
|
|
146
165
|
new Component(
|
|
147
166
|
{
|
|
@@ -157,11 +176,11 @@ class Table extends Component {
|
|
|
157
176
|
),
|
|
158
177
|
);
|
|
159
178
|
|
|
160
|
-
if (
|
|
179
|
+
if (footer) {
|
|
161
180
|
this.tfoot.append(
|
|
162
181
|
new Component(
|
|
163
182
|
{ tag: 'tr' },
|
|
164
|
-
|
|
183
|
+
footer.map(footData => new Component({ tag: 'td', ...footData })),
|
|
165
184
|
),
|
|
166
185
|
);
|
|
167
186
|
}
|
|
@@ -52,14 +52,23 @@ const StyledComponent = styled(
|
|
|
52
52
|
`,
|
|
53
53
|
);
|
|
54
54
|
|
|
55
|
-
const defaultOptions = { tag: 'li', readOnly: false };
|
|
56
|
-
|
|
57
55
|
class Tag extends StyledComponent {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
static schema = {
|
|
57
|
+
tag: { default: 'li' },
|
|
58
|
+
tabIndex: { default: 0 },
|
|
59
|
+
readOnly: {
|
|
60
|
+
default: false,
|
|
61
|
+
set(value) {
|
|
62
|
+
this.toggleClass('readOnly', !!value);
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
textContent: {
|
|
66
|
+
set(value) {
|
|
67
|
+
this.elem.setAttribute('data-value', value);
|
|
68
|
+
this._textSpan.elem.textContent = value;
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
};
|
|
63
72
|
|
|
64
73
|
build() {
|
|
65
74
|
this._textSpan = new Elem({ tag: 'span', appendTo: this });
|
|
@@ -72,13 +81,6 @@ class Tag extends StyledComponent {
|
|
|
72
81
|
});
|
|
73
82
|
}
|
|
74
83
|
}
|
|
75
|
-
|
|
76
|
-
static handlers = {
|
|
77
|
-
textContent(value) {
|
|
78
|
-
this.elem.setAttribute('data-value', value);
|
|
79
|
-
this._textSpan.elem.textContent = value;
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
export default Tag;
|
|
@@ -32,8 +32,6 @@ const TagListInput = styled(
|
|
|
32
32
|
`,
|
|
33
33
|
);
|
|
34
34
|
|
|
35
|
-
const defaultOptions = { readOnly: false };
|
|
36
|
-
|
|
37
35
|
/**
|
|
38
36
|
* Interactive tag list component with add/remove functionality and input support.
|
|
39
37
|
*
|
|
@@ -47,11 +45,20 @@ const defaultOptions = { readOnly: false };
|
|
|
47
45
|
* @returns {TagList} TagList component instance
|
|
48
46
|
*/
|
|
49
47
|
class TagList extends StyledComponent {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
static schema = {
|
|
49
|
+
tag: { default: 'ul' },
|
|
50
|
+
readOnly: {
|
|
51
|
+
default: false,
|
|
52
|
+
set(value) {
|
|
53
|
+
this.toggleClass('readOnly', !!value);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
tags: {
|
|
57
|
+
get default() {
|
|
58
|
+
return [];
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
55
62
|
|
|
56
63
|
_addTag(value) {
|
|
57
64
|
value = (value || '').trim();
|
|
@@ -91,7 +98,7 @@ class TagList extends StyledComponent {
|
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
this.append([
|
|
94
|
-
...
|
|
101
|
+
...this.options.tags.map(textContent => new Tag({ readOnly: this.options.readOnly, textContent })),
|
|
95
102
|
...(this.addTag ? [this.addTag] : []),
|
|
96
103
|
]);
|
|
97
104
|
}
|
|
@@ -80,8 +80,6 @@ const StyledPopover = styled(
|
|
|
80
80
|
`,
|
|
81
81
|
);
|
|
82
82
|
|
|
83
|
-
const defaultOptions = { position: 'topRight', autoOpen: false };
|
|
84
|
-
|
|
85
83
|
const position_enum = Object.freeze([
|
|
86
84
|
'center',
|
|
87
85
|
'top',
|
|
@@ -108,32 +106,21 @@ const position_enum = Object.freeze([
|
|
|
108
106
|
* @returns {Tooltip} Tooltip component instance
|
|
109
107
|
*/
|
|
110
108
|
class Tooltip extends StyledPopover {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
{
|
|
117
|
-
...
|
|
118
|
-
|
|
119
|
-
addClass: ['tooltip'].concat(options.addClass),
|
|
109
|
+
static schema = {
|
|
110
|
+
autoOpen: { default: false },
|
|
111
|
+
position: {
|
|
112
|
+
default: 'topRight',
|
|
113
|
+
enum: position_enum,
|
|
114
|
+
set(value) {
|
|
115
|
+
this.removeClass(...position_enum);
|
|
116
|
+
this.addClass(value);
|
|
120
117
|
},
|
|
121
|
-
...children,
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
static handlers = {
|
|
126
|
-
position(value) {
|
|
127
|
-
if (!position_enum.includes(value)) {
|
|
128
|
-
throw new Error(
|
|
129
|
-
`"${value}" is not a valid position. The position must be one of the following values: ${position_enum.join(', ')}`,
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
this.removeClass(...position_enum);
|
|
134
|
-
this.addClass(value);
|
|
135
118
|
},
|
|
136
119
|
};
|
|
120
|
+
|
|
121
|
+
static prepareOptions(options) {
|
|
122
|
+
return { ...options, addClass: ['tooltip'].concat(options.addClass) };
|
|
123
|
+
}
|
|
137
124
|
}
|
|
138
125
|
|
|
139
126
|
export default Tooltip;
|
|
@@ -29,61 +29,67 @@ const StyledIcon = styled(
|
|
|
29
29
|
* @returns {TooltipWrapper} TooltipWrapper component instance
|
|
30
30
|
*/
|
|
31
31
|
export default class TooltipWrapper extends StyledIcon {
|
|
32
|
-
static
|
|
33
|
-
tooltip
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
static schema = {
|
|
33
|
+
tooltip: {
|
|
34
|
+
set(value) {
|
|
35
|
+
this._applyTooltip(value);
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
36
39
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this._tooltip = new Tooltip({
|
|
41
|
-
appendTo: this.elem,
|
|
42
|
-
...tooltipOptions,
|
|
43
|
-
});
|
|
40
|
+
_applyTooltip(value) {
|
|
41
|
+
if (value == null) return;
|
|
42
|
+
const tooltipOptions = typeof value === 'object' ? value : { textContent: value };
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
if (this._tooltip) {
|
|
45
|
+
this._tooltip.setOptions(tooltipOptions);
|
|
46
|
+
} else {
|
|
47
|
+
this._tooltip = new Tooltip({
|
|
48
|
+
appendTo: this.elem,
|
|
49
|
+
...tooltipOptions,
|
|
50
|
+
});
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
targetEvent: 'pointerover',
|
|
49
|
-
callback: ({ clientX, clientY }) => {
|
|
50
|
-
this.tooltipTimeout = setTimeout(() => this._tooltip?.show({ x: clientX, y: clientY }), 700);
|
|
51
|
-
},
|
|
52
|
-
});
|
|
52
|
+
this.addClass('has-tooltip');
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
});
|
|
54
|
+
this.on({
|
|
55
|
+
targetEvent: 'pointerover',
|
|
56
|
+
callback: ({ clientX, clientY }) => {
|
|
57
|
+
this.tooltipTimeout = setTimeout(() => this._tooltip?.show({ x: clientX, y: clientY }), 700);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
61
|
+
this.on({
|
|
62
|
+
targetEvent: 'pointerout',
|
|
63
|
+
callback: () => {
|
|
64
|
+
clearTimeout(this.tooltipTimeout);
|
|
65
|
+
if (!this.elem.contains(document.activeElement)) this._tooltip?.hide();
|
|
66
|
+
},
|
|
67
|
+
});
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
}
|
|
69
|
+
this.on({
|
|
70
|
+
targetEvent: 'focus',
|
|
71
|
+
callback: () => {
|
|
72
|
+
clearTimeout(this.tooltipTimeout);
|
|
73
|
+
const { left, bottom } = this.elem.getBoundingClientRect();
|
|
74
|
+
this._tooltip?.show({ x: left, y: bottom });
|
|
75
|
+
},
|
|
76
|
+
});
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
this._tooltip = null;
|
|
83
|
-
}
|
|
78
|
+
this.on({
|
|
79
|
+
targetEvent: 'blur',
|
|
80
|
+
callback: () => {
|
|
84
81
|
clearTimeout(this.tooltipTimeout);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
this._tooltip?.hide();
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
this.replaceCleanup('tooltip', () => {
|
|
87
|
+
if (this._tooltip) {
|
|
88
|
+
this._tooltip.destroy?.();
|
|
89
|
+
this._tooltip = null;
|
|
90
|
+
}
|
|
91
|
+
clearTimeout(this.tooltipTimeout);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
89
95
|
}
|
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
import { throttle } from '../../utils/data';
|
|
2
2
|
import { Component } from '../../Component';
|
|
3
3
|
|
|
4
|
-
const defaultOptions = {
|
|
5
|
-
tag: 'canvas',
|
|
6
|
-
background: '#FFF',
|
|
7
|
-
color: '#000',
|
|
8
|
-
lineWidth: 3,
|
|
9
|
-
width: '200px',
|
|
10
|
-
height: '200px',
|
|
11
|
-
readOnly: false,
|
|
12
|
-
registeredEvents: new Set(['line', 'draw']),
|
|
13
|
-
};
|
|
14
|
-
|
|
15
4
|
/**
|
|
16
5
|
* Interactive drawing canvas component with multi-touch support and line rendering.
|
|
17
6
|
*
|
|
@@ -31,22 +20,52 @@ const defaultOptions = {
|
|
|
31
20
|
* @returns {Whiteboard} Whiteboard component instance
|
|
32
21
|
*/
|
|
33
22
|
export default class Whiteboard extends Component {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
style: {
|
|
42
|
-
cursor: 'crosshair',
|
|
43
|
-
touchAction: 'none',
|
|
44
|
-
borderRadius: '3px',
|
|
45
|
-
...options.style,
|
|
46
|
-
},
|
|
23
|
+
static schema = {
|
|
24
|
+
tag: { default: 'canvas' },
|
|
25
|
+
width: {
|
|
26
|
+
default: '200px',
|
|
27
|
+
set(value) {
|
|
28
|
+
this.elem.width = Number.parseInt(value);
|
|
29
|
+
this.elem.style.width = value;
|
|
47
30
|
},
|
|
48
|
-
|
|
49
|
-
|
|
31
|
+
},
|
|
32
|
+
height: {
|
|
33
|
+
default: '200px',
|
|
34
|
+
set(value) {
|
|
35
|
+
this.elem.height = Number.parseInt(value);
|
|
36
|
+
this.elem.style.height = value;
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
background: {
|
|
40
|
+
default: '#FFF',
|
|
41
|
+
set(value) {
|
|
42
|
+
this.elem.style.background = value;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
lines: {
|
|
46
|
+
set(value) {
|
|
47
|
+
value.forEach(line => this.drawLine(line));
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
// Drawing config read from this.options during draw interactions
|
|
51
|
+
color: { default: '#000' },
|
|
52
|
+
lineWidth: { default: 3 },
|
|
53
|
+
readOnly: { default: false },
|
|
54
|
+
drawThrottle: {},
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
static events = ['line', 'draw'];
|
|
58
|
+
|
|
59
|
+
static prepareOptions(options) {
|
|
60
|
+
return {
|
|
61
|
+
...options,
|
|
62
|
+
style: {
|
|
63
|
+
cursor: 'crosshair',
|
|
64
|
+
touchAction: 'none',
|
|
65
|
+
borderRadius: '3px',
|
|
66
|
+
...options.style,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
50
69
|
}
|
|
51
70
|
|
|
52
71
|
build() {
|
|
@@ -59,23 +78,6 @@ export default class Whiteboard extends Component {
|
|
|
59
78
|
this.replaceCleanup('pointerdown', () => this.elem.removeEventListener('pointerdown', boundInteractionInit));
|
|
60
79
|
}
|
|
61
80
|
|
|
62
|
-
static handlers = {
|
|
63
|
-
width(value) {
|
|
64
|
-
this.elem.width = Number.parseInt(value);
|
|
65
|
-
this.elem.style.width = value;
|
|
66
|
-
},
|
|
67
|
-
height(value) {
|
|
68
|
-
this.elem.height = Number.parseInt(value);
|
|
69
|
-
this.elem.style.height = value;
|
|
70
|
-
},
|
|
71
|
-
lines(value) {
|
|
72
|
-
value.forEach(line => this.drawLine(line));
|
|
73
|
-
},
|
|
74
|
-
background(value) {
|
|
75
|
-
this.elem.style.background = value;
|
|
76
|
-
},
|
|
77
|
-
};
|
|
78
|
-
|
|
79
81
|
getPosition({ offsetX, offsetY }) {
|
|
80
82
|
return { x: offsetX.toFixed(3), y: offsetY.toFixed(3) };
|
|
81
83
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { watch } from 'fs';
|
|
2
|
+
import { buildLoader as asText } from '../plugins/asText';
|
|
3
|
+
import { buildLoader as markdownLoader } from '../plugins/markdownLoader';
|
|
4
|
+
|
|
5
|
+
const build = async () => {
|
|
6
|
+
console.log('Building...');
|
|
7
|
+
|
|
8
|
+
const buildResults = await Bun.build({
|
|
9
|
+
entrypoints: ['demo/index.html'],
|
|
10
|
+
outdir: 'demo/build',
|
|
11
|
+
define: {
|
|
12
|
+
'process.env.AUTOPREFIXER_GRID': 'undefined',
|
|
13
|
+
'process.cwd': 'String',
|
|
14
|
+
},
|
|
15
|
+
plugins: [asText, markdownLoader],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
console.log(buildResults.success ? 'build.success' : buildResults.logs);
|
|
19
|
+
|
|
20
|
+
return buildResults;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const enableWatcher = process.argv[2] === '--watch';
|
|
24
|
+
const watcherIgnore = /\.asText$|^demo\/build|^\.|^img\/|^devTools\//;
|
|
25
|
+
|
|
26
|
+
if (enableWatcher) {
|
|
27
|
+
console.log(`Initializing watcher`);
|
|
28
|
+
|
|
29
|
+
const watcher = watch(`${import.meta.dir}/..`, { recursive: true }, (event, filename) => {
|
|
30
|
+
if (watcherIgnore.test(filename)) return;
|
|
31
|
+
|
|
32
|
+
console.log(`Detected ${event} in ${filename}`);
|
|
33
|
+
|
|
34
|
+
build();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
process.on('SIGINT', () => {
|
|
38
|
+
watcher.close();
|
|
39
|
+
process.exit(0);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await build();
|