@shortfuse/materialdesignweb 0.7.2 → 0.7.4

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.
@@ -1,4 +1,4 @@
1
- import { constructHTMLOptionsCollectionProxy } from '../dom/ HTMLOptionsCollectionProxy.js';
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';
@@ -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
- autocomplete: 'string',
18
- trailingIcon: {
19
- empty: 'arrow_drop_down',
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
- .setStatic({
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');
@@ -207,7 +207,7 @@ export default CustomElement
207
207
  --mdw-ink: var(--mdw-color__on-primary);
208
208
  --mdw-bg: var(--mdw-color__primary);
209
209
 
210
- display: inline-block;
210
+ display: block;
211
211
  vertical-align: middle;
212
212
 
213
213
  min-block-size: 40px;
@@ -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
- /** @implements {HTMLTextAreaElement} */
9
- export default class TextArea extends CustomElement
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
- static { this.autoRegister('mdw-textarea'); }
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
- static {
18
- // eslint-disable-next-line no-unused-expressions
19
- this.css`
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');
@@ -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
- let array = this.attributeChangedCallbacks.get(name);
566
+ const lcName = name.toLowerCase();
567
+ let array = this.attributeChangedCallbacks.get(lcName);
550
568
  if (!array) {
551
569
  array = [];
552
- this.attributeChangedCallbacks.set(name, array);
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);
@@ -272,17 +272,20 @@ export declare const ICustomElement: {
272
272
  },
273
273
  ): T1;
274
274
 
275
- onAttributeChanged<T extends typeof ICustomElement>
275
+ onAttributeChanged<
276
+ T1 extends typeof ICustomElement,
277
+ T2 extends InstanceType<T1>
278
+ >
276
279
  (
277
- this: T,
280
+ this: T1,
278
281
  options: {
279
282
  [x:string]: (
280
283
  // eslint-disable-next-line no-shadow
281
- this: InstanceType<T>,
284
+ this: T2,
282
285
  oldValue: string,
283
286
  newValue: string,
284
- element: InstanceType<T>
287
+ element: T2
285
288
  ) => void
286
289
  },
287
- ): T;
290
+ ): T1;
288
291
  };