@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
|
@@ -11,19 +11,7 @@ const DialogButton = styled(
|
|
|
11
11
|
`,
|
|
12
12
|
);
|
|
13
13
|
|
|
14
|
-
const
|
|
15
|
-
const variant_enum = Object.freeze(['info', 'success', 'warning', 'error']);
|
|
16
|
-
|
|
17
|
-
const defaultOptions = {
|
|
18
|
-
tag: 'dialog',
|
|
19
|
-
size: 'small',
|
|
20
|
-
openOnRender: 16,
|
|
21
|
-
modal: true,
|
|
22
|
-
get appendTo() {
|
|
23
|
-
return document.body;
|
|
24
|
-
},
|
|
25
|
-
registeredEvents: new Set(['close']),
|
|
26
|
-
};
|
|
14
|
+
const defaultOpenDelay = 16;
|
|
27
15
|
|
|
28
16
|
/**
|
|
29
17
|
* Modal and non-modal dialog component with customizable appearance and behavior.
|
|
@@ -149,57 +137,70 @@ class Dialog extends styled(
|
|
|
149
137
|
}
|
|
150
138
|
`,
|
|
151
139
|
) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const openDelay = value ? setTimeout(() => this.open(), delay) : null;
|
|
159
|
-
this.replaceCleanup('openOnRender', () => openDelay && clearTimeout(openDelay));
|
|
140
|
+
static schema = {
|
|
141
|
+
tag: { default: 'dialog' },
|
|
142
|
+
appendTo: {
|
|
143
|
+
get default() {
|
|
144
|
+
return document.body;
|
|
145
|
+
},
|
|
160
146
|
},
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
this.removeClass(/\bsize-\S+\b/g);
|
|
172
|
-
|
|
173
|
-
if (value) this.addClass(`size-${value}`);
|
|
147
|
+
openOnRender: {
|
|
148
|
+
default: defaultOpenDelay,
|
|
149
|
+
set(value) {
|
|
150
|
+
const delay = typeof value === 'number' ? value : defaultOpenDelay;
|
|
151
|
+
const openDelay = value ? setTimeout(() => this.open(), delay) : null;
|
|
152
|
+
this.replaceCleanup('openOnRender', () => openDelay && clearTimeout(openDelay));
|
|
153
|
+
},
|
|
174
154
|
},
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
155
|
+
// Read directly from this.options.modal in open()
|
|
156
|
+
modal: { default: true },
|
|
157
|
+
size: {
|
|
158
|
+
default: 'small',
|
|
159
|
+
enum: ['small', 'standard', 'large'],
|
|
160
|
+
set(value) {
|
|
161
|
+
this.removeClass(/\bsize-\S+\b/g);
|
|
162
|
+
|
|
163
|
+
if (value) this.addClass(`size-${value}`);
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
variant: {
|
|
167
|
+
enum: ['info', 'success', 'warning', 'error'],
|
|
168
|
+
set(value) {
|
|
169
|
+
this.removeClass(/\bvariant-\S+\b/g);
|
|
183
170
|
|
|
184
|
-
|
|
171
|
+
if (value) this.addClass(`variant-${value}`);
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
body: {
|
|
175
|
+
set(value) {
|
|
176
|
+
this.body?.content(value);
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
header: {
|
|
180
|
+
set(value) {
|
|
181
|
+
this._header?.content(value);
|
|
182
|
+
},
|
|
185
183
|
},
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
buttons: {
|
|
185
|
+
set() {
|
|
186
|
+
this._refreshFooter();
|
|
187
|
+
},
|
|
188
188
|
},
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
footer: {
|
|
190
|
+
set() {
|
|
191
|
+
this._refreshFooter();
|
|
192
|
+
},
|
|
191
193
|
},
|
|
194
|
+
// Read from this.options at button-press time
|
|
195
|
+
closeDialog: {},
|
|
196
|
+
onButtonPress: {},
|
|
192
197
|
};
|
|
193
198
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
constructor(options = {}, ...children) {
|
|
197
|
-
super({ ...defaultOptions, ...options }, ...children);
|
|
199
|
+
static events = ['close'];
|
|
198
200
|
|
|
201
|
+
build() {
|
|
199
202
|
this.options['aria-labelledby'] = this.uniqueId;
|
|
200
|
-
}
|
|
201
203
|
|
|
202
|
-
build() {
|
|
203
204
|
this._header = new Elem({
|
|
204
205
|
tag: 'div',
|
|
205
206
|
id: this.uniqueId,
|
|
@@ -210,25 +211,30 @@ class Dialog extends styled(
|
|
|
210
211
|
|
|
211
212
|
this._body = new Elem({ addClass: ['content'], appendTo: this });
|
|
212
213
|
|
|
213
|
-
this._footer = new Elem({
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
214
|
+
this._footer = new Elem({ addClass: ['footer'], append: this._footerContent(), appendTo: this });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
_refreshFooter() {
|
|
218
|
+
if (this.rendered) this._footer?.content(this._footerContent() || []);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
_footerContent() {
|
|
222
|
+
return (
|
|
223
|
+
this.options.footer ||
|
|
224
|
+
this.options.buttons?.map(
|
|
225
|
+
button =>
|
|
226
|
+
new DialogButton({
|
|
227
|
+
onPointerPress: event =>
|
|
228
|
+
this.options.onButtonPress?.({
|
|
229
|
+
event,
|
|
230
|
+
button,
|
|
231
|
+
dialog: this,
|
|
232
|
+
closeDialog: this.options.closeDialog || (() => this.close()),
|
|
233
|
+
}),
|
|
234
|
+
...(typeof button === 'object' ? button : { textContent: button }),
|
|
235
|
+
}),
|
|
236
|
+
)
|
|
237
|
+
);
|
|
232
238
|
}
|
|
233
239
|
|
|
234
240
|
/**
|
package/components/Form/Form.js
CHANGED
|
@@ -65,15 +65,19 @@ export default class Form extends Component {
|
|
|
65
65
|
* Rebuild the form when inputs change without recreating the data store.
|
|
66
66
|
* Existing data is preserved; new keys are added with their initial values.
|
|
67
67
|
*/
|
|
68
|
-
static
|
|
69
|
-
inputs
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
static schema = {
|
|
69
|
+
inputs: {
|
|
70
|
+
set(value) {
|
|
71
|
+
if (!this.rendered || !value || !this.options.data) return;
|
|
72
|
+
this.empty();
|
|
73
|
+
this._resetState();
|
|
74
|
+
this._processInputs(value, this);
|
|
75
|
+
this._wireConditions();
|
|
76
|
+
this._setupAnnouncer();
|
|
77
|
+
},
|
|
76
78
|
},
|
|
79
|
+
// Data store managed by build()
|
|
80
|
+
data: {},
|
|
77
81
|
};
|
|
78
82
|
|
|
79
83
|
/** @private */
|
package/components/Icon/Icon.js
CHANGED
|
@@ -14,20 +14,28 @@ import { Component } from '../../Component';
|
|
|
14
14
|
* @returns {Icon} Icon component instance
|
|
15
15
|
*/
|
|
16
16
|
export default class Icon extends Component {
|
|
17
|
-
static
|
|
18
|
-
icon
|
|
19
|
-
|
|
17
|
+
static schema = {
|
|
18
|
+
icon: {
|
|
19
|
+
set() {
|
|
20
|
+
this._refreshIcon();
|
|
21
|
+
},
|
|
20
22
|
},
|
|
21
|
-
animation
|
|
22
|
-
|
|
23
|
+
animation: {
|
|
24
|
+
set() {
|
|
25
|
+
this._refreshIcon();
|
|
26
|
+
},
|
|
23
27
|
},
|
|
24
|
-
content
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
content: {
|
|
29
|
+
set(value, next) {
|
|
30
|
+
next(value);
|
|
31
|
+
this._refreshIcon();
|
|
32
|
+
},
|
|
27
33
|
},
|
|
28
|
-
textContent
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
textContent: {
|
|
35
|
+
set(value, next) {
|
|
36
|
+
next(value);
|
|
37
|
+
this._refreshIcon();
|
|
38
|
+
},
|
|
31
39
|
},
|
|
32
40
|
};
|
|
33
41
|
|
|
@@ -26,13 +26,11 @@ const type_enum = Object.freeze([
|
|
|
26
26
|
'url',
|
|
27
27
|
'week',
|
|
28
28
|
]);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
value: '',
|
|
29
|
+
// Only meaningful on input/textarea elements - child classes rendering other tags (e.g. ColorPicker's div) must not receive them
|
|
30
|
+
const textInputDefaults = {
|
|
32
31
|
autocomplete: 'off',
|
|
33
32
|
autocapitalize: 'off',
|
|
34
33
|
autocorrect: 'off',
|
|
35
|
-
height: 'auto',
|
|
36
34
|
placeholder: '',
|
|
37
35
|
};
|
|
38
36
|
|
|
@@ -59,19 +57,91 @@ const dataTypeToInputType = { number: 'number', boolean: 'checkbox', string: 'te
|
|
|
59
57
|
* @returns {Input} Input component instance
|
|
60
58
|
*/
|
|
61
59
|
export default class Input extends Component {
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
static schema = {
|
|
61
|
+
tag: { default: 'input' },
|
|
62
|
+
type: { enum: type_enum },
|
|
63
|
+
height: {
|
|
64
|
+
default: 'auto',
|
|
65
|
+
set(value) {
|
|
66
|
+
if (this.tag !== 'textarea') return;
|
|
67
|
+
|
|
68
|
+
if (value === 'auto') {
|
|
69
|
+
this.__updateAutoHeight = () => {
|
|
70
|
+
this.elem.style.height = this.options.syntaxHighlighting
|
|
71
|
+
? `calc(${((this.elem.value?.match(/\n/g) || '').length + 1) * 1.19}em + 10px)`
|
|
72
|
+
: `calc(${((this.elem.value?.match(/\n/g) || '').length + 1) * 1.25}em + 16px)`;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
this.__debouncedUpdateAutoHeight =
|
|
76
|
+
this.__debouncedUpdateAutoHeight ||
|
|
77
|
+
(() => {
|
|
78
|
+
clearTimeout(this.__autoHeightTimeout);
|
|
79
|
+
this.__autoHeightTimeout = setTimeout(this.__updateAutoHeight, 16);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
this.__updateAutoHeight();
|
|
83
|
+
|
|
84
|
+
this.elem.addEventListener('input', this.__debouncedUpdateAutoHeight);
|
|
85
|
+
|
|
86
|
+
this.replaceCleanup('autoHeight', () => {
|
|
87
|
+
clearTimeout(this.__autoHeightTimeout);
|
|
88
|
+
this.elem.removeEventListener?.('input', this.__debouncedUpdateAutoHeight);
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
this.elem.removeEventListener('input', this.__debouncedUpdateAutoHeight);
|
|
92
|
+
clearTimeout(this.__autoHeightTimeout);
|
|
64
93
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
94
|
+
this.elem.style.height = typeof value === 'number' ? `${value + 1}em` : value;
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
value: {
|
|
99
|
+
default: '',
|
|
100
|
+
set(value) {
|
|
101
|
+
if (this.options.type === 'checkbox') this.elem.checked = value;
|
|
102
|
+
else this.elem.value = value;
|
|
103
|
+
|
|
104
|
+
if (this.rendered && this.options.validations?.length) retry(() => this.validate(), { delay: 500, max: 1 });
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
syntaxHighlighting: {
|
|
108
|
+
set(value) {
|
|
109
|
+
this[value ? 'addClass' : 'removeClass']('syntax-highlighting');
|
|
72
110
|
},
|
|
73
|
-
|
|
74
|
-
|
|
111
|
+
},
|
|
112
|
+
language: {
|
|
113
|
+
set(value) {
|
|
114
|
+
if (!this.options.syntaxHighlighting) return;
|
|
115
|
+
this.removeClass(/\blanguage-\S+\b/g);
|
|
116
|
+
this.addClass(`language-${value}`);
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
autocorrect: {
|
|
120
|
+
set(value) {
|
|
121
|
+
this.elem.autocorrect = value;
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
// Read by validate() and the value handler
|
|
125
|
+
validations: {
|
|
126
|
+
get default() {
|
|
127
|
+
return [];
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
static prepareOptions(options) {
|
|
133
|
+
const rawValue = options.value?.__isDerived ? options.value.toJSON() : options.value;
|
|
134
|
+
const tag = options.tag || 'input';
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
...(tag === 'input' ? { type: dataTypeToInputType[typeof rawValue] || 'text' } : {}),
|
|
138
|
+
...(tag === 'input' || tag === 'textarea' ? textInputDefaults : {}),
|
|
139
|
+
...options,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
constructor(options = {}, ...children) {
|
|
144
|
+
super(options, ...children);
|
|
75
145
|
|
|
76
146
|
this.initialValue = this.options.value;
|
|
77
147
|
}
|
|
@@ -93,58 +163,6 @@ export default class Input extends Component {
|
|
|
93
163
|
}
|
|
94
164
|
}
|
|
95
165
|
|
|
96
|
-
static handlers = {
|
|
97
|
-
height(value) {
|
|
98
|
-
if (this.tag !== 'textarea') return;
|
|
99
|
-
|
|
100
|
-
if (value === 'auto') {
|
|
101
|
-
this.__updateAutoHeight = () => {
|
|
102
|
-
this.elem.style.height = this.options.syntaxHighlighting
|
|
103
|
-
? `calc(${((this.elem.value?.match(/\n/g) || '').length + 1) * 1.19}em + 10px)`
|
|
104
|
-
: `calc(${((this.elem.value?.match(/\n/g) || '').length + 1) * 1.25}em + 16px)`;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
this.__debouncedUpdateAutoHeight =
|
|
108
|
-
this.__debouncedUpdateAutoHeight ||
|
|
109
|
-
(() => {
|
|
110
|
-
clearTimeout(this.__autoHeightTimeout);
|
|
111
|
-
this.__autoHeightTimeout = setTimeout(this.__updateAutoHeight, 16);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
this.__updateAutoHeight();
|
|
115
|
-
|
|
116
|
-
this.elem.addEventListener('input', this.__debouncedUpdateAutoHeight);
|
|
117
|
-
|
|
118
|
-
this.replaceCleanup('autoHeight', () => {
|
|
119
|
-
clearTimeout(this.__autoHeightTimeout);
|
|
120
|
-
this.elem.removeEventListener?.('input', this.__debouncedUpdateAutoHeight);
|
|
121
|
-
});
|
|
122
|
-
} else {
|
|
123
|
-
this.elem.removeEventListener('input', this.__debouncedUpdateAutoHeight);
|
|
124
|
-
clearTimeout(this.__autoHeightTimeout);
|
|
125
|
-
|
|
126
|
-
this.elem.style.height = typeof value === 'number' ? `${value + 1}em` : value;
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
value(value) {
|
|
130
|
-
if (this.options.type === 'checkbox') this.elem.checked = value;
|
|
131
|
-
else this.elem.value = value;
|
|
132
|
-
|
|
133
|
-
if (this.rendered && this.options.validations?.length) retry(() => this.validate(), { delay: 500, max: 1 });
|
|
134
|
-
},
|
|
135
|
-
syntaxHighlighting(value) {
|
|
136
|
-
this[value ? 'addClass' : 'removeClass']('syntax-highlighting');
|
|
137
|
-
},
|
|
138
|
-
language(value) {
|
|
139
|
-
if (!this.options.syntaxHighlighting) return;
|
|
140
|
-
this.removeClass(/\blanguage-\S+\b/g);
|
|
141
|
-
this.addClass(`language-${value}`);
|
|
142
|
-
},
|
|
143
|
-
autocorrect(value) {
|
|
144
|
-
this.elem.autocorrect = value;
|
|
145
|
-
},
|
|
146
|
-
};
|
|
147
|
-
|
|
148
166
|
/**
|
|
149
167
|
* Checks if the input value has changed from its initial value
|
|
150
168
|
* @returns {boolean} True if value is no longer the initial value
|
|
@@ -69,8 +69,6 @@ input.isDirty: boolean // getter - true if current value differs from the initi
|
|
|
69
69
|
|
|
70
70
|
Input components emit enhanced native events. All handlers (`onInput`, `onChange`, `onKeyUp`, etc.) receive a standard DOM event augmented with a `.value` property containing the current input value.
|
|
71
71
|
|
|
72
|
-
The `close` event is registered by default via `registeredEvents`.
|
|
73
|
-
|
|
74
72
|
## Example
|
|
75
73
|
|
|
76
74
|
Textarea with auto-height and syntax highlighting:
|
|
@@ -21,17 +21,14 @@ const StyledButton = styled(
|
|
|
21
21
|
);
|
|
22
22
|
|
|
23
23
|
class Key extends StyledButton {
|
|
24
|
-
|
|
25
|
-
const { key, text, class: keyClass, ...
|
|
24
|
+
static prepareOptions(options) {
|
|
25
|
+
const { key, text, class: keyClass, ...rest } = options;
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
...children,
|
|
34
|
-
);
|
|
27
|
+
return {
|
|
28
|
+
textContent: text ?? key,
|
|
29
|
+
...rest,
|
|
30
|
+
addClass: [key, keyClass].concat(options.addClass),
|
|
31
|
+
};
|
|
35
32
|
}
|
|
36
33
|
}
|
|
37
34
|
|
|
@@ -24,54 +24,46 @@ const KeyRow = styled(
|
|
|
24
24
|
* @returns {Keyboard} Keyboard component instance
|
|
25
25
|
*/
|
|
26
26
|
class Keyboard extends Component {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
},
|
|
59
|
-
|
|
27
|
+
static schema = {
|
|
28
|
+
layout: {
|
|
29
|
+
default: 'simple',
|
|
30
|
+
set(value) {
|
|
31
|
+
this.setLayout(value);
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
// Read directly from this.options in setLayout() and key press handling
|
|
35
|
+
layouts: {
|
|
36
|
+
default: {
|
|
37
|
+
simple: [
|
|
38
|
+
['simple', 'number'],
|
|
39
|
+
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],
|
|
40
|
+
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],
|
|
41
|
+
['shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'backspace'],
|
|
42
|
+
[',', '.', 'space', '!', 'return'],
|
|
43
|
+
],
|
|
44
|
+
number: [
|
|
45
|
+
['simple', 'number'],
|
|
46
|
+
['1', '2', '3', 'backspace'],
|
|
47
|
+
['4', '5', '6', 'clear'],
|
|
48
|
+
['7', '8', '9', 'done'],
|
|
49
|
+
['.', '0', '-', 'exponent'],
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
keyDefinitions: {
|
|
54
|
+
default: {
|
|
55
|
+
simple: { text: 'ABC' },
|
|
56
|
+
number: { text: '123' },
|
|
57
|
+
shift: { class: 'u1_5' },
|
|
58
|
+
return: { class: 'u1_5' },
|
|
59
|
+
backspace: { class: 'u1_5' },
|
|
60
|
+
clear: { class: 'u1_5' },
|
|
61
|
+
done: { class: 'u1_5' },
|
|
62
|
+
exponent: { key: 'e', text: 'e', class: 'u1_5' },
|
|
63
|
+
space: { key: ' ', text: ' ', class: 'u6' },
|
|
60
64
|
},
|
|
61
|
-
...children,
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
this.setLayout(this.options.layout);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
static handlers = {
|
|
68
|
-
// Claim these keys so standard routing doesn't try to assign them as elem properties.
|
|
69
|
-
// Both are read directly from this.options in setLayout() and key resolution.
|
|
70
|
-
layouts() {},
|
|
71
|
-
keyDefinitions() {},
|
|
72
|
-
layout(value) {
|
|
73
|
-
this.setLayout(value);
|
|
74
65
|
},
|
|
66
|
+
tactileResponse: { default: true },
|
|
75
67
|
};
|
|
76
68
|
|
|
77
69
|
// todo native keyboard events https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent
|