@rettangoli/ui 0.1.2-rc15 → 0.1.2-rc16
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/dist/rettangoli-iife-layout.min.js +14 -14
- package/dist/rettangoli-iife-ui.min.js +40 -40
- package/package.json +1 -1
- package/src/components/form/form.handlers.js +37 -0
- package/src/components/form/form.store.js +8 -1
- package/src/components/form/form.view.yaml +38 -0
- package/src/components/popoverInput/popoverInput.handlers.js +99 -0
- package/src/components/popoverInput/popoverInput.store.js +48 -0
- package/src/components/popoverInput/popoverInput.view.yaml +55 -0
- package/src/components/waveform/waveform.handlers.js +86 -0
- package/src/components/waveform/waveform.store.js +16 -0
- package/src/components/waveform/waveform.view.yaml +35 -0
- package/src/primitives/input.js +4 -0
package/package.json
CHANGED
|
@@ -3,6 +3,18 @@ export const handleBeforeMount = (deps) => {
|
|
|
3
3
|
store.setFormValues(props.defaultValues);
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
+
export const handleOnUpdate = (changes, deps) => {
|
|
7
|
+
const { oldAttrs, newAttrs } = changes
|
|
8
|
+
const { store, props, render } = deps;
|
|
9
|
+
|
|
10
|
+
if (oldAttrs?.key === newAttrs?.key) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
store.setFormValues(props.defaultValues);
|
|
15
|
+
render();
|
|
16
|
+
};
|
|
17
|
+
|
|
6
18
|
const dispatchFormChange = (name, fieldValue, formValues, dispatchEvent) => {
|
|
7
19
|
dispatchEvent(
|
|
8
20
|
new CustomEvent("form-change", {
|
|
@@ -41,6 +53,19 @@ export const handleInputChange = (e, deps) => {
|
|
|
41
53
|
}
|
|
42
54
|
};
|
|
43
55
|
|
|
56
|
+
export const handlePopoverInputChange = (e, deps) => {
|
|
57
|
+
const { store, dispatchEvent } = deps;
|
|
58
|
+
const name = e.currentTarget.id.replace("popover-input-", "");
|
|
59
|
+
// TODO fix double event
|
|
60
|
+
if (name && e.detail.value !== undefined) {
|
|
61
|
+
store.setFormFieldValue({
|
|
62
|
+
name: name,
|
|
63
|
+
value: e.detail.value,
|
|
64
|
+
});
|
|
65
|
+
dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
44
69
|
export const handleSelectChange = (e, deps) => {
|
|
45
70
|
const { store, dispatchEvent } = deps;
|
|
46
71
|
const name = e.currentTarget.id.replace("select-", "");
|
|
@@ -100,3 +125,15 @@ export const handleImageClick = (e, deps) => {
|
|
|
100
125
|
}),
|
|
101
126
|
);
|
|
102
127
|
};
|
|
128
|
+
|
|
129
|
+
export const handleWaveformClick = (e, deps) => {
|
|
130
|
+
const { dispatchEvent } = deps;
|
|
131
|
+
const name = e.currentTarget.id.replace("waveform-", "");
|
|
132
|
+
dispatchEvent(
|
|
133
|
+
new CustomEvent("extra-event", {
|
|
134
|
+
detail: {
|
|
135
|
+
name: name
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
);
|
|
139
|
+
};
|
|
@@ -13,7 +13,7 @@ export const toViewData = ({ state, props, attrs }) => {
|
|
|
13
13
|
const fields = structuredClone(props.form.fields || []);
|
|
14
14
|
const defaultValues = props.defaultValues || {};
|
|
15
15
|
const fieldResources = props.fieldResources || {};
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
fields.forEach((field) => {
|
|
18
18
|
field.defaultValue = defaultValues[field.name];
|
|
19
19
|
if (field.inputType === 'image') {
|
|
@@ -23,6 +23,13 @@ export const toViewData = ({ state, props, attrs }) => {
|
|
|
23
23
|
// Set placeholder text
|
|
24
24
|
field.placeholderText = field.placeholder || 'No Image';
|
|
25
25
|
}
|
|
26
|
+
if (field.inputType === 'waveform') {
|
|
27
|
+
const waveformData = fieldResources[field.name]?.waveformData;
|
|
28
|
+
// Only set waveformData if it exists
|
|
29
|
+
field.waveformData = waveformData || null;
|
|
30
|
+
// Set placeholder text
|
|
31
|
+
field.placeholderText = field.placeholder || 'No Waveform';
|
|
32
|
+
}
|
|
26
33
|
})
|
|
27
34
|
|
|
28
35
|
return {
|
|
@@ -153,6 +153,27 @@ propsSchema:
|
|
|
153
153
|
- label
|
|
154
154
|
- inputType
|
|
155
155
|
additionalProperties: false
|
|
156
|
+
- type: object
|
|
157
|
+
properties:
|
|
158
|
+
name:
|
|
159
|
+
type: string
|
|
160
|
+
label:
|
|
161
|
+
type: string
|
|
162
|
+
description:
|
|
163
|
+
type: string
|
|
164
|
+
inputType:
|
|
165
|
+
const: waveform
|
|
166
|
+
width:
|
|
167
|
+
type: number
|
|
168
|
+
height:
|
|
169
|
+
type: number
|
|
170
|
+
placeholder:
|
|
171
|
+
type: string
|
|
172
|
+
required:
|
|
173
|
+
- name
|
|
174
|
+
- label
|
|
175
|
+
- inputType
|
|
176
|
+
additionalProperties: false
|
|
156
177
|
actions:
|
|
157
178
|
type: object
|
|
158
179
|
properties:
|
|
@@ -200,6 +221,14 @@ refs:
|
|
|
200
221
|
eventListeners:
|
|
201
222
|
click:
|
|
202
223
|
handler: handleImageClick
|
|
224
|
+
waveform-*:
|
|
225
|
+
eventListeners:
|
|
226
|
+
click:
|
|
227
|
+
handler: handleWaveformClick
|
|
228
|
+
popover-input-*:
|
|
229
|
+
eventListeners:
|
|
230
|
+
input-change:
|
|
231
|
+
handler: handlePopoverInputChange
|
|
203
232
|
|
|
204
233
|
events:
|
|
205
234
|
form-change: {}
|
|
@@ -216,8 +245,12 @@ template:
|
|
|
216
245
|
- rtgl-view g=sm:
|
|
217
246
|
- rtgl-text: ${field.label}
|
|
218
247
|
- rtgl-text s=sm c=mu-fg: ${field.description}
|
|
248
|
+
- $if field.inputType == "read-only-text":
|
|
249
|
+
- rtgl-text s=sm: ${field.defaultValue}
|
|
219
250
|
- $if field.inputType == "inputText":
|
|
220
251
|
- rtgl-input#input-${field.name} w=f placeholder=${field.placeholder} value=${field.defaultValue}:
|
|
252
|
+
- $if field.inputType == "popover-input":
|
|
253
|
+
- rtgl-popover-input#popover-input-${field.name} label="${field.label}" .defaultValue=fields[${i}].defaultValue:
|
|
221
254
|
- $if field.inputType == "select":
|
|
222
255
|
- rtgl-select#select-${field.name} w=f .options=fields[${i}].options .placeholder=fields[${i}].placeholder .selectedValue=fields[${i}].defaultValue:
|
|
223
256
|
- $if field.inputType == "colorPicker":
|
|
@@ -231,6 +264,11 @@ template:
|
|
|
231
264
|
- $if field.inputType == "image" && !field.imageSrc:
|
|
232
265
|
- rtgl-view#image-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
|
|
233
266
|
- rtgl-text c=mu-fg ta=c: ${field.placeholderText}
|
|
267
|
+
- $if field.inputType == "waveform" && field.waveformData:
|
|
268
|
+
- rtgl-waveform#waveform-${field.name} .waveformData=fields[${i}].waveformData w=${field.width} h=${field.height}:
|
|
269
|
+
- $if field.inputType == "waveform" && !field.waveformData:
|
|
270
|
+
- rtgl-view#waveform-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
|
|
271
|
+
- rtgl-text c=mu-fg ta=c: ${field.placeholderText}
|
|
234
272
|
- rtgl-view g=sm w=f:
|
|
235
273
|
- rtgl-view d=h ah=e g=sm w=f:
|
|
236
274
|
- $for button, i in actions.buttons:
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export const handleBeforeMount = (deps) => {
|
|
2
|
+
const { store, props } = deps;
|
|
3
|
+
|
|
4
|
+
if (props.value !== undefined || props.defaultValue !== undefined) {
|
|
5
|
+
store.setValue(props.value || props.defaultValue || '');
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const handleOnUpdate = (changes, deps) => {
|
|
10
|
+
const { oldProps, newProps} = changes
|
|
11
|
+
const { store, props, render } = deps;
|
|
12
|
+
|
|
13
|
+
if (oldProps.defaultValue !== newProps.defaultValue) {
|
|
14
|
+
store.setValue(props.defaultValue || '');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
render();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const handleTextClick = (e, deps) => {
|
|
21
|
+
const { store, render, getRefIds, attrs } = deps;
|
|
22
|
+
|
|
23
|
+
const value = store.selectValue();
|
|
24
|
+
store.setTempValue(value)
|
|
25
|
+
|
|
26
|
+
store.openPopover({
|
|
27
|
+
position: {
|
|
28
|
+
x: e.currentTarget.getBoundingClientRect().left,
|
|
29
|
+
y: e.currentTarget.getBoundingClientRect().bottom,
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const { input } = getRefIds();
|
|
34
|
+
input.elm.value = value;
|
|
35
|
+
render();
|
|
36
|
+
|
|
37
|
+
if (attrs['auto-focus']) {
|
|
38
|
+
setTimeout(() => {
|
|
39
|
+
input.elm.focus();
|
|
40
|
+
}, 50)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export const handlePopoverClose = (e, deps) => {
|
|
45
|
+
const { store, render } = deps;
|
|
46
|
+
store.closePopover();
|
|
47
|
+
render();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const handleInputChange = (e, deps) => {
|
|
51
|
+
const { store, render, dispatchEvent } = deps;
|
|
52
|
+
const value = e.detail.value;
|
|
53
|
+
|
|
54
|
+
store.setTempValue(value);
|
|
55
|
+
|
|
56
|
+
dispatchEvent(new CustomEvent('temp-input-change', {
|
|
57
|
+
detail: { value },
|
|
58
|
+
bubbles: true
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
render();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const handleSubmitClick = (e, deps) => {
|
|
65
|
+
const { store, render, dispatchEvent, getRefIds } = deps;
|
|
66
|
+
const { input } = getRefIds()
|
|
67
|
+
const value = input.elm.value;
|
|
68
|
+
|
|
69
|
+
store.setValue(value)
|
|
70
|
+
store.closePopover();
|
|
71
|
+
|
|
72
|
+
dispatchEvent(new CustomEvent('input-change', {
|
|
73
|
+
detail: { value },
|
|
74
|
+
bubbles: true
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
render();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const handleInputKeydown = (e, deps) => {
|
|
81
|
+
const { store, render, dispatchEvent, getRefIds } = deps;
|
|
82
|
+
|
|
83
|
+
if (e.key === 'Enter') {
|
|
84
|
+
const { input } = getRefIds()
|
|
85
|
+
const value = input.elm.value;
|
|
86
|
+
|
|
87
|
+
store.closePopover();
|
|
88
|
+
// Dispatch custom event
|
|
89
|
+
dispatchEvent(new CustomEvent('input-change', {
|
|
90
|
+
detail: { value },
|
|
91
|
+
bubbles: true
|
|
92
|
+
}));
|
|
93
|
+
|
|
94
|
+
render();
|
|
95
|
+
} else if (e.key === 'Escape') {
|
|
96
|
+
store.closePopover();
|
|
97
|
+
render();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const INITIAL_STATE = Object.freeze({
|
|
2
|
+
isOpen: false,
|
|
3
|
+
position: {
|
|
4
|
+
x: 0,
|
|
5
|
+
y: 0,
|
|
6
|
+
},
|
|
7
|
+
value: '',
|
|
8
|
+
tempValue: '',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export const toViewData = ({ attrs, state, props }) => {
|
|
12
|
+
// Use state's current value if it has been modified, otherwise use props
|
|
13
|
+
const value = state.value || '-';
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
isOpen: state.isOpen,
|
|
17
|
+
position: state.position,
|
|
18
|
+
value: value ?? '-',
|
|
19
|
+
tempValue: state.tempValue,
|
|
20
|
+
placeholder: props.placeholder ?? '',
|
|
21
|
+
label: attrs.label,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const setTempValue = (state, value) => {
|
|
26
|
+
state.tempValue = value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const openPopover = (state, payload) => {
|
|
30
|
+
const { position } = payload;
|
|
31
|
+
state.position = position;
|
|
32
|
+
state.isOpen = true;
|
|
33
|
+
// Reset the current value to match the display value when opening
|
|
34
|
+
state.hasUnsavedChanges = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const closePopover = (state) => {
|
|
38
|
+
state.isOpen = false;
|
|
39
|
+
state.tempValue = '';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const setValue = (state, value) => {
|
|
43
|
+
state.value = value;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const selectValue = ({ state }) => {
|
|
47
|
+
return state.value;
|
|
48
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
elementName: rtgl-popover-input
|
|
2
|
+
|
|
3
|
+
viewDataSchema:
|
|
4
|
+
type: object
|
|
5
|
+
|
|
6
|
+
attrsSchema:
|
|
7
|
+
type: object
|
|
8
|
+
properties:
|
|
9
|
+
auto-focus:
|
|
10
|
+
type: boolean
|
|
11
|
+
|
|
12
|
+
propsSchema:
|
|
13
|
+
type: object
|
|
14
|
+
properties:
|
|
15
|
+
value:
|
|
16
|
+
type: string
|
|
17
|
+
defaultValue:
|
|
18
|
+
type: string
|
|
19
|
+
placeholder:
|
|
20
|
+
type: string
|
|
21
|
+
onChange:
|
|
22
|
+
type: function
|
|
23
|
+
|
|
24
|
+
refs:
|
|
25
|
+
text-display:
|
|
26
|
+
eventListeners:
|
|
27
|
+
click:
|
|
28
|
+
handler: handleTextClick
|
|
29
|
+
popover:
|
|
30
|
+
eventListeners:
|
|
31
|
+
close:
|
|
32
|
+
handler: handlePopoverClose
|
|
33
|
+
input:
|
|
34
|
+
eventListeners:
|
|
35
|
+
input-change:
|
|
36
|
+
handler: handleInputChange
|
|
37
|
+
keydown:
|
|
38
|
+
handler: handleInputKeydown
|
|
39
|
+
submit:
|
|
40
|
+
eventListeners:
|
|
41
|
+
click:
|
|
42
|
+
handler: handleSubmitClick
|
|
43
|
+
|
|
44
|
+
events:
|
|
45
|
+
input-change: {}
|
|
46
|
+
|
|
47
|
+
template:
|
|
48
|
+
- rtgl-view#text-display w=f cur=p:
|
|
49
|
+
- rtgl-text: ${value}
|
|
50
|
+
- rtgl-popover#popover ?open=${isOpen} x=${position.x} y=${position.y}:
|
|
51
|
+
- rtgl-view g=md w=240 slot=content bgc=background br=md:
|
|
52
|
+
- rtgl-text: ${label}
|
|
53
|
+
- rtgl-input#input w=f placeholder=${placeholder}:
|
|
54
|
+
- rtgl-view w=f ah=e:
|
|
55
|
+
- rtgl-button#submit: Submit
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const handleAfterMount = async (deps) => {
|
|
2
|
+
const { props, store, render, getRefIds, } = deps;
|
|
3
|
+
const { waveformData } = props;
|
|
4
|
+
|
|
5
|
+
store.setWaveformData(waveformData);
|
|
6
|
+
render();
|
|
7
|
+
|
|
8
|
+
const canvas = getRefIds().canvas?.elm;
|
|
9
|
+
if (canvas) {
|
|
10
|
+
renderWaveform(waveformData, canvas);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const handleOnUpdate = async (changes, deps) => {
|
|
15
|
+
const { store, render, getRefIds, props } = deps;
|
|
16
|
+
const { waveformData } = props;
|
|
17
|
+
store.setWaveformData(waveformData);
|
|
18
|
+
render();
|
|
19
|
+
|
|
20
|
+
const canvas = getRefIds().canvas?.elm;
|
|
21
|
+
if (canvas) {
|
|
22
|
+
renderWaveform(waveformData, canvas);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
async function renderWaveform(waveformData, canvas) {
|
|
27
|
+
const ctx = canvas.getContext("2d");
|
|
28
|
+
|
|
29
|
+
// Get the actual display size of the canvas
|
|
30
|
+
const rect = canvas.getBoundingClientRect();
|
|
31
|
+
const displayWidth = rect.width;
|
|
32
|
+
const displayHeight = rect.height;
|
|
33
|
+
|
|
34
|
+
// Set canvas internal resolution to match display size
|
|
35
|
+
canvas.width = displayWidth;
|
|
36
|
+
canvas.height = displayHeight;
|
|
37
|
+
|
|
38
|
+
const width = canvas.width;
|
|
39
|
+
const height = canvas.height;
|
|
40
|
+
|
|
41
|
+
// Clear canvas
|
|
42
|
+
ctx.clearRect(0, 0, width, height);
|
|
43
|
+
|
|
44
|
+
// Dark theme background
|
|
45
|
+
ctx.fillStyle = "#1a1a1a";
|
|
46
|
+
ctx.fillRect(0, 0, width, height);
|
|
47
|
+
|
|
48
|
+
if (!waveformData || !waveformData.data) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const data = waveformData.data;
|
|
53
|
+
const centerY = height / 2;
|
|
54
|
+
|
|
55
|
+
// Create gradient for waveform
|
|
56
|
+
const gradient = ctx.createLinearGradient(0, 0, 0, height);
|
|
57
|
+
gradient.addColorStop(0, "#404040");
|
|
58
|
+
gradient.addColorStop(0.5, "#A1A1A1");
|
|
59
|
+
gradient.addColorStop(1, "#404040");
|
|
60
|
+
|
|
61
|
+
// Draw waveform bars
|
|
62
|
+
const barWidth = Math.max(1, width / data.length);
|
|
63
|
+
const barSpacing = 0.2; // 20% spacing between bars
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < data.length; i++) {
|
|
66
|
+
const amplitude = data[i];
|
|
67
|
+
const barHeight = amplitude * (height * 0.85);
|
|
68
|
+
const x = i * barWidth;
|
|
69
|
+
const y = centerY - barHeight / 2;
|
|
70
|
+
|
|
71
|
+
ctx.fillStyle = gradient;
|
|
72
|
+
ctx.fillRect(x, y, Math.max(1, barWidth * (1 - barSpacing)), barHeight);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Draw subtle center line
|
|
76
|
+
ctx.strokeStyle = "rgba(255, 255, 255, 0.1)";
|
|
77
|
+
ctx.lineWidth = 1;
|
|
78
|
+
ctx.beginPath();
|
|
79
|
+
ctx.moveTo(0, centerY);
|
|
80
|
+
ctx.lineTo(width, centerY);
|
|
81
|
+
ctx.stroke();
|
|
82
|
+
|
|
83
|
+
// Add subtle glow effect
|
|
84
|
+
ctx.shadowBlur = 10;
|
|
85
|
+
ctx.shadowColor = "#2196F3";
|
|
86
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const INITIAL_STATE = Object.freeze({
|
|
2
|
+
waveformData: null,
|
|
3
|
+
});
|
|
4
|
+
|
|
5
|
+
export const setWaveformData = (state, data) => {
|
|
6
|
+
state.waveformData = data;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const toViewData = ({ state, attrs, props }) => {
|
|
10
|
+
return {
|
|
11
|
+
isLoading: props.isLoading,
|
|
12
|
+
w: attrs.w || "250",
|
|
13
|
+
h: attrs.h || "150",
|
|
14
|
+
waveformData: props.waveformData,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
elementName: rtgl-waveform
|
|
2
|
+
|
|
3
|
+
attrsSchema:
|
|
4
|
+
type: object
|
|
5
|
+
properties:
|
|
6
|
+
w:
|
|
7
|
+
type: string
|
|
8
|
+
description: Width of the waveform visualizer
|
|
9
|
+
default: '250'
|
|
10
|
+
h:
|
|
11
|
+
type: string
|
|
12
|
+
description: Height of the waveform visualizer
|
|
13
|
+
default: '150'
|
|
14
|
+
|
|
15
|
+
propsSchema:
|
|
16
|
+
type: object
|
|
17
|
+
properties:
|
|
18
|
+
waveformData:
|
|
19
|
+
type: object
|
|
20
|
+
description: File ID of the waveform data in object storage
|
|
21
|
+
isLoading:
|
|
22
|
+
type: boolean
|
|
23
|
+
description: Whether the waveform data is currently being loaded
|
|
24
|
+
|
|
25
|
+
refs:
|
|
26
|
+
canvas:
|
|
27
|
+
selector: canvas
|
|
28
|
+
|
|
29
|
+
template:
|
|
30
|
+
- rtgl-view w=f h=f pos=rel w=${w} h=${h}:
|
|
31
|
+
- $if isLoading:
|
|
32
|
+
- rtgl-view w=f h=f av=c ah=c:
|
|
33
|
+
- rtgl-text c=mu-fg: ...
|
|
34
|
+
$else:
|
|
35
|
+
- 'canvas#canvas style="width:100%; height:100%;"':
|
package/src/primitives/input.js
CHANGED
|
@@ -110,6 +110,10 @@ class RettangoliInputElement extends HTMLElement {
|
|
|
110
110
|
this._inputElement.value = newValue;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
focus() {
|
|
114
|
+
this._inputElement.focus();
|
|
115
|
+
}
|
|
116
|
+
|
|
113
117
|
_onChange = (event) => {
|
|
114
118
|
this.dispatchEvent(new CustomEvent('input-change', {
|
|
115
119
|
detail: {
|