@shortfuse/materialdesignweb 0.7.2 → 0.7.5
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/components/Button.js +1 -2
- package/components/Checkbox.js +0 -1
- package/components/FilterChip.js +0 -1
- package/components/ListSelect.js +1 -1
- package/components/Radio.js +0 -2
- package/components/SegmentedButton.js +0 -1
- package/components/Select.js +12 -24
- package/components/Slider.js +1 -2
- package/components/Switch.js +0 -1
- package/components/TextArea.js +206 -219
- package/core/CustomElement.js +23 -5
- package/core/ICustomElement.d.ts +8 -5
- package/core/observe.js +17 -19
- package/core/typings.d.ts +2 -1
- package/dist/index.min.js +72 -69
- package/dist/index.min.js.map +4 -4
- package/dist/meta.json +1 -1
- package/mixins/ControlMixin.js +193 -247
- package/mixins/FormAssociatedMixin.js +166 -30
- package/mixins/InputMixin.js +211 -290
- package/mixins/TextFieldMixin.js +18 -13
- package/package.json +8 -5
package/components/Button.js
CHANGED
|
@@ -25,7 +25,7 @@ export default CustomElement
|
|
|
25
25
|
delegatesFocus: true,
|
|
26
26
|
})
|
|
27
27
|
.observe({
|
|
28
|
-
type: {
|
|
28
|
+
type: { empty: 'button' },
|
|
29
29
|
elevated: 'boolean',
|
|
30
30
|
filled: 'string',
|
|
31
31
|
outlined: 'boolean',
|
|
@@ -57,7 +57,6 @@ export default CustomElement
|
|
|
57
57
|
|
|
58
58
|
shape.setAttribute('filled', '{filled}');
|
|
59
59
|
control.setAttribute('role', 'button');
|
|
60
|
-
control.setAttribute('type', 'button');
|
|
61
60
|
},
|
|
62
61
|
})
|
|
63
62
|
.css`
|
package/components/Checkbox.js
CHANGED
package/components/FilterChip.js
CHANGED
package/components/ListSelect.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { constructHTMLOptionsCollectionProxy } from '../dom/
|
|
1
|
+
import { constructHTMLOptionsCollectionProxy } from '../dom/HTMLOptionsCollectionProxy.js';
|
|
2
2
|
import FormAssociatedMixin from '../mixins/FormAssociatedMixin.js';
|
|
3
3
|
import KeyboardNavMixin from '../mixins/KeyboardNavMixin.js';
|
|
4
4
|
import StateMixin from '../mixins/StateMixin.js';
|
package/components/Radio.js
CHANGED
|
@@ -29,7 +29,6 @@ export default Button
|
|
|
29
29
|
outline.setAttribute('inner-segmented-button', '{innerSegmentedButton}');
|
|
30
30
|
outline.setAttribute('shape-start', '{shapeStart}');
|
|
31
31
|
outline.setAttribute('shape-end', '{shapeEnd}');
|
|
32
|
-
control.setAttribute('type', 'radio');
|
|
33
32
|
control.setAttribute('role', 'option');
|
|
34
33
|
control.setAttribute('aria-checked', inline(
|
|
35
34
|
({ type, checked }) => (type === 'checkbox' ? `${(!!checked)}` : null),
|
package/components/Select.js
CHANGED
|
@@ -4,20 +4,20 @@ import StateMixin from '../mixins/StateMixin.js';
|
|
|
4
4
|
import TextFieldMixin from '../mixins/TextFieldMixin.js';
|
|
5
5
|
import ThemableMixin from '../mixins/ThemableMixin.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
/* @implements {HTMLSelectElement} */
|
|
9
|
-
|
|
10
|
-
export default class Select extends CustomElement
|
|
8
|
+
export default CustomElement
|
|
11
9
|
.mixin(ThemableMixin)
|
|
12
10
|
.mixin(StateMixin)
|
|
13
11
|
.mixin(ControlMixin)
|
|
14
12
|
.mixin(TextFieldMixin)
|
|
15
13
|
.extend()
|
|
16
14
|
.observe({
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
trailingIcon: { empty: 'arrow_drop_down' },
|
|
16
|
+
})
|
|
17
|
+
.overrides({
|
|
18
|
+
controlTagName: 'select',
|
|
19
|
+
controlVoidElement: false,
|
|
20
|
+
type: 'select-one',
|
|
21
21
|
})
|
|
22
22
|
.define({
|
|
23
23
|
_select() {
|
|
@@ -26,7 +26,6 @@ export default class Select extends CustomElement
|
|
|
26
26
|
/** Readonly values */
|
|
27
27
|
multiple: { value: false },
|
|
28
28
|
size: { value: 1 },
|
|
29
|
-
type: { value: 'select-one' },
|
|
30
29
|
})
|
|
31
30
|
.html/* html */`<slot id=slot></slot>`
|
|
32
31
|
.childEvents({
|
|
@@ -50,6 +49,10 @@ export default class Select extends CustomElement
|
|
|
50
49
|
prefix.remove();
|
|
51
50
|
suffix.remove();
|
|
52
51
|
},
|
|
52
|
+
_formResetChanged(oldValue, newValue) {
|
|
53
|
+
if (!newValue) return;
|
|
54
|
+
this._select.value = this.querySelector('option[selected]')?.value ?? '';
|
|
55
|
+
},
|
|
53
56
|
})
|
|
54
57
|
.css`
|
|
55
58
|
#slot {
|
|
@@ -105,19 +108,4 @@ export default class Select extends CustomElement
|
|
|
105
108
|
letter-spacing: var(--mdw-typescale__label-large__letter-spacing);
|
|
106
109
|
}
|
|
107
110
|
`
|
|
108
|
-
.
|
|
109
|
-
controlTagName: 'select',
|
|
110
|
-
controlVoidElement: false,
|
|
111
|
-
})
|
|
112
|
-
.autoRegister('mdw-select') {
|
|
113
|
-
/* Overrides */
|
|
114
|
-
static clonedContentAttributes = [
|
|
115
|
-
...super.clonedContentAttributes,
|
|
116
|
-
'autocomplete', // Hint for form autofill feature
|
|
117
|
-
];
|
|
118
|
-
|
|
119
|
-
formResetCallback() {
|
|
120
|
-
this._select.value = this.querySelector('option[selected]')?.value ?? '';
|
|
121
|
-
super.formResetCallback();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
111
|
+
.autoRegister('mdw-select');
|
package/components/Slider.js
CHANGED
|
@@ -194,7 +194,6 @@ export default CustomElement
|
|
|
194
194
|
</div>
|
|
195
195
|
`);
|
|
196
196
|
label.removeAttribute('aria-labelledby');
|
|
197
|
-
control.setAttribute('type', 'range');
|
|
198
197
|
},
|
|
199
198
|
valueChanged(oldValue, newValue) {
|
|
200
199
|
this._previewValue = newValue;
|
|
@@ -207,7 +206,7 @@ export default CustomElement
|
|
|
207
206
|
--mdw-ink: var(--mdw-color__on-primary);
|
|
208
207
|
--mdw-bg: var(--mdw-color__primary);
|
|
209
208
|
|
|
210
|
-
display:
|
|
209
|
+
display: block;
|
|
211
210
|
vertical-align: middle;
|
|
212
211
|
|
|
213
212
|
min-block-size: 40px;
|
package/components/Switch.js
CHANGED
package/components/TextArea.js
CHANGED
|
@@ -1,22 +1,218 @@
|
|
|
1
|
-
import CustomElement from '../core/CustomElement.js';
|
|
1
|
+
import CustomElement, { cloneAttributeCallback } from '../core/CustomElement.js';
|
|
2
2
|
import ControlMixin from '../mixins/ControlMixin.js';
|
|
3
3
|
import ResizeObserverMixin from '../mixins/ResizeObserverMixin.js';
|
|
4
4
|
import StateMixin from '../mixins/StateMixin.js';
|
|
5
5
|
import TextFieldMixin from '../mixins/TextFieldMixin.js';
|
|
6
6
|
import ThemableMixin from '../mixins/ThemableMixin.js';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const DOMString = { nullParser: String, value: '' };
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @see https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element
|
|
12
|
+
* -implements {HTMLTextAreaElement}
|
|
13
|
+
*/
|
|
14
|
+
export default CustomElement
|
|
10
15
|
.mixin(ThemableMixin)
|
|
11
16
|
.mixin(StateMixin)
|
|
12
17
|
.mixin(ControlMixin)
|
|
13
18
|
.mixin(TextFieldMixin)
|
|
14
|
-
.mixin(ResizeObserverMixin)
|
|
15
|
-
|
|
19
|
+
.mixin(ResizeObserverMixin)
|
|
20
|
+
.extend()
|
|
21
|
+
.set({
|
|
22
|
+
supportsCSSLineHeightUnit: CSS.supports('height', '1lh'),
|
|
23
|
+
type: 'textarea',
|
|
24
|
+
})
|
|
25
|
+
.overrides({
|
|
26
|
+
controlTagName: 'textarea',
|
|
27
|
+
controlVoidElement: false,
|
|
28
|
+
})
|
|
29
|
+
.observe({
|
|
30
|
+
fixed: { type: 'boolean' },
|
|
31
|
+
minRows: { attr: 'minrows', type: 'integer', nullable: false },
|
|
32
|
+
maxRows: { attr: 'maxrows', type: 'integer', nullable: false },
|
|
33
|
+
_lineHeight: 'string',
|
|
34
|
+
cols: { type: 'integer', empty: 0 },
|
|
35
|
+
dirName: { attr: 'dirname', ...DOMString },
|
|
36
|
+
maxLength: { attr: 'maxlength', type: 'integer', empty: 0 },
|
|
37
|
+
minLength: { attr: 'minlength', type: 'integer', empty: 0 },
|
|
38
|
+
placeholder: DOMString,
|
|
39
|
+
rows: { type: 'integer', empty: 1 },
|
|
40
|
+
wrap: DOMString,
|
|
41
|
+
// Not in spec, but plays nice with HTML linters
|
|
42
|
+
defaultValueAttr: { attr: 'value', ...DOMString },
|
|
43
|
+
})
|
|
44
|
+
.define({
|
|
45
|
+
_textarea() { return /** @type {HTMLTextAreaElement} */ (this.refs.control); },
|
|
46
|
+
})
|
|
47
|
+
.define({
|
|
48
|
+
defaultValue: {
|
|
49
|
+
get() { return this._textarea.defaultValue; },
|
|
50
|
+
set(value) {
|
|
51
|
+
const previousValue = this._textarea.defaultValue;
|
|
52
|
+
this._textarea.defaultValue = value;
|
|
53
|
+
const newValue = this._textarea.defaultValue;
|
|
54
|
+
if (previousValue !== newValue) {
|
|
55
|
+
this.propChangedCallback('defaultValue', previousValue, newValue);
|
|
56
|
+
}
|
|
57
|
+
this.textContent = this._textarea.defaultValue;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
textLength() { return this._textarea.textLength; },
|
|
61
|
+
select() { return this._textarea.select; },
|
|
62
|
+
|
|
63
|
+
selectionDirection: {
|
|
64
|
+
get() { return this._textarea.selectionDirection; },
|
|
65
|
+
set(value) { this._textarea.selectionDirection = value; },
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
selectionStart: {
|
|
69
|
+
get() { return this._textarea.selectionStart; },
|
|
70
|
+
set(value) { this._textarea.selectionStart = value; },
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
selectionEnd: {
|
|
74
|
+
get() { return this._textarea.selectionEnd; },
|
|
75
|
+
set(value) { this._textarea.selectionEnd = value; },
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
setRangeText() { return this._textarea.setRangeText; },
|
|
79
|
+
|
|
80
|
+
setSelectionRange() { return this._textarea.setSelectionRange; },
|
|
81
|
+
|
|
82
|
+
})
|
|
83
|
+
.methods({
|
|
84
|
+
|
|
85
|
+
/** @return {number} */
|
|
86
|
+
resize() {
|
|
87
|
+
const textarea = this._textarea;
|
|
88
|
+
textarea.style.removeProperty('height');
|
|
16
89
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
90
|
+
// if (this.placeholder) textarea.removeAttribute('placeholder');
|
|
91
|
+
|
|
92
|
+
if (!this.supportsCSSLineHeightUnit) {
|
|
93
|
+
const { lineHeight } = window.getComputedStyle(textarea);
|
|
94
|
+
this._lineHeight = lineHeight;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (this.minRows > 1 && textarea.rows < this.minRows) {
|
|
98
|
+
textarea.rows = this.minRows;
|
|
99
|
+
} else if (this.maxRows && textarea.rows > this.maxRows) {
|
|
100
|
+
textarea.rows = this.maxRows;
|
|
101
|
+
}
|
|
102
|
+
if (!this.fixed) {
|
|
103
|
+
while (textarea.scrollHeight > textarea.clientHeight) {
|
|
104
|
+
if (this.maxRows && textarea.rows === this.maxRows) break;
|
|
105
|
+
const lastClientHeight = textarea.clientHeight;
|
|
106
|
+
textarea.rows++;
|
|
107
|
+
if (lastClientHeight === textarea.clientHeight) {
|
|
108
|
+
textarea.rows--;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
while (textarea.scrollHeight === textarea.clientHeight) {
|
|
113
|
+
if (textarea.rows === 1) break;
|
|
114
|
+
if (this.minRows > 1 && textarea.rows === this.minRows) break;
|
|
115
|
+
const lastClientHeight = textarea.clientHeight;
|
|
116
|
+
textarea.rows--;
|
|
117
|
+
if ((lastClientHeight === textarea.clientHeight)
|
|
118
|
+
|| (textarea.scrollHeight > textarea.clientHeight)) {
|
|
119
|
+
textarea.rows++;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (textarea.selectionEnd === textarea.value.length) {
|
|
126
|
+
textarea.scrollTop = textarea.scrollHeight;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this.rows = textarea.rows;
|
|
130
|
+
// if (this.placeholder) textarea.setAttribute('placeholder', this.placeholder);
|
|
131
|
+
return this.rows;
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
/** @param {ResizeObserverEntry} entry */
|
|
135
|
+
onResizeObserved(entry) {
|
|
136
|
+
super.onResizeObserved(entry);
|
|
137
|
+
if (this.matches(':active')) return;
|
|
138
|
+
this.resize();
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
.childEvents({
|
|
142
|
+
slot: {
|
|
143
|
+
/**
|
|
144
|
+
* @param {Event & {currentTarget:HTMLSlotElement}} event
|
|
145
|
+
* @return {void}
|
|
146
|
+
*/
|
|
147
|
+
slotchange({ currentTarget }) {
|
|
148
|
+
const textarea = /** @type {HTMLTextAreaElement} */ (this.refs.control);
|
|
149
|
+
const previousValue = textarea.defaultValue;
|
|
150
|
+
textarea.replaceChildren(
|
|
151
|
+
...currentTarget.assignedNodes().map((child) => child.cloneNode(true)),
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const newValue = textarea.defaultValue;
|
|
155
|
+
if (previousValue !== newValue) {
|
|
156
|
+
this.propChangedCallback('defaultValue', previousValue, newValue);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
control: {
|
|
161
|
+
input() {
|
|
162
|
+
this.resize();
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
})
|
|
166
|
+
.on({
|
|
167
|
+
composed() {
|
|
168
|
+
const { control } = this.refs;
|
|
169
|
+
// Spec
|
|
170
|
+
control.removeAttribute('placeholder');
|
|
171
|
+
control.setAttribute('rows', '{rows}');
|
|
172
|
+
|
|
173
|
+
// Custom
|
|
174
|
+
control.setAttribute('input-prefix', '{inputPrefix}');
|
|
175
|
+
control.setAttribute('input-suffix', '{inputSuffix}');
|
|
176
|
+
control.setAttribute('minrows', '{minRows}');
|
|
177
|
+
control.setAttribute('fixed', '{fixed}');
|
|
178
|
+
control.setAttribute('icon', '{icon}');
|
|
179
|
+
control.setAttribute('maxrows', '{maxRows}');
|
|
180
|
+
},
|
|
181
|
+
defaultValueAttrChanged(oldValue, newValue) {
|
|
182
|
+
this.defaultValue = newValue;
|
|
183
|
+
},
|
|
184
|
+
defaultValueChanged() {
|
|
185
|
+
this._value = this._textarea.value;
|
|
186
|
+
this.resize();
|
|
187
|
+
},
|
|
188
|
+
_lineHeightChanged(oldValue, newValue) {
|
|
189
|
+
this.refs.label.style.setProperty('--line-height', newValue);
|
|
190
|
+
},
|
|
191
|
+
minRowsChanged(oldValue, newValue) {
|
|
192
|
+
this.refs.label.style.setProperty('--min-rows', `${newValue || 'none'}`);
|
|
193
|
+
this.resize();
|
|
194
|
+
},
|
|
195
|
+
maxRowsChanged(oldValue, newValue) {
|
|
196
|
+
this.refs.label.style.setProperty('--max-rows', `${newValue || 'none'}`);
|
|
197
|
+
this.resize();
|
|
198
|
+
},
|
|
199
|
+
rowsChanged() {
|
|
200
|
+
this.resize();
|
|
201
|
+
},
|
|
202
|
+
_formResetChanged(oldValue, newValue) {
|
|
203
|
+
if (!newValue) return;
|
|
204
|
+
this._textarea.value = this.defaultValue;
|
|
205
|
+
this._value = this._textarea.value;
|
|
206
|
+
},
|
|
207
|
+
attrs: {
|
|
208
|
+
cols: cloneAttributeCallback('cols', 'control'),
|
|
209
|
+
dirname: cloneAttributeCallback('dirname', 'control'),
|
|
210
|
+
minlength: cloneAttributeCallback('minlength', 'control'),
|
|
211
|
+
maxlength: cloneAttributeCallback('maxlength', 'control'),
|
|
212
|
+
placeholder: cloneAttributeCallback('placeholder', 'control'),
|
|
213
|
+
},
|
|
214
|
+
})
|
|
215
|
+
.css`
|
|
20
216
|
/* https://m3.material.io/components/text-fields/specs */
|
|
21
217
|
|
|
22
218
|
:host {
|
|
@@ -110,214 +306,5 @@ export default class TextArea extends CustomElement
|
|
|
110
306
|
/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
|
|
111
307
|
resize: none;
|
|
112
308
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.childEvents({ slot: { slotchange: 'onSlotChange' } });
|
|
116
|
-
this.on({
|
|
117
|
-
composed() {
|
|
118
|
-
const { control } = this.refs;
|
|
119
|
-
control.setAttribute('input-prefix', '{input-prefix}');
|
|
120
|
-
control.setAttribute('input-suffix', '{input-suffix}');
|
|
121
|
-
control.setAttribute('minrows', '{minrows}');
|
|
122
|
-
control.setAttribute('fixed', '{fixed}');
|
|
123
|
-
control.setAttribute('icon', '{icon}');
|
|
124
|
-
control.setAttribute('maxrows', '{maxrows}');
|
|
125
|
-
},
|
|
126
|
-
defaultValueAttrChanged(oldValue, newValue) {
|
|
127
|
-
this.defaultValue = newValue;
|
|
128
|
-
},
|
|
129
|
-
defaultValueChanged() {
|
|
130
|
-
this._value = this.#textarea.value;
|
|
131
|
-
this.resize();
|
|
132
|
-
},
|
|
133
|
-
_maxHeightChanged(oldValue, newValue) {
|
|
134
|
-
this.#textarea.style.setProperty('max-height', newValue);
|
|
135
|
-
},
|
|
136
|
-
_lineHeightChanged(oldValue, newValue) {
|
|
137
|
-
this.refs.label.style.setProperty('--line-height', newValue);
|
|
138
|
-
},
|
|
139
|
-
minRowsChanged(oldValue, newValue) {
|
|
140
|
-
this.refs.label.style.setProperty('--min-rows', `${newValue || 'none'}`);
|
|
141
|
-
this.resize();
|
|
142
|
-
},
|
|
143
|
-
maxRowsChanged(oldValue, newValue) {
|
|
144
|
-
this.refs.label.style.setProperty('--max-rows', `${newValue || 'none'}`);
|
|
145
|
-
this.resize();
|
|
146
|
-
},
|
|
147
|
-
rowsChanged() {
|
|
148
|
-
this.resize();
|
|
149
|
-
},
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
static supportsCSSLineHeightUnit = CSS.supports('height', '1lh');
|
|
154
|
-
|
|
155
|
-
static controlTagName = 'textarea';
|
|
156
|
-
|
|
157
|
-
static controlVoidElement = false;
|
|
158
|
-
|
|
159
|
-
static clonedContentAttributes = [
|
|
160
|
-
...super.clonedContentAttributes,
|
|
161
|
-
'cols',
|
|
162
|
-
'dirname',
|
|
163
|
-
'maxlength',
|
|
164
|
-
'minlength',
|
|
165
|
-
'placeholder',
|
|
166
|
-
'rows',
|
|
167
|
-
];
|
|
168
|
-
|
|
169
|
-
#updatingSlot = false;
|
|
170
|
-
|
|
171
|
-
#textarea = /** @type {HTMLTextAreaElement} */ (this.refs.control);
|
|
172
|
-
|
|
173
|
-
static {
|
|
174
|
-
if (TextArea.supportsCSSLineHeightUnit) {
|
|
175
|
-
this.childEvents({
|
|
176
|
-
control: {
|
|
177
|
-
input() {
|
|
178
|
-
this.resize();
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* @param {Event & {currentTarget:HTMLSlotElement}} event
|
|
187
|
-
* @return {void}
|
|
188
|
-
*/
|
|
189
|
-
onSlotChange({ currentTarget }) {
|
|
190
|
-
const textarea = /** @type {HTMLTextAreaElement} */ (this.refs.control);
|
|
191
|
-
const previousValue = textarea.defaultValue;
|
|
192
|
-
textarea.replaceChildren(
|
|
193
|
-
...currentTarget.assignedNodes().map((child) => child.cloneNode(true)),
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
const newValue = textarea.defaultValue;
|
|
197
|
-
if (previousValue !== newValue) {
|
|
198
|
-
this.propChangedCallback('defaultValue', previousValue, newValue);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** @return {number} */
|
|
203
|
-
resize() {
|
|
204
|
-
const textarea = this.#textarea;
|
|
205
|
-
textarea.style.removeProperty('height');
|
|
206
|
-
|
|
207
|
-
// if (this.placeholder) textarea.removeAttribute('placeholder');
|
|
208
|
-
|
|
209
|
-
if (!TextArea.supportsCSSLineHeightUnit) {
|
|
210
|
-
const { lineHeight } = window.getComputedStyle(textarea);
|
|
211
|
-
this._lineHeight = lineHeight;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (this.minRows > 1 && textarea.rows < this.minRows) {
|
|
215
|
-
textarea.rows = this.minRows;
|
|
216
|
-
} else if (this.maxRows && textarea.rows > this.maxRows) {
|
|
217
|
-
textarea.rows = this.maxRows;
|
|
218
|
-
}
|
|
219
|
-
if (!this.fixed) {
|
|
220
|
-
while (textarea.scrollHeight > textarea.clientHeight) {
|
|
221
|
-
if (this.maxRows && textarea.rows === this.maxRows) break;
|
|
222
|
-
const lastClientHeight = textarea.clientHeight;
|
|
223
|
-
textarea.rows++;
|
|
224
|
-
if (lastClientHeight === textarea.clientHeight) {
|
|
225
|
-
textarea.rows--;
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
while (textarea.scrollHeight === textarea.clientHeight) {
|
|
230
|
-
if (textarea.rows === 1) break;
|
|
231
|
-
if (this.minRows > 1 && textarea.rows === this.minRows) break;
|
|
232
|
-
const lastClientHeight = textarea.clientHeight;
|
|
233
|
-
textarea.rows--;
|
|
234
|
-
if ((lastClientHeight === textarea.clientHeight)
|
|
235
|
-
|| (textarea.scrollHeight > textarea.clientHeight)) {
|
|
236
|
-
textarea.rows++;
|
|
237
|
-
break;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (textarea.selectionEnd === textarea.value.length) {
|
|
243
|
-
textarea.scrollTop = textarea.scrollHeight;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
this.rows = textarea.rows;
|
|
247
|
-
// if (this.placeholder) textarea.setAttribute('placeholder', this.placeholder);
|
|
248
|
-
return this.rows;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
formResetCallback() {
|
|
252
|
-
this.#textarea.value = this.defaultValue;
|
|
253
|
-
this._value = this.#textarea.value;
|
|
254
|
-
super.formResetCallback();
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
get updatingSlot() { return this.#updatingSlot; }
|
|
258
|
-
|
|
259
|
-
get defaultValue() {
|
|
260
|
-
return this.#textarea.defaultValue;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
set defaultValue(value) {
|
|
264
|
-
const previousValue = this.#textarea.defaultValue;
|
|
265
|
-
this.#textarea.defaultValue = value;
|
|
266
|
-
if (previousValue !== this.#textarea.defaultValue) {
|
|
267
|
-
this.propChangedCallback('defaultValue', previousValue, this.defaultValue);
|
|
268
|
-
}
|
|
269
|
-
this.textContent = this.#textarea.defaultValue;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// @ts-ignore @override
|
|
273
|
-
|
|
274
|
-
get type() { return 'textarea'; }
|
|
275
|
-
|
|
276
|
-
get textLength() { return this.#textarea.textLength; }
|
|
277
|
-
|
|
278
|
-
get select() { return this.#textarea.select; }
|
|
279
|
-
|
|
280
|
-
get selectionDirection() { return this.#textarea.selectionDirection; }
|
|
281
|
-
|
|
282
|
-
set selectionDirection(value) { this.#textarea.selectionDirection = value; }
|
|
283
|
-
|
|
284
|
-
get selectionStart() { return this.#textarea.selectionStart; }
|
|
285
|
-
|
|
286
|
-
set selectionStart(value) { this.#textarea.selectionStart = value; }
|
|
287
|
-
|
|
288
|
-
get selectionEnd() { return this.#textarea.selectionEnd; }
|
|
289
|
-
|
|
290
|
-
set selectionEnd(value) { this.#textarea.selectionEnd = value; }
|
|
291
|
-
|
|
292
|
-
get setRangeText() { return this.#textarea.setRangeText; }
|
|
293
|
-
|
|
294
|
-
get setSelectionRange() { return this.#textarea.setSelectionRange; }
|
|
295
|
-
|
|
296
|
-
/** @param {ResizeObserverEntry} entry */
|
|
297
|
-
onResizeObserved(entry) {
|
|
298
|
-
super.onResizeObserved(entry);
|
|
299
|
-
this.resize();
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
TextArea.propList.delete('type');
|
|
304
|
-
|
|
305
|
-
TextArea.prototype._maxHeight = TextArea.prop('_maxHeight');
|
|
306
|
-
TextArea.prototype.fixed = TextArea.prop('fixed', { type: 'boolean' });
|
|
307
|
-
TextArea.prototype.minRows = TextArea.prop('minRows', { attr: 'minrows', type: 'integer', empty: 0 });
|
|
308
|
-
TextArea.prototype.maxRows = TextArea.prop('maxRows', { attr: 'maxrows', type: 'integer', empty: 0 });
|
|
309
|
-
TextArea.prototype._lineHeight = TextArea.prop('_lineHeight');
|
|
310
|
-
|
|
311
|
-
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element
|
|
312
|
-
|
|
313
|
-
const DOMString = { nullParser: String };
|
|
314
|
-
TextArea.prototype.cols = TextArea.prop('cols', { type: 'integer', empty: 0 });
|
|
315
|
-
TextArea.prototype.dirName = TextArea.prop('dirName', { attr: 'dirname', ...DOMString });
|
|
316
|
-
TextArea.prototype.maxLength = TextArea.prop('maxLength', { attr: 'maxlength', type: 'integer', empty: 0 });
|
|
317
|
-
TextArea.prototype.minLength = TextArea.prop('minLength', { attr: 'minlength', type: 'integer', empty: 0 });
|
|
318
|
-
TextArea.prototype.placeholder = TextArea.prop('placeholder', DOMString);
|
|
319
|
-
TextArea.prototype.rows = TextArea.prop('rows', { type: 'integer', empty: 1 });
|
|
320
|
-
TextArea.prototype.wrap = TextArea.prop('wrap', DOMString);
|
|
321
|
-
|
|
322
|
-
// Not in spec, but plays nice with HTML linters
|
|
323
|
-
TextArea.prototype.defaultValueAttr = TextArea.prop('defaultValueAttr', { attr: 'value', ...DOMString });
|
|
309
|
+
`
|
|
310
|
+
.autoRegister('mdw-textarea');
|
package/core/CustomElement.js
CHANGED
|
@@ -16,6 +16,22 @@ function superOf(instance) {
|
|
|
16
16
|
return superOfStatic.prototype;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Clone attribute
|
|
21
|
+
* @param {string} name
|
|
22
|
+
* @param {string} target
|
|
23
|
+
* @return {(oldValue:string, newValue:string, element: CustomElement) => void}
|
|
24
|
+
*/
|
|
25
|
+
export function cloneAttributeCallback(name, target) {
|
|
26
|
+
return (oldValue, newValue, element) => {
|
|
27
|
+
if (newValue == null) {
|
|
28
|
+
element.refs[target].removeAttribute(name);
|
|
29
|
+
} else {
|
|
30
|
+
element.refs[target].setAttribute(name, newValue);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
const EVENT_PREFIX_REGEX = /^([*1~]+)?(.*)$/;
|
|
20
36
|
|
|
21
37
|
/**
|
|
@@ -365,6 +381,7 @@ export default class CustomElement extends ICustomElement {
|
|
|
365
381
|
/**
|
|
366
382
|
* Define properties on instances via Object.defineProperties().
|
|
367
383
|
* Automatically sets property non-enumerable if name begins with `_`.
|
|
384
|
+
* Functions will be remapped as getters
|
|
368
385
|
* @type {typeof ICustomElement.define}
|
|
369
386
|
*/
|
|
370
387
|
static define(props) {
|
|
@@ -546,10 +563,11 @@ export default class CustomElement extends ICustomElement {
|
|
|
546
563
|
/** @type {typeof ICustomElement['onAttributeChanged']} */
|
|
547
564
|
static onAttributeChanged(options) {
|
|
548
565
|
for (const [name, callback] of Object.entries(options)) {
|
|
549
|
-
|
|
566
|
+
const lcName = name.toLowerCase();
|
|
567
|
+
let array = this.attributeChangedCallbacks.get(lcName);
|
|
550
568
|
if (!array) {
|
|
551
569
|
array = [];
|
|
552
|
-
this.attributeChangedCallbacks.set(
|
|
570
|
+
this.attributeChangedCallbacks.set(lcName, array);
|
|
553
571
|
}
|
|
554
572
|
array.push(callback);
|
|
555
573
|
}
|
|
@@ -608,14 +626,14 @@ export default class CustomElement extends ICustomElement {
|
|
|
608
626
|
|
|
609
627
|
/** @type {InstanceType<typeof ICustomElement>['propChangedCallback']} */
|
|
610
628
|
propChangedCallback(name, oldValue, newValue, changes = newValue) {
|
|
629
|
+
this.render({ [name]: changes });
|
|
630
|
+
|
|
611
631
|
const callbacks = this.static.propChangedCallbacks.get(name);
|
|
612
632
|
if (callbacks) {
|
|
613
633
|
for (const callback of callbacks) {
|
|
614
634
|
callback.call(this, oldValue, newValue, changes, this);
|
|
615
635
|
}
|
|
616
636
|
}
|
|
617
|
-
|
|
618
|
-
this.render({ [name]: changes });
|
|
619
637
|
}
|
|
620
638
|
|
|
621
639
|
/**
|
|
@@ -624,7 +642,7 @@ export default class CustomElement extends ICustomElement {
|
|
|
624
642
|
* @param {string|null} newValue
|
|
625
643
|
*/
|
|
626
644
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
627
|
-
const callbacks = this.static.attributeChangedCallbacks.get(name);
|
|
645
|
+
const callbacks = this.static.attributeChangedCallbacks.get(name.toLowerCase());
|
|
628
646
|
if (callbacks) {
|
|
629
647
|
for (const callback of callbacks) {
|
|
630
648
|
callback.call(this, oldValue, newValue, this);
|
package/core/ICustomElement.d.ts
CHANGED
|
@@ -272,17 +272,20 @@ export declare const ICustomElement: {
|
|
|
272
272
|
},
|
|
273
273
|
): T1;
|
|
274
274
|
|
|
275
|
-
onAttributeChanged<
|
|
275
|
+
onAttributeChanged<
|
|
276
|
+
T1 extends typeof ICustomElement,
|
|
277
|
+
T2 extends InstanceType<T1>
|
|
278
|
+
>
|
|
276
279
|
(
|
|
277
|
-
this:
|
|
280
|
+
this: T1,
|
|
278
281
|
options: {
|
|
279
282
|
[x:string]: (
|
|
280
283
|
// eslint-disable-next-line no-shadow
|
|
281
|
-
this:
|
|
284
|
+
this: T2,
|
|
282
285
|
oldValue: string,
|
|
283
286
|
newValue: string,
|
|
284
|
-
element:
|
|
287
|
+
element: T2
|
|
285
288
|
) => void
|
|
286
289
|
},
|
|
287
|
-
):
|
|
290
|
+
): T1;
|
|
288
291
|
};
|