@matter-server/dashboard 0.2.7-alpha.0-20260118-993a1c7 → 0.2.7-alpha.0-20260118-45c7af0
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/esm/components/dialogs/settings/log-level-dialog.d.ts +33 -0
- package/dist/esm/components/dialogs/settings/log-level-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/settings/log-level-dialog.js +185 -0
- package/dist/esm/components/dialogs/settings/log-level-dialog.js.map +6 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.d.ts +8 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.d.ts.map +1 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.js +15 -0
- package/dist/esm/components/dialogs/settings/show-log-level-dialog.js.map +6 -0
- package/dist/esm/pages/components/header.d.ts +1 -0
- package/dist/esm/pages/components/header.d.ts.map +1 -1
- package/dist/esm/pages/components/header.js +13 -1
- package/dist/esm/pages/components/header.js.map +1 -1
- package/dist/web/js/{commission-node-dialog-DGw5qDgH.js → commission-node-dialog-CoaDIV2Y.js} +5 -5
- package/dist/web/js/{commission-node-existing-CHyyeC8y.js → commission-node-existing-DEU_mJjO.js} +5 -4
- package/dist/web/js/{commission-node-thread-iRDSlidy.js → commission-node-thread-DZ6DghSs.js} +5 -4
- package/dist/web/js/{commission-node-wifi-C4YNR3bG.js → commission-node-wifi-DOyin0q3.js} +5 -4
- package/dist/web/js/{dialog-box-ag-xOaYh.js → dialog-box-B5sunUPv.js} +2 -2
- package/dist/web/js/{fire_event-BeiEbHcE.js → fire_event-C9Duc1j-.js} +1 -1
- package/dist/web/js/log-level-dialog-B7LsZYUL.js +3232 -0
- package/dist/web/js/main.js +24 -1
- package/dist/web/js/{matter-dashboard-app-BxQ4W_uT.js → matter-dashboard-app-DlHSE_Qh.js} +81 -5
- package/dist/web/js/{node-binding-dialog-ClziphM0.js → node-binding-dialog-BifZsigR.js} +4 -3
- package/dist/web/js/outlined-text-field-D2BOt1yD.js +968 -0
- package/dist/web/js/{prevent_default-Bs2sUnny.js → prevent_default-CuW2EnKR.js} +1 -1
- package/dist/web/js/validator-MOJiFndw.js +1122 -0
- package/package.json +4 -4
- package/src/components/dialogs/settings/log-level-dialog.ts +179 -0
- package/src/components/dialogs/settings/show-log-level-dialog.ts +14 -0
- package/src/pages/components/header.ts +16 -1
- package/dist/web/js/outlined-text-field-B-CiqgEJ.js +0 -2086
|
@@ -0,0 +1,1122 @@
|
|
|
1
|
+
import { _ as __decorate, n as n$1, o as o$1, r, a as e, i as i$1, f as e$1, A, h as b, D, E as EASING, j as i$2, t, s as e$2, v as i$3, w as t$1, x as E, y as internals } from './matter-dashboard-app-DlHSE_Qh.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @license
|
|
5
|
+
* Copyright 2021 Google LLC
|
|
6
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* A field component.
|
|
10
|
+
*/
|
|
11
|
+
class Field extends i$1 {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
this.disabled = false;
|
|
15
|
+
this.error = false;
|
|
16
|
+
this.focused = false;
|
|
17
|
+
this.label = '';
|
|
18
|
+
this.noAsterisk = false;
|
|
19
|
+
this.populated = false;
|
|
20
|
+
this.required = false;
|
|
21
|
+
this.resizable = false;
|
|
22
|
+
this.supportingText = '';
|
|
23
|
+
this.errorText = '';
|
|
24
|
+
this.count = -1;
|
|
25
|
+
this.max = -1;
|
|
26
|
+
/**
|
|
27
|
+
* Whether or not the field has leading content.
|
|
28
|
+
*/
|
|
29
|
+
this.hasStart = false;
|
|
30
|
+
/**
|
|
31
|
+
* Whether or not the field has trailing content.
|
|
32
|
+
*/
|
|
33
|
+
this.hasEnd = false;
|
|
34
|
+
this.isAnimating = false;
|
|
35
|
+
/**
|
|
36
|
+
* When set to true, the error text's `role="alert"` will be removed, then
|
|
37
|
+
* re-added after an animation frame. This will re-announce an error message
|
|
38
|
+
* to screen readers.
|
|
39
|
+
*/
|
|
40
|
+
this.refreshErrorAlert = false;
|
|
41
|
+
this.disableTransitions = false;
|
|
42
|
+
}
|
|
43
|
+
get counterText() {
|
|
44
|
+
// Count and max are typed as number, but can be set to null when Lit removes
|
|
45
|
+
// their attributes. These getters coerce back to a number for calculations.
|
|
46
|
+
const countAsNumber = this.count ?? -1;
|
|
47
|
+
const maxAsNumber = this.max ?? -1;
|
|
48
|
+
// Counter does not show if count is negative, or max is negative or 0.
|
|
49
|
+
if (countAsNumber < 0 || maxAsNumber <= 0) {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
return `${countAsNumber} / ${maxAsNumber}`;
|
|
53
|
+
}
|
|
54
|
+
get supportingOrErrorText() {
|
|
55
|
+
return this.error && this.errorText ? this.errorText : this.supportingText;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Re-announces the field's error supporting text to screen readers.
|
|
59
|
+
*
|
|
60
|
+
* Error text announces to screen readers anytime it is visible and changes.
|
|
61
|
+
* Use the method to re-announce the message when the text has not changed,
|
|
62
|
+
* but announcement is still needed (such as for `reportValidity()`).
|
|
63
|
+
*/
|
|
64
|
+
reannounceError() {
|
|
65
|
+
this.refreshErrorAlert = true;
|
|
66
|
+
}
|
|
67
|
+
update(props) {
|
|
68
|
+
// Client-side property updates
|
|
69
|
+
const isDisabledChanging = props.has('disabled') && props.get('disabled') !== undefined;
|
|
70
|
+
if (isDisabledChanging) {
|
|
71
|
+
this.disableTransitions = true;
|
|
72
|
+
}
|
|
73
|
+
// When disabling, remove focus styles if focused.
|
|
74
|
+
if (this.disabled && this.focused) {
|
|
75
|
+
props.set('focused', true);
|
|
76
|
+
this.focused = false;
|
|
77
|
+
}
|
|
78
|
+
// Animate if focused or populated change.
|
|
79
|
+
this.animateLabelIfNeeded({
|
|
80
|
+
wasFocused: props.get('focused'),
|
|
81
|
+
wasPopulated: props.get('populated')
|
|
82
|
+
});
|
|
83
|
+
super.update(props);
|
|
84
|
+
}
|
|
85
|
+
render() {
|
|
86
|
+
var _this$renderOutline, _this$renderBackgroun, _this$renderStateLaye, _this$renderIndicator;
|
|
87
|
+
const floatingLabel = this.renderLabel(/*isFloating*/true);
|
|
88
|
+
const restingLabel = this.renderLabel(/*isFloating*/false);
|
|
89
|
+
const outline = (_this$renderOutline = this.renderOutline) === null || _this$renderOutline === void 0 ? void 0 : _this$renderOutline.call(this, floatingLabel);
|
|
90
|
+
const classes = {
|
|
91
|
+
'disabled': this.disabled,
|
|
92
|
+
'disable-transitions': this.disableTransitions,
|
|
93
|
+
'error': this.error && !this.disabled,
|
|
94
|
+
'focused': this.focused,
|
|
95
|
+
'with-start': this.hasStart,
|
|
96
|
+
'with-end': this.hasEnd,
|
|
97
|
+
'populated': this.populated,
|
|
98
|
+
'resizable': this.resizable,
|
|
99
|
+
'required': this.required,
|
|
100
|
+
'no-label': !this.label
|
|
101
|
+
};
|
|
102
|
+
return b`
|
|
103
|
+
<div class="field ${e$1(classes)}">
|
|
104
|
+
<div class="container-overflow">
|
|
105
|
+
${(_this$renderBackgroun = this.renderBackground) === null || _this$renderBackgroun === void 0 ? void 0 : _this$renderBackgroun.call(this)}
|
|
106
|
+
<slot name="container"></slot>
|
|
107
|
+
${(_this$renderStateLaye = this.renderStateLayer) === null || _this$renderStateLaye === void 0 ? void 0 : _this$renderStateLaye.call(this)} ${(_this$renderIndicator = this.renderIndicator) === null || _this$renderIndicator === void 0 ? void 0 : _this$renderIndicator.call(this)} ${outline}
|
|
108
|
+
<div class="container">
|
|
109
|
+
<div class="start">
|
|
110
|
+
<slot name="start"></slot>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="middle">
|
|
113
|
+
<div class="label-wrapper">
|
|
114
|
+
${restingLabel} ${outline ? A : floatingLabel}
|
|
115
|
+
</div>
|
|
116
|
+
<div class="content">
|
|
117
|
+
<slot></slot>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
<div class="end">
|
|
121
|
+
<slot name="end"></slot>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
${this.renderSupportingText()}
|
|
126
|
+
</div>
|
|
127
|
+
`;
|
|
128
|
+
}
|
|
129
|
+
updated(changed) {
|
|
130
|
+
if (changed.has('supportingText') || changed.has('errorText') || changed.has('count') || changed.has('max')) {
|
|
131
|
+
this.updateSlottedAriaDescribedBy();
|
|
132
|
+
}
|
|
133
|
+
if (this.refreshErrorAlert) {
|
|
134
|
+
// The past render cycle removed the role="alert" from the error message.
|
|
135
|
+
// Re-add it after an animation frame to re-announce the error.
|
|
136
|
+
requestAnimationFrame(() => {
|
|
137
|
+
this.refreshErrorAlert = false;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (this.disableTransitions) {
|
|
141
|
+
requestAnimationFrame(() => {
|
|
142
|
+
this.disableTransitions = false;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
renderSupportingText() {
|
|
147
|
+
const {
|
|
148
|
+
supportingOrErrorText,
|
|
149
|
+
counterText
|
|
150
|
+
} = this;
|
|
151
|
+
if (!supportingOrErrorText && !counterText) {
|
|
152
|
+
return A;
|
|
153
|
+
}
|
|
154
|
+
// Always render the supporting text span so that our `space-around`
|
|
155
|
+
// container puts the counter at the end.
|
|
156
|
+
const start = b`<span>${supportingOrErrorText}</span>`;
|
|
157
|
+
// Conditionally render counter so we don't render the extra `gap`.
|
|
158
|
+
// TODO(b/244473435): add aria-label and announcements
|
|
159
|
+
const end = counterText ? b`<span class="counter">${counterText}</span>` : A;
|
|
160
|
+
// Announce if there is an error and error text visible.
|
|
161
|
+
// If refreshErrorAlert is true, do not announce. This will remove the
|
|
162
|
+
// role="alert" attribute. Another render cycle will happen after an
|
|
163
|
+
// animation frame to re-add the role.
|
|
164
|
+
const shouldErrorAnnounce = this.error && this.errorText && !this.refreshErrorAlert;
|
|
165
|
+
const role = shouldErrorAnnounce ? 'alert' : A;
|
|
166
|
+
return b`
|
|
167
|
+
<div class="supporting-text" role=${role}>${start}${end}</div>
|
|
168
|
+
<slot
|
|
169
|
+
name="aria-describedby"
|
|
170
|
+
@slotchange=${this.updateSlottedAriaDescribedBy}></slot>
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
updateSlottedAriaDescribedBy() {
|
|
174
|
+
for (const element of this.slottedAriaDescribedBy) {
|
|
175
|
+
D(b`${this.supportingOrErrorText} ${this.counterText}`, element);
|
|
176
|
+
element.setAttribute('hidden', '');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
renderLabel(isFloating) {
|
|
180
|
+
if (!this.label) {
|
|
181
|
+
return A;
|
|
182
|
+
}
|
|
183
|
+
let visible;
|
|
184
|
+
if (isFloating) {
|
|
185
|
+
// Floating label is visible when focused/populated or when animating.
|
|
186
|
+
visible = this.focused || this.populated || this.isAnimating;
|
|
187
|
+
} else {
|
|
188
|
+
// Resting label is visible when unfocused. It is never visible while
|
|
189
|
+
// animating.
|
|
190
|
+
visible = !this.focused && !this.populated && !this.isAnimating;
|
|
191
|
+
}
|
|
192
|
+
const classes = {
|
|
193
|
+
'hidden': !visible,
|
|
194
|
+
'floating': isFloating,
|
|
195
|
+
'resting': !isFloating
|
|
196
|
+
};
|
|
197
|
+
// Add '*' if a label is present and the field is required
|
|
198
|
+
const labelText = `${this.label}${this.required && !this.noAsterisk ? '*' : ''}`;
|
|
199
|
+
return b`
|
|
200
|
+
<span class="label ${e$1(classes)}" aria-hidden=${!visible}
|
|
201
|
+
>${labelText}</span
|
|
202
|
+
>
|
|
203
|
+
`;
|
|
204
|
+
}
|
|
205
|
+
animateLabelIfNeeded({
|
|
206
|
+
wasFocused,
|
|
207
|
+
wasPopulated
|
|
208
|
+
}) {
|
|
209
|
+
var _this$labelAnimation, _this$floatingLabelEl, _this$labelAnimation2;
|
|
210
|
+
if (!this.label) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
wasFocused ?? (wasFocused = this.focused);
|
|
214
|
+
wasPopulated ?? (wasPopulated = this.populated);
|
|
215
|
+
const wasFloating = wasFocused || wasPopulated;
|
|
216
|
+
const shouldBeFloating = this.focused || this.populated;
|
|
217
|
+
if (wasFloating === shouldBeFloating) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
this.isAnimating = true;
|
|
221
|
+
(_this$labelAnimation = this.labelAnimation) === null || _this$labelAnimation === void 0 || _this$labelAnimation.cancel();
|
|
222
|
+
// Only one label is visible at a time for clearer text rendering.
|
|
223
|
+
// The floating label is visible and used during animation. At the end of
|
|
224
|
+
// the animation, it will either remain visible (if floating) or hide and
|
|
225
|
+
// the resting label will be shown.
|
|
226
|
+
//
|
|
227
|
+
// We don't use forward filling because if the dimensions of the text field
|
|
228
|
+
// change (leading icon removed, density changes, etc), then the animation
|
|
229
|
+
// will be inaccurate.
|
|
230
|
+
//
|
|
231
|
+
// Re-calculating the animation each time will prevent any visual glitches
|
|
232
|
+
// from appearing.
|
|
233
|
+
// TODO(b/241113345): use animation tokens
|
|
234
|
+
this.labelAnimation = (_this$floatingLabelEl = this.floatingLabelEl) === null || _this$floatingLabelEl === void 0 ? void 0 : _this$floatingLabelEl.animate(this.getLabelKeyframes(), {
|
|
235
|
+
duration: 150,
|
|
236
|
+
easing: EASING.STANDARD
|
|
237
|
+
});
|
|
238
|
+
(_this$labelAnimation2 = this.labelAnimation) === null || _this$labelAnimation2 === void 0 || _this$labelAnimation2.addEventListener('finish', () => {
|
|
239
|
+
// At the end of the animation, update the visible label.
|
|
240
|
+
this.isAnimating = false;
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
getLabelKeyframes() {
|
|
244
|
+
const {
|
|
245
|
+
floatingLabelEl,
|
|
246
|
+
restingLabelEl
|
|
247
|
+
} = this;
|
|
248
|
+
if (!floatingLabelEl || !restingLabelEl) {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
const {
|
|
252
|
+
x: floatingX,
|
|
253
|
+
y: floatingY,
|
|
254
|
+
height: floatingHeight
|
|
255
|
+
} = floatingLabelEl.getBoundingClientRect();
|
|
256
|
+
const {
|
|
257
|
+
x: restingX,
|
|
258
|
+
y: restingY,
|
|
259
|
+
height: restingHeight
|
|
260
|
+
} = restingLabelEl.getBoundingClientRect();
|
|
261
|
+
const floatingScrollWidth = floatingLabelEl.scrollWidth;
|
|
262
|
+
const restingScrollWidth = restingLabelEl.scrollWidth;
|
|
263
|
+
// Scale by width ratio instead of font size since letter-spacing will scale
|
|
264
|
+
// incorrectly. Using the width we can better approximate the adjusted
|
|
265
|
+
// scale and compensate for tracking and overflow.
|
|
266
|
+
// (use scrollWidth instead of width to account for clipped labels)
|
|
267
|
+
const scale = restingScrollWidth / floatingScrollWidth;
|
|
268
|
+
const xDelta = restingX - floatingX;
|
|
269
|
+
// The line-height of the resting and floating label are different. When
|
|
270
|
+
// we move the floating label down to the resting label's position, it won't
|
|
271
|
+
// exactly match because of this. We need to adjust by half of what the
|
|
272
|
+
// final scaled floating label's height will be.
|
|
273
|
+
const yDelta = restingY - floatingY + Math.round((restingHeight - floatingHeight * scale) / 2);
|
|
274
|
+
// Create the two transforms: floating to resting (using the calculations
|
|
275
|
+
// above), and resting to floating (re-setting the transform to initial
|
|
276
|
+
// values).
|
|
277
|
+
const restTransform = `translateX(${xDelta}px) translateY(${yDelta}px) scale(${scale})`;
|
|
278
|
+
const floatTransform = `translateX(0) translateY(0) scale(1)`;
|
|
279
|
+
// Constrain the floating labels width to a scaled percentage of the
|
|
280
|
+
// resting label's width. This will prevent long clipped labels from
|
|
281
|
+
// overflowing the container.
|
|
282
|
+
const restingClientWidth = restingLabelEl.clientWidth;
|
|
283
|
+
const isRestingClipped = restingScrollWidth > restingClientWidth;
|
|
284
|
+
const width = isRestingClipped ? `${restingClientWidth / scale}px` : '';
|
|
285
|
+
if (this.focused || this.populated) {
|
|
286
|
+
return [{
|
|
287
|
+
transform: restTransform,
|
|
288
|
+
width
|
|
289
|
+
}, {
|
|
290
|
+
transform: floatTransform,
|
|
291
|
+
width
|
|
292
|
+
}];
|
|
293
|
+
}
|
|
294
|
+
return [{
|
|
295
|
+
transform: floatTransform,
|
|
296
|
+
width
|
|
297
|
+
}, {
|
|
298
|
+
transform: restTransform,
|
|
299
|
+
width
|
|
300
|
+
}];
|
|
301
|
+
}
|
|
302
|
+
getSurfacePositionClientRect() {
|
|
303
|
+
return this.containerEl.getBoundingClientRect();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
__decorate([n$1({
|
|
307
|
+
type: Boolean
|
|
308
|
+
})], Field.prototype, "disabled", void 0);
|
|
309
|
+
__decorate([n$1({
|
|
310
|
+
type: Boolean
|
|
311
|
+
})], Field.prototype, "error", void 0);
|
|
312
|
+
__decorate([n$1({
|
|
313
|
+
type: Boolean
|
|
314
|
+
})], Field.prototype, "focused", void 0);
|
|
315
|
+
__decorate([n$1()], Field.prototype, "label", void 0);
|
|
316
|
+
__decorate([n$1({
|
|
317
|
+
type: Boolean,
|
|
318
|
+
attribute: 'no-asterisk'
|
|
319
|
+
})], Field.prototype, "noAsterisk", void 0);
|
|
320
|
+
__decorate([n$1({
|
|
321
|
+
type: Boolean
|
|
322
|
+
})], Field.prototype, "populated", void 0);
|
|
323
|
+
__decorate([n$1({
|
|
324
|
+
type: Boolean
|
|
325
|
+
})], Field.prototype, "required", void 0);
|
|
326
|
+
__decorate([n$1({
|
|
327
|
+
type: Boolean
|
|
328
|
+
})], Field.prototype, "resizable", void 0);
|
|
329
|
+
__decorate([n$1({
|
|
330
|
+
attribute: 'supporting-text'
|
|
331
|
+
})], Field.prototype, "supportingText", void 0);
|
|
332
|
+
__decorate([n$1({
|
|
333
|
+
attribute: 'error-text'
|
|
334
|
+
})], Field.prototype, "errorText", void 0);
|
|
335
|
+
__decorate([n$1({
|
|
336
|
+
type: Number
|
|
337
|
+
})], Field.prototype, "count", void 0);
|
|
338
|
+
__decorate([n$1({
|
|
339
|
+
type: Number
|
|
340
|
+
})], Field.prototype, "max", void 0);
|
|
341
|
+
__decorate([n$1({
|
|
342
|
+
type: Boolean,
|
|
343
|
+
attribute: 'has-start'
|
|
344
|
+
})], Field.prototype, "hasStart", void 0);
|
|
345
|
+
__decorate([n$1({
|
|
346
|
+
type: Boolean,
|
|
347
|
+
attribute: 'has-end'
|
|
348
|
+
})], Field.prototype, "hasEnd", void 0);
|
|
349
|
+
__decorate([o$1({
|
|
350
|
+
slot: 'aria-describedby'
|
|
351
|
+
})], Field.prototype, "slottedAriaDescribedBy", void 0);
|
|
352
|
+
__decorate([r()], Field.prototype, "isAnimating", void 0);
|
|
353
|
+
__decorate([r()], Field.prototype, "refreshErrorAlert", void 0);
|
|
354
|
+
__decorate([r()], Field.prototype, "disableTransitions", void 0);
|
|
355
|
+
__decorate([e('.label.floating')], Field.prototype, "floatingLabelEl", void 0);
|
|
356
|
+
__decorate([e('.label.resting')], Field.prototype, "restingLabelEl", void 0);
|
|
357
|
+
__decorate([e('.container')], Field.prototype, "containerEl", void 0);
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* @license
|
|
361
|
+
* Copyright 2021 Google LLC
|
|
362
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
363
|
+
*/
|
|
364
|
+
/**
|
|
365
|
+
* An outlined field component.
|
|
366
|
+
*/
|
|
367
|
+
class OutlinedField extends Field {
|
|
368
|
+
renderOutline(floatingLabel) {
|
|
369
|
+
return b`
|
|
370
|
+
<div class="outline">
|
|
371
|
+
<div class="outline-start"></div>
|
|
372
|
+
<div class="outline-notch">
|
|
373
|
+
<div class="outline-panel-inactive"></div>
|
|
374
|
+
<div class="outline-panel-active"></div>
|
|
375
|
+
<div class="outline-label">${floatingLabel}</div>
|
|
376
|
+
</div>
|
|
377
|
+
<div class="outline-end"></div>
|
|
378
|
+
</div>
|
|
379
|
+
`;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* @license
|
|
385
|
+
* Copyright 2024 Google LLC
|
|
386
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
387
|
+
*/
|
|
388
|
+
// Generated stylesheet for ./field/internal/outlined-styles.css.
|
|
389
|
+
const styles$1 = i$2`@layer styles{:host{--_bottom-space: var(--md-outlined-field-bottom-space, 16px);--_content-color: var(--md-outlined-field-content-color, var(--md-sys-color-on-surface, #1d1b20));--_content-font: var(--md-outlined-field-content-font, var(--md-sys-typescale-body-large-font, var(--md-ref-typeface-plain, Roboto)));--_content-line-height: var(--md-outlined-field-content-line-height, var(--md-sys-typescale-body-large-line-height, 1.5rem));--_content-size: var(--md-outlined-field-content-size, var(--md-sys-typescale-body-large-size, 1rem));--_content-space: var(--md-outlined-field-content-space, 16px);--_content-weight: var(--md-outlined-field-content-weight, var(--md-sys-typescale-body-large-weight, var(--md-ref-typeface-weight-regular, 400)));--_disabled-content-color: var(--md-outlined-field-disabled-content-color, var(--md-sys-color-on-surface, #1d1b20));--_disabled-content-opacity: var(--md-outlined-field-disabled-content-opacity, 0.38);--_disabled-label-text-color: var(--md-outlined-field-disabled-label-text-color, var(--md-sys-color-on-surface, #1d1b20));--_disabled-label-text-opacity: var(--md-outlined-field-disabled-label-text-opacity, 0.38);--_disabled-leading-content-color: var(--md-outlined-field-disabled-leading-content-color, var(--md-sys-color-on-surface, #1d1b20));--_disabled-leading-content-opacity: var(--md-outlined-field-disabled-leading-content-opacity, 0.38);--_disabled-outline-color: var(--md-outlined-field-disabled-outline-color, var(--md-sys-color-on-surface, #1d1b20));--_disabled-outline-opacity: var(--md-outlined-field-disabled-outline-opacity, 0.12);--_disabled-outline-width: var(--md-outlined-field-disabled-outline-width, 1px);--_disabled-supporting-text-color: var(--md-outlined-field-disabled-supporting-text-color, var(--md-sys-color-on-surface, #1d1b20));--_disabled-supporting-text-opacity: var(--md-outlined-field-disabled-supporting-text-opacity, 0.38);--_disabled-trailing-content-color: var(--md-outlined-field-disabled-trailing-content-color, var(--md-sys-color-on-surface, #1d1b20));--_disabled-trailing-content-opacity: var(--md-outlined-field-disabled-trailing-content-opacity, 0.38);--_error-content-color: var(--md-outlined-field-error-content-color, var(--md-sys-color-on-surface, #1d1b20));--_error-focus-content-color: var(--md-outlined-field-error-focus-content-color, var(--md-sys-color-on-surface, #1d1b20));--_error-focus-label-text-color: var(--md-outlined-field-error-focus-label-text-color, var(--md-sys-color-error, #b3261e));--_error-focus-leading-content-color: var(--md-outlined-field-error-focus-leading-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_error-focus-outline-color: var(--md-outlined-field-error-focus-outline-color, var(--md-sys-color-error, #b3261e));--_error-focus-supporting-text-color: var(--md-outlined-field-error-focus-supporting-text-color, var(--md-sys-color-error, #b3261e));--_error-focus-trailing-content-color: var(--md-outlined-field-error-focus-trailing-content-color, var(--md-sys-color-error, #b3261e));--_error-hover-content-color: var(--md-outlined-field-error-hover-content-color, var(--md-sys-color-on-surface, #1d1b20));--_error-hover-label-text-color: var(--md-outlined-field-error-hover-label-text-color, var(--md-sys-color-on-error-container, #410e0b));--_error-hover-leading-content-color: var(--md-outlined-field-error-hover-leading-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_error-hover-outline-color: var(--md-outlined-field-error-hover-outline-color, var(--md-sys-color-on-error-container, #410e0b));--_error-hover-supporting-text-color: var(--md-outlined-field-error-hover-supporting-text-color, var(--md-sys-color-error, #b3261e));--_error-hover-trailing-content-color: var(--md-outlined-field-error-hover-trailing-content-color, var(--md-sys-color-on-error-container, #410e0b));--_error-label-text-color: var(--md-outlined-field-error-label-text-color, var(--md-sys-color-error, #b3261e));--_error-leading-content-color: var(--md-outlined-field-error-leading-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_error-outline-color: var(--md-outlined-field-error-outline-color, var(--md-sys-color-error, #b3261e));--_error-supporting-text-color: var(--md-outlined-field-error-supporting-text-color, var(--md-sys-color-error, #b3261e));--_error-trailing-content-color: var(--md-outlined-field-error-trailing-content-color, var(--md-sys-color-error, #b3261e));--_focus-content-color: var(--md-outlined-field-focus-content-color, var(--md-sys-color-on-surface, #1d1b20));--_focus-label-text-color: var(--md-outlined-field-focus-label-text-color, var(--md-sys-color-primary, #6750a4));--_focus-leading-content-color: var(--md-outlined-field-focus-leading-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_focus-outline-color: var(--md-outlined-field-focus-outline-color, var(--md-sys-color-primary, #6750a4));--_focus-outline-width: var(--md-outlined-field-focus-outline-width, 3px);--_focus-supporting-text-color: var(--md-outlined-field-focus-supporting-text-color, var(--md-sys-color-on-surface-variant, #49454f));--_focus-trailing-content-color: var(--md-outlined-field-focus-trailing-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_hover-content-color: var(--md-outlined-field-hover-content-color, var(--md-sys-color-on-surface, #1d1b20));--_hover-label-text-color: var(--md-outlined-field-hover-label-text-color, var(--md-sys-color-on-surface, #1d1b20));--_hover-leading-content-color: var(--md-outlined-field-hover-leading-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_hover-outline-color: var(--md-outlined-field-hover-outline-color, var(--md-sys-color-on-surface, #1d1b20));--_hover-outline-width: var(--md-outlined-field-hover-outline-width, 1px);--_hover-supporting-text-color: var(--md-outlined-field-hover-supporting-text-color, var(--md-sys-color-on-surface-variant, #49454f));--_hover-trailing-content-color: var(--md-outlined-field-hover-trailing-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_label-text-color: var(--md-outlined-field-label-text-color, var(--md-sys-color-on-surface-variant, #49454f));--_label-text-font: var(--md-outlined-field-label-text-font, var(--md-sys-typescale-body-large-font, var(--md-ref-typeface-plain, Roboto)));--_label-text-line-height: var(--md-outlined-field-label-text-line-height, var(--md-sys-typescale-body-large-line-height, 1.5rem));--_label-text-padding-bottom: var(--md-outlined-field-label-text-padding-bottom, 8px);--_label-text-populated-line-height: var(--md-outlined-field-label-text-populated-line-height, var(--md-sys-typescale-body-small-line-height, 1rem));--_label-text-populated-size: var(--md-outlined-field-label-text-populated-size, var(--md-sys-typescale-body-small-size, 0.75rem));--_label-text-size: var(--md-outlined-field-label-text-size, var(--md-sys-typescale-body-large-size, 1rem));--_label-text-weight: var(--md-outlined-field-label-text-weight, var(--md-sys-typescale-body-large-weight, var(--md-ref-typeface-weight-regular, 400)));--_leading-content-color: var(--md-outlined-field-leading-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_leading-space: var(--md-outlined-field-leading-space, 16px);--_outline-color: var(--md-outlined-field-outline-color, var(--md-sys-color-outline, #79747e));--_outline-label-padding: var(--md-outlined-field-outline-label-padding, 4px);--_outline-width: var(--md-outlined-field-outline-width, 1px);--_supporting-text-color: var(--md-outlined-field-supporting-text-color, var(--md-sys-color-on-surface-variant, #49454f));--_supporting-text-font: var(--md-outlined-field-supporting-text-font, var(--md-sys-typescale-body-small-font, var(--md-ref-typeface-plain, Roboto)));--_supporting-text-leading-space: var(--md-outlined-field-supporting-text-leading-space, 16px);--_supporting-text-line-height: var(--md-outlined-field-supporting-text-line-height, var(--md-sys-typescale-body-small-line-height, 1rem));--_supporting-text-size: var(--md-outlined-field-supporting-text-size, var(--md-sys-typescale-body-small-size, 0.75rem));--_supporting-text-top-space: var(--md-outlined-field-supporting-text-top-space, 4px);--_supporting-text-trailing-space: var(--md-outlined-field-supporting-text-trailing-space, 16px);--_supporting-text-weight: var(--md-outlined-field-supporting-text-weight, var(--md-sys-typescale-body-small-weight, var(--md-ref-typeface-weight-regular, 400)));--_top-space: var(--md-outlined-field-top-space, 16px);--_trailing-content-color: var(--md-outlined-field-trailing-content-color, var(--md-sys-color-on-surface-variant, #49454f));--_trailing-space: var(--md-outlined-field-trailing-space, 16px);--_with-leading-content-leading-space: var(--md-outlined-field-with-leading-content-leading-space, 12px);--_with-trailing-content-trailing-space: var(--md-outlined-field-with-trailing-content-trailing-space, 12px);--_container-shape-start-start: var(--md-outlined-field-container-shape-start-start, var(--md-outlined-field-container-shape, var(--md-sys-shape-corner-extra-small, 4px)));--_container-shape-start-end: var(--md-outlined-field-container-shape-start-end, var(--md-outlined-field-container-shape, var(--md-sys-shape-corner-extra-small, 4px)));--_container-shape-end-end: var(--md-outlined-field-container-shape-end-end, var(--md-outlined-field-container-shape, var(--md-sys-shape-corner-extra-small, 4px)));--_container-shape-end-start: var(--md-outlined-field-container-shape-end-start, var(--md-outlined-field-container-shape, var(--md-sys-shape-corner-extra-small, 4px)))}.outline{border-color:var(--_outline-color);border-radius:inherit;display:flex;pointer-events:none;height:100%;position:absolute;width:100%;z-index:1}.outline-start::before,.outline-start::after,.outline-panel-inactive::before,.outline-panel-inactive::after,.outline-panel-active::before,.outline-panel-active::after,.outline-end::before,.outline-end::after{border:inherit;content:"";inset:0;position:absolute}.outline-start,.outline-end{border:inherit;border-radius:inherit;box-sizing:border-box;position:relative}.outline-start::before,.outline-start::after,.outline-end::before,.outline-end::after{border-bottom-style:solid;border-top-style:solid}.outline-start::after,.outline-end::after{opacity:0;transition:opacity 150ms cubic-bezier(0.2, 0, 0, 1)}.focused .outline-start::after,.focused .outline-end::after{opacity:1}.outline-start::before,.outline-start::after{border-inline-start-style:solid;border-inline-end-style:none;border-start-start-radius:inherit;border-start-end-radius:0;border-end-start-radius:inherit;border-end-end-radius:0;margin-inline-end:var(--_outline-label-padding)}.outline-end{flex-grow:1;margin-inline-start:calc(-1*var(--_outline-label-padding))}.outline-end::before,.outline-end::after{border-inline-start-style:none;border-inline-end-style:solid;border-start-start-radius:0;border-start-end-radius:inherit;border-end-start-radius:0;border-end-end-radius:inherit}.outline-notch{align-items:flex-start;border:inherit;display:flex;margin-inline-start:calc(-1*var(--_outline-label-padding));margin-inline-end:var(--_outline-label-padding);max-width:calc(100% - var(--_leading-space) - var(--_trailing-space));padding:0 var(--_outline-label-padding);position:relative}.no-label .outline-notch{display:none}.outline-panel-inactive,.outline-panel-active{border:inherit;border-bottom-style:solid;inset:0;position:absolute}.outline-panel-inactive::before,.outline-panel-inactive::after,.outline-panel-active::before,.outline-panel-active::after{border-top-style:solid;border-bottom:none;bottom:auto;transform:scaleX(1);transition:transform 150ms cubic-bezier(0.2, 0, 0, 1)}.outline-panel-inactive::before,.outline-panel-active::before{right:50%;transform-origin:top left}.outline-panel-inactive::after,.outline-panel-active::after{left:50%;transform-origin:top right}.populated .outline-panel-inactive::before,.populated .outline-panel-inactive::after,.populated .outline-panel-active::before,.populated .outline-panel-active::after,.focused .outline-panel-inactive::before,.focused .outline-panel-inactive::after,.focused .outline-panel-active::before,.focused .outline-panel-active::after{transform:scaleX(0)}.outline-panel-active{opacity:0;transition:opacity 150ms cubic-bezier(0.2, 0, 0, 1)}.focused .outline-panel-active{opacity:1}.outline-label{display:flex;max-width:100%;transform:translateY(calc(-100% + var(--_label-text-padding-bottom)))}.outline-start,.field:not(.with-start) .content ::slotted(*){padding-inline-start:max(var(--_leading-space),max(var(--_container-shape-start-start),var(--_container-shape-end-start)) + var(--_outline-label-padding))}.field:not(.with-start) .label-wrapper{margin-inline-start:max(var(--_leading-space),max(var(--_container-shape-start-start),var(--_container-shape-end-start)) + var(--_outline-label-padding))}.field:not(.with-end) .content ::slotted(*){padding-inline-end:max(var(--_trailing-space),max(var(--_container-shape-start-end),var(--_container-shape-end-end)))}.field:not(.with-end) .label-wrapper{margin-inline-end:max(var(--_trailing-space),max(var(--_container-shape-start-end),var(--_container-shape-end-end)))}.outline-start::before,.outline-end::before,.outline-panel-inactive,.outline-panel-inactive::before,.outline-panel-inactive::after{border-width:var(--_outline-width)}:hover .outline{border-color:var(--_hover-outline-color);color:var(--_hover-outline-color)}:hover .outline-start::before,:hover .outline-end::before,:hover .outline-panel-inactive,:hover .outline-panel-inactive::before,:hover .outline-panel-inactive::after{border-width:var(--_hover-outline-width)}.focused .outline{border-color:var(--_focus-outline-color);color:var(--_focus-outline-color)}.outline-start::after,.outline-end::after,.outline-panel-active,.outline-panel-active::before,.outline-panel-active::after{border-width:var(--_focus-outline-width)}.disabled .outline{border-color:var(--_disabled-outline-color);color:var(--_disabled-outline-color)}.disabled .outline-start,.disabled .outline-end,.disabled .outline-panel-inactive{opacity:var(--_disabled-outline-opacity)}.disabled .outline-start::before,.disabled .outline-end::before,.disabled .outline-panel-inactive,.disabled .outline-panel-inactive::before,.disabled .outline-panel-inactive::after{border-width:var(--_disabled-outline-width)}.error .outline{border-color:var(--_error-outline-color);color:var(--_error-outline-color)}.error:hover .outline{border-color:var(--_error-hover-outline-color);color:var(--_error-hover-outline-color)}.error.focused .outline{border-color:var(--_error-focus-outline-color);color:var(--_error-focus-outline-color)}.resizable .container{bottom:var(--_focus-outline-width);inset-inline-end:var(--_focus-outline-width);clip-path:inset(var(--_focus-outline-width) 0 0 var(--_focus-outline-width))}.resizable .container>*{top:var(--_focus-outline-width);inset-inline-start:var(--_focus-outline-width)}.resizable .container:dir(rtl){clip-path:inset(var(--_focus-outline-width) var(--_focus-outline-width) 0 0)}}@layer hcm{@media(forced-colors: active){.disabled .outline{border-color:GrayText;color:GrayText}.disabled :is(.outline-start,.outline-end,.outline-panel-inactive){opacity:1}}}
|
|
390
|
+
`;
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* @license
|
|
394
|
+
* Copyright 2024 Google LLC
|
|
395
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
396
|
+
*/
|
|
397
|
+
// Generated stylesheet for ./field/internal/shared-styles.css.
|
|
398
|
+
const styles = i$2`:host{display:inline-flex;resize:both}.field{display:flex;flex:1;flex-direction:column;writing-mode:horizontal-tb;max-width:100%}.container-overflow{border-start-start-radius:var(--_container-shape-start-start);border-start-end-radius:var(--_container-shape-start-end);border-end-end-radius:var(--_container-shape-end-end);border-end-start-radius:var(--_container-shape-end-start);display:flex;height:100%;position:relative}.container{align-items:center;border-radius:inherit;display:flex;flex:1;max-height:100%;min-height:100%;min-width:min-content;position:relative}.field,.container-overflow{resize:inherit}.resizable:not(.disabled) .container{resize:inherit;overflow:hidden}.disabled{pointer-events:none}slot[name=container]{border-radius:inherit}slot[name=container]::slotted(*){border-radius:inherit;inset:0;pointer-events:none;position:absolute}@layer styles{.start,.middle,.end{display:flex;box-sizing:border-box;height:100%;position:relative}.start{color:var(--_leading-content-color)}.end{color:var(--_trailing-content-color)}.start,.end{align-items:center;justify-content:center}.with-start .start{margin-inline:var(--_with-leading-content-leading-space) var(--_content-space)}.with-end .end{margin-inline:var(--_content-space) var(--_with-trailing-content-trailing-space)}.middle{align-items:stretch;align-self:baseline;flex:1}.content{color:var(--_content-color);display:flex;flex:1;opacity:0;transition:opacity 83ms cubic-bezier(0.2, 0, 0, 1)}.no-label .content,.focused .content,.populated .content{opacity:1;transition-delay:67ms}:is(.disabled,.disable-transitions) .content{transition:none}.content ::slotted(*){all:unset;color:currentColor;font-family:var(--_content-font);font-size:var(--_content-size);line-height:var(--_content-line-height);font-weight:var(--_content-weight);width:100%;overflow-wrap:revert;white-space:revert}.content ::slotted(:not(textarea)){padding-top:var(--_top-space);padding-bottom:var(--_bottom-space)}.content ::slotted(textarea){margin-top:var(--_top-space);margin-bottom:var(--_bottom-space)}:hover .content{color:var(--_hover-content-color)}:hover .start{color:var(--_hover-leading-content-color)}:hover .end{color:var(--_hover-trailing-content-color)}.focused .content{color:var(--_focus-content-color)}.focused .start{color:var(--_focus-leading-content-color)}.focused .end{color:var(--_focus-trailing-content-color)}.disabled .content{color:var(--_disabled-content-color)}.disabled.no-label .content,.disabled.focused .content,.disabled.populated .content{opacity:var(--_disabled-content-opacity)}.disabled .start{color:var(--_disabled-leading-content-color);opacity:var(--_disabled-leading-content-opacity)}.disabled .end{color:var(--_disabled-trailing-content-color);opacity:var(--_disabled-trailing-content-opacity)}.error .content{color:var(--_error-content-color)}.error .start{color:var(--_error-leading-content-color)}.error .end{color:var(--_error-trailing-content-color)}.error:hover .content{color:var(--_error-hover-content-color)}.error:hover .start{color:var(--_error-hover-leading-content-color)}.error:hover .end{color:var(--_error-hover-trailing-content-color)}.error.focused .content{color:var(--_error-focus-content-color)}.error.focused .start{color:var(--_error-focus-leading-content-color)}.error.focused .end{color:var(--_error-focus-trailing-content-color)}}@layer hcm{@media(forced-colors: active){.disabled :is(.start,.content,.end){color:GrayText;opacity:1}}}@layer styles{.label{box-sizing:border-box;color:var(--_label-text-color);overflow:hidden;max-width:100%;text-overflow:ellipsis;white-space:nowrap;z-index:1;font-family:var(--_label-text-font);font-size:var(--_label-text-size);line-height:var(--_label-text-line-height);font-weight:var(--_label-text-weight);width:min-content}.label-wrapper{inset:0;pointer-events:none;position:absolute}.label.resting{position:absolute;top:var(--_top-space)}.label.floating{font-size:var(--_label-text-populated-size);line-height:var(--_label-text-populated-line-height);transform-origin:top left}.label.hidden{opacity:0}.no-label .label{display:none}.label-wrapper{inset:0;position:absolute;text-align:initial}:hover .label{color:var(--_hover-label-text-color)}.focused .label{color:var(--_focus-label-text-color)}.disabled .label{color:var(--_disabled-label-text-color)}.disabled .label:not(.hidden){opacity:var(--_disabled-label-text-opacity)}.error .label{color:var(--_error-label-text-color)}.error:hover .label{color:var(--_error-hover-label-text-color)}.error.focused .label{color:var(--_error-focus-label-text-color)}}@layer hcm{@media(forced-colors: active){.disabled .label:not(.hidden){color:GrayText;opacity:1}}}@layer styles{.supporting-text{color:var(--_supporting-text-color);display:flex;font-family:var(--_supporting-text-font);font-size:var(--_supporting-text-size);line-height:var(--_supporting-text-line-height);font-weight:var(--_supporting-text-weight);gap:16px;justify-content:space-between;padding-inline-start:var(--_supporting-text-leading-space);padding-inline-end:var(--_supporting-text-trailing-space);padding-top:var(--_supporting-text-top-space)}.supporting-text :nth-child(2){flex-shrink:0}:hover .supporting-text{color:var(--_hover-supporting-text-color)}.focus .supporting-text{color:var(--_focus-supporting-text-color)}.disabled .supporting-text{color:var(--_disabled-supporting-text-color);opacity:var(--_disabled-supporting-text-opacity)}.error .supporting-text{color:var(--_error-supporting-text-color)}.error:hover .supporting-text{color:var(--_error-hover-supporting-text-color)}.error.focus .supporting-text{color:var(--_error-focus-supporting-text-color)}}@layer hcm{@media(forced-colors: active){.disabled .supporting-text{color:GrayText;opacity:1}}}
|
|
399
|
+
`;
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* @license
|
|
403
|
+
* Copyright 2021 Google LLC
|
|
404
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
405
|
+
*/
|
|
406
|
+
/**
|
|
407
|
+
* TODO(b/228525797): add docs
|
|
408
|
+
* @final
|
|
409
|
+
* @suppress {visibility}
|
|
410
|
+
*/
|
|
411
|
+
let MdOutlinedField = class MdOutlinedField extends OutlinedField {};
|
|
412
|
+
MdOutlinedField.styles = [styles, styles$1];
|
|
413
|
+
MdOutlinedField = __decorate([t('md-outlined-field')], MdOutlinedField);
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* @license
|
|
417
|
+
* Copyright 2018 Google LLC
|
|
418
|
+
* SPDX-License-Identifier: BSD-3-Clause
|
|
419
|
+
*/
|
|
420
|
+
const n = "important",
|
|
421
|
+
i = " !" + n,
|
|
422
|
+
o = e$2(class extends i$3 {
|
|
423
|
+
constructor(t) {
|
|
424
|
+
var _t$strings;
|
|
425
|
+
if (super(t), t.type !== t$1.ATTRIBUTE || "style" !== t.name || ((_t$strings = t.strings) === null || _t$strings === void 0 ? void 0 : _t$strings.length) > 2) throw Error("The `styleMap` directive must be used in the `style` attribute and must be the only part in the attribute.");
|
|
426
|
+
}
|
|
427
|
+
render(t) {
|
|
428
|
+
return Object.keys(t).reduce((e, r) => {
|
|
429
|
+
const s = t[r];
|
|
430
|
+
return null == s ? e : e + `${r = r.includes("-") ? r : r.replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g, "-$&").toLowerCase()}:${s};`;
|
|
431
|
+
}, "");
|
|
432
|
+
}
|
|
433
|
+
update(e, [r]) {
|
|
434
|
+
const {
|
|
435
|
+
style: s
|
|
436
|
+
} = e.element;
|
|
437
|
+
if (void 0 === this.ft) return this.ft = new Set(Object.keys(r)), this.render(r);
|
|
438
|
+
for (const t of this.ft) null == r[t] && (this.ft.delete(t), t.includes("-") ? s.removeProperty(t) : s[t] = null);
|
|
439
|
+
for (const t in r) {
|
|
440
|
+
const e = r[t];
|
|
441
|
+
if (null != e) {
|
|
442
|
+
this.ft.add(t);
|
|
443
|
+
const r = "string" == typeof e && e.endsWith(i);
|
|
444
|
+
t.includes("-") || r ? s.setProperty(t, r ? e.slice(0, -11) : e, r ? n : "") : s[t] = e;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return E;
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* @license
|
|
453
|
+
* Copyright 2023 Google LLC
|
|
454
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
455
|
+
*/
|
|
456
|
+
/**
|
|
457
|
+
* A symbol property used to create a constraint validation `Validator`.
|
|
458
|
+
* Required for all `mixinConstraintValidation()` elements.
|
|
459
|
+
*/
|
|
460
|
+
const createValidator = Symbol('createValidator');
|
|
461
|
+
/**
|
|
462
|
+
* A symbol property used to return an anchor for constraint validation popups.
|
|
463
|
+
* Required for all `mixinConstraintValidation()` elements.
|
|
464
|
+
*/
|
|
465
|
+
const getValidityAnchor = Symbol('getValidityAnchor');
|
|
466
|
+
// Private symbol members, used to avoid name clashing.
|
|
467
|
+
const privateValidator = Symbol('privateValidator');
|
|
468
|
+
const privateSyncValidity = Symbol('privateSyncValidity');
|
|
469
|
+
const privateCustomValidationMessage = Symbol('privateCustomValidationMessage');
|
|
470
|
+
/**
|
|
471
|
+
* Mixes in constraint validation APIs for an element.
|
|
472
|
+
*
|
|
473
|
+
* See https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation
|
|
474
|
+
* for more details.
|
|
475
|
+
*
|
|
476
|
+
* Implementations must provide a validator to cache and compute its validity,
|
|
477
|
+
* along with a shadow root element to anchor validation popups to.
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* ```ts
|
|
481
|
+
* const baseClass = mixinConstraintValidation(
|
|
482
|
+
* mixinFormAssociated(mixinElementInternals(LitElement))
|
|
483
|
+
* );
|
|
484
|
+
*
|
|
485
|
+
* class MyCheckbox extends baseClass {
|
|
486
|
+
* \@property({type: Boolean}) checked = false;
|
|
487
|
+
* \@property({type: Boolean}) required = false;
|
|
488
|
+
*
|
|
489
|
+
* [createValidator]() {
|
|
490
|
+
* return new CheckboxValidator(() => this);
|
|
491
|
+
* }
|
|
492
|
+
*
|
|
493
|
+
* [getValidityAnchor]() {
|
|
494
|
+
* return this.renderRoot.querySelector('.root');
|
|
495
|
+
* }
|
|
496
|
+
* }
|
|
497
|
+
* ```
|
|
498
|
+
*
|
|
499
|
+
* @param base The class to mix functionality into.
|
|
500
|
+
* @return The provided class with `ConstraintValidation` mixed in.
|
|
501
|
+
*/
|
|
502
|
+
function mixinConstraintValidation(base) {
|
|
503
|
+
var _a;
|
|
504
|
+
class ConstraintValidationElement extends base {
|
|
505
|
+
constructor() {
|
|
506
|
+
super(...arguments);
|
|
507
|
+
/**
|
|
508
|
+
* Needed for Safari, see https://bugs.webkit.org/show_bug.cgi?id=261432
|
|
509
|
+
* Replace with this[internals].validity.customError when resolved.
|
|
510
|
+
*/
|
|
511
|
+
this[_a] = '';
|
|
512
|
+
}
|
|
513
|
+
get validity() {
|
|
514
|
+
this[privateSyncValidity]();
|
|
515
|
+
return this[internals].validity;
|
|
516
|
+
}
|
|
517
|
+
get validationMessage() {
|
|
518
|
+
this[privateSyncValidity]();
|
|
519
|
+
return this[internals].validationMessage;
|
|
520
|
+
}
|
|
521
|
+
get willValidate() {
|
|
522
|
+
this[privateSyncValidity]();
|
|
523
|
+
return this[internals].willValidate;
|
|
524
|
+
}
|
|
525
|
+
checkValidity() {
|
|
526
|
+
this[privateSyncValidity]();
|
|
527
|
+
return this[internals].checkValidity();
|
|
528
|
+
}
|
|
529
|
+
reportValidity() {
|
|
530
|
+
this[privateSyncValidity]();
|
|
531
|
+
return this[internals].reportValidity();
|
|
532
|
+
}
|
|
533
|
+
setCustomValidity(error) {
|
|
534
|
+
this[privateCustomValidationMessage] = error;
|
|
535
|
+
this[privateSyncValidity]();
|
|
536
|
+
}
|
|
537
|
+
requestUpdate(name, oldValue, options) {
|
|
538
|
+
super.requestUpdate(name, oldValue, options);
|
|
539
|
+
this[privateSyncValidity]();
|
|
540
|
+
}
|
|
541
|
+
firstUpdated(changed) {
|
|
542
|
+
super.firstUpdated(changed);
|
|
543
|
+
// Sync the validity again when the element first renders, since the
|
|
544
|
+
// validity anchor is now available.
|
|
545
|
+
//
|
|
546
|
+
// Elements that `delegatesFocus: true` to an `<input>` will throw an
|
|
547
|
+
// error in Chrome and Safari when a form tries to submit or call
|
|
548
|
+
// `form.reportValidity()`:
|
|
549
|
+
// "An invalid form control with name='' is not focusable"
|
|
550
|
+
//
|
|
551
|
+
// The validity anchor MUST be provided in `internals.setValidity()` and
|
|
552
|
+
// MUST be the `<input>` element rendered.
|
|
553
|
+
//
|
|
554
|
+
// See https://lit.dev/playground/#gist=6c26e418e0010f7a5aac15005cde8bde
|
|
555
|
+
// for a reproduction.
|
|
556
|
+
this[privateSyncValidity]();
|
|
557
|
+
}
|
|
558
|
+
[(_a = privateCustomValidationMessage, privateSyncValidity)]() {
|
|
559
|
+
if (!this[privateValidator]) {
|
|
560
|
+
this[privateValidator] = this[createValidator]();
|
|
561
|
+
}
|
|
562
|
+
const {
|
|
563
|
+
validity,
|
|
564
|
+
validationMessage: nonCustomValidationMessage
|
|
565
|
+
} = this[privateValidator].getValidity();
|
|
566
|
+
const customError = !!this[privateCustomValidationMessage];
|
|
567
|
+
const validationMessage = this[privateCustomValidationMessage] || nonCustomValidationMessage;
|
|
568
|
+
this[internals].setValidity({
|
|
569
|
+
...validity,
|
|
570
|
+
customError
|
|
571
|
+
}, validationMessage, this[getValidityAnchor]() ?? undefined);
|
|
572
|
+
}
|
|
573
|
+
[createValidator]() {
|
|
574
|
+
throw new Error('Implement [createValidator]');
|
|
575
|
+
}
|
|
576
|
+
[getValidityAnchor]() {
|
|
577
|
+
throw new Error('Implement [getValidityAnchor]');
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return ConstraintValidationElement;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* @license
|
|
585
|
+
* Copyright 2023 Google LLC
|
|
586
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
587
|
+
*/
|
|
588
|
+
/**
|
|
589
|
+
* A symbol property to retrieve the form value for an element.
|
|
590
|
+
*/
|
|
591
|
+
const getFormValue = Symbol('getFormValue');
|
|
592
|
+
/**
|
|
593
|
+
* A symbol property to retrieve the form state for an element.
|
|
594
|
+
*/
|
|
595
|
+
const getFormState = Symbol('getFormState');
|
|
596
|
+
/**
|
|
597
|
+
* Mixes in form-associated behavior for a class. This allows an element to add
|
|
598
|
+
* values to `<form>` elements.
|
|
599
|
+
*
|
|
600
|
+
* Implementing classes should provide a `[formValue]` to return the current
|
|
601
|
+
* value of the element, as well as reset and restore callbacks.
|
|
602
|
+
*
|
|
603
|
+
* @example
|
|
604
|
+
* ```ts
|
|
605
|
+
* const base = mixinFormAssociated(mixinElementInternals(LitElement));
|
|
606
|
+
*
|
|
607
|
+
* class MyControl extends base {
|
|
608
|
+
* \@property()
|
|
609
|
+
* value = '';
|
|
610
|
+
*
|
|
611
|
+
* override [getFormValue]() {
|
|
612
|
+
* return this.value;
|
|
613
|
+
* }
|
|
614
|
+
*
|
|
615
|
+
* override formResetCallback() {
|
|
616
|
+
* const defaultValue = this.getAttribute('value');
|
|
617
|
+
* this.value = defaultValue;
|
|
618
|
+
* }
|
|
619
|
+
*
|
|
620
|
+
* override formStateRestoreCallback(state: string) {
|
|
621
|
+
* this.value = state;
|
|
622
|
+
* }
|
|
623
|
+
* }
|
|
624
|
+
* ```
|
|
625
|
+
*
|
|
626
|
+
* Elements may optionally provide a `[formState]` if their values do not
|
|
627
|
+
* represent the state of the component.
|
|
628
|
+
*
|
|
629
|
+
* @example
|
|
630
|
+
* ```ts
|
|
631
|
+
* const base = mixinFormAssociated(mixinElementInternals(LitElement));
|
|
632
|
+
*
|
|
633
|
+
* class MyCheckbox extends base {
|
|
634
|
+
* \@property()
|
|
635
|
+
* value = 'on';
|
|
636
|
+
*
|
|
637
|
+
* \@property({type: Boolean})
|
|
638
|
+
* checked = false;
|
|
639
|
+
*
|
|
640
|
+
* override [getFormValue]() {
|
|
641
|
+
* return this.checked ? this.value : null;
|
|
642
|
+
* }
|
|
643
|
+
*
|
|
644
|
+
* override [getFormState]() {
|
|
645
|
+
* return String(this.checked);
|
|
646
|
+
* }
|
|
647
|
+
*
|
|
648
|
+
* override formResetCallback() {
|
|
649
|
+
* const defaultValue = this.hasAttribute('checked');
|
|
650
|
+
* this.checked = defaultValue;
|
|
651
|
+
* }
|
|
652
|
+
*
|
|
653
|
+
* override formStateRestoreCallback(state: string) {
|
|
654
|
+
* this.checked = Boolean(state);
|
|
655
|
+
* }
|
|
656
|
+
* }
|
|
657
|
+
* ```
|
|
658
|
+
*
|
|
659
|
+
* IMPORTANT: Requires declares for lit-analyzer
|
|
660
|
+
* @example
|
|
661
|
+
* ```ts
|
|
662
|
+
* const base = mixinFormAssociated(mixinElementInternals(LitElement));
|
|
663
|
+
* class MyControl extends base {
|
|
664
|
+
* // Writable mixin properties for lit-html binding, needed for lit-analyzer
|
|
665
|
+
* declare disabled: boolean;
|
|
666
|
+
* declare name: string;
|
|
667
|
+
* }
|
|
668
|
+
* ```
|
|
669
|
+
*
|
|
670
|
+
* @param base The class to mix functionality into. The base class must use
|
|
671
|
+
* `mixinElementInternals()`.
|
|
672
|
+
* @return The provided class with `FormAssociated` mixed in.
|
|
673
|
+
*/
|
|
674
|
+
function mixinFormAssociated(base) {
|
|
675
|
+
class FormAssociatedElement extends base {
|
|
676
|
+
get form() {
|
|
677
|
+
return this[internals].form;
|
|
678
|
+
}
|
|
679
|
+
get labels() {
|
|
680
|
+
return this[internals].labels;
|
|
681
|
+
}
|
|
682
|
+
// Use @property for the `name` and `disabled` properties to add them to the
|
|
683
|
+
// `observedAttributes` array and trigger `attributeChangedCallback()`.
|
|
684
|
+
//
|
|
685
|
+
// We don't use Lit's default getter/setter (`noAccessor: true`) because
|
|
686
|
+
// the attributes need to be updated synchronously to work with synchronous
|
|
687
|
+
// form APIs, and Lit updates attributes async by default.
|
|
688
|
+
get name() {
|
|
689
|
+
return this.getAttribute('name') ?? '';
|
|
690
|
+
}
|
|
691
|
+
set name(name) {
|
|
692
|
+
// Note: setting name to null or empty does not remove the attribute.
|
|
693
|
+
this.setAttribute('name', name);
|
|
694
|
+
// We don't need to call `requestUpdate()` since it's called synchronously
|
|
695
|
+
// in `attributeChangedCallback()`.
|
|
696
|
+
}
|
|
697
|
+
get disabled() {
|
|
698
|
+
return this.hasAttribute('disabled');
|
|
699
|
+
}
|
|
700
|
+
set disabled(disabled) {
|
|
701
|
+
this.toggleAttribute('disabled', disabled);
|
|
702
|
+
// We don't need to call `requestUpdate()` since it's called synchronously
|
|
703
|
+
// in `attributeChangedCallback()`.
|
|
704
|
+
}
|
|
705
|
+
attributeChangedCallback(name, old, value) {
|
|
706
|
+
// Manually `requestUpdate()` for `name` and `disabled` when their
|
|
707
|
+
// attribute or property changes.
|
|
708
|
+
// The properties update their attributes, so this callback is invoked
|
|
709
|
+
// immediately when the properties are set. We call `requestUpdate()` here
|
|
710
|
+
// instead of letting Lit set the properties from the attribute change.
|
|
711
|
+
// That would cause the properties to re-set the attribute and invoke this
|
|
712
|
+
// callback again in a loop. This leads to stale state when Lit tries to
|
|
713
|
+
// determine if a property changed or not.
|
|
714
|
+
if (name === 'name' || name === 'disabled') {
|
|
715
|
+
// Disabled's value is only false if the attribute is missing and null.
|
|
716
|
+
const oldValue = name === 'disabled' ? old !== null : old;
|
|
717
|
+
// Trigger a lit update when the attribute changes.
|
|
718
|
+
this.requestUpdate(name, oldValue);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
super.attributeChangedCallback(name, old, value);
|
|
722
|
+
}
|
|
723
|
+
requestUpdate(name, oldValue, options) {
|
|
724
|
+
super.requestUpdate(name, oldValue, options);
|
|
725
|
+
// If any properties change, update the form value, which may have changed
|
|
726
|
+
// as well.
|
|
727
|
+
// Update the form value synchronously in `requestUpdate()` rather than
|
|
728
|
+
// `update()` or `updated()`, which are async. This is necessary to ensure
|
|
729
|
+
// that form data is updated in time for synchronous event listeners.
|
|
730
|
+
this[internals].setFormValue(this[getFormValue](), this[getFormState]());
|
|
731
|
+
}
|
|
732
|
+
[getFormValue]() {
|
|
733
|
+
// Closure does not allow abstract symbol members, so a default
|
|
734
|
+
// implementation is needed.
|
|
735
|
+
throw new Error('Implement [getFormValue]');
|
|
736
|
+
}
|
|
737
|
+
[getFormState]() {
|
|
738
|
+
return this[getFormValue]();
|
|
739
|
+
}
|
|
740
|
+
formDisabledCallback(disabled) {
|
|
741
|
+
this.disabled = disabled;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
/** @nocollapse */
|
|
745
|
+
FormAssociatedElement.formAssociated = true;
|
|
746
|
+
__decorate([n$1({
|
|
747
|
+
noAccessor: true
|
|
748
|
+
})], FormAssociatedElement.prototype, "name", null);
|
|
749
|
+
__decorate([n$1({
|
|
750
|
+
type: Boolean,
|
|
751
|
+
noAccessor: true
|
|
752
|
+
})], FormAssociatedElement.prototype, "disabled", null);
|
|
753
|
+
return FormAssociatedElement;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* @license
|
|
758
|
+
* Copyright 2023 Google LLC
|
|
759
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
760
|
+
*/
|
|
761
|
+
/**
|
|
762
|
+
* A symbol property used for a callback when validity has been reported.
|
|
763
|
+
*/
|
|
764
|
+
const onReportValidity = Symbol('onReportValidity');
|
|
765
|
+
// Private symbol members, used to avoid name clashing.
|
|
766
|
+
const privateCleanupFormListeners = Symbol('privateCleanupFormListeners');
|
|
767
|
+
const privateDoNotReportInvalid = Symbol('privateDoNotReportInvalid');
|
|
768
|
+
const privateIsSelfReportingValidity = Symbol('privateIsSelfReportingValidity');
|
|
769
|
+
const privateCallOnReportValidity = Symbol('privateCallOnReportValidity');
|
|
770
|
+
/**
|
|
771
|
+
* Mixes in a callback for constraint validation when validity should be
|
|
772
|
+
* styled and reported to the user.
|
|
773
|
+
*
|
|
774
|
+
* This is commonly used in text-field-like controls that display error styles
|
|
775
|
+
* and error messages.
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* ```ts
|
|
779
|
+
* const baseClass = mixinOnReportValidity(
|
|
780
|
+
* mixinConstraintValidation(
|
|
781
|
+
* mixinFormAssociated(mixinElementInternals(LitElement)),
|
|
782
|
+
* ),
|
|
783
|
+
* );
|
|
784
|
+
*
|
|
785
|
+
* class MyField extends baseClass {
|
|
786
|
+
* \@property({type: Boolean}) error = false;
|
|
787
|
+
* \@property() errorMessage = '';
|
|
788
|
+
*
|
|
789
|
+
* [onReportValidity](invalidEvent: Event | null) {
|
|
790
|
+
* this.error = !!invalidEvent;
|
|
791
|
+
* this.errorMessage = this.validationMessage;
|
|
792
|
+
*
|
|
793
|
+
* // Optionally prevent platform popup from displaying
|
|
794
|
+
* invalidEvent?.preventDefault();
|
|
795
|
+
* }
|
|
796
|
+
* }
|
|
797
|
+
* ```
|
|
798
|
+
*
|
|
799
|
+
* @param base The class to mix functionality into.
|
|
800
|
+
* @return The provided class with `OnReportValidity` mixed in.
|
|
801
|
+
*/
|
|
802
|
+
function mixinOnReportValidity(base) {
|
|
803
|
+
var _a, _b, _c;
|
|
804
|
+
class OnReportValidityElement extends base {
|
|
805
|
+
// Mixins must have a constructor with `...args: any[]`
|
|
806
|
+
// tslint:disable-next-line:no-any
|
|
807
|
+
constructor(...args) {
|
|
808
|
+
super(...args);
|
|
809
|
+
/**
|
|
810
|
+
* Used to clean up event listeners when a new form is associated.
|
|
811
|
+
*/
|
|
812
|
+
this[_a] = new AbortController();
|
|
813
|
+
/**
|
|
814
|
+
* Used to determine if an invalid event should report validity. Invalid
|
|
815
|
+
* events from `checkValidity()` do not trigger reporting.
|
|
816
|
+
*/
|
|
817
|
+
this[_b] = false;
|
|
818
|
+
/**
|
|
819
|
+
* Used to determine if the control is reporting validity from itself, or
|
|
820
|
+
* if a `<form>` is causing the validity report. Forms have different
|
|
821
|
+
* control focusing behavior.
|
|
822
|
+
*/
|
|
823
|
+
this[_c] = false;
|
|
824
|
+
this.addEventListener('invalid', invalidEvent => {
|
|
825
|
+
// Listen for invalid events dispatched by a `<form>` when it tries to
|
|
826
|
+
// submit and the element is invalid. We ignore events dispatched when
|
|
827
|
+
// calling `checkValidity()` as well as untrusted events, since the
|
|
828
|
+
// `reportValidity()` and `<form>`-dispatched events are always
|
|
829
|
+
// trusted.
|
|
830
|
+
if (this[privateDoNotReportInvalid] || !invalidEvent.isTrusted) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
this.addEventListener('invalid', () => {
|
|
834
|
+
// A normal bubbling phase event listener. By adding it here, we
|
|
835
|
+
// ensure it's the last event listener that is called during the
|
|
836
|
+
// bubbling phase.
|
|
837
|
+
this[privateCallOnReportValidity](invalidEvent);
|
|
838
|
+
}, {
|
|
839
|
+
once: true
|
|
840
|
+
});
|
|
841
|
+
}, {
|
|
842
|
+
// Listen during the capture phase, which will happen before the
|
|
843
|
+
// bubbling phase. That way, we can add a final event listener that
|
|
844
|
+
// will run after other event listeners, and we can check if it was
|
|
845
|
+
// default prevented. This works because invalid does not bubble.
|
|
846
|
+
capture: true
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
checkValidity() {
|
|
850
|
+
this[privateDoNotReportInvalid] = true;
|
|
851
|
+
const valid = super.checkValidity();
|
|
852
|
+
this[privateDoNotReportInvalid] = false;
|
|
853
|
+
return valid;
|
|
854
|
+
}
|
|
855
|
+
reportValidity() {
|
|
856
|
+
this[privateIsSelfReportingValidity] = true;
|
|
857
|
+
const valid = super.reportValidity();
|
|
858
|
+
// Constructor's invalid listener will handle reporting invalid events.
|
|
859
|
+
if (valid) {
|
|
860
|
+
this[privateCallOnReportValidity](null);
|
|
861
|
+
}
|
|
862
|
+
this[privateIsSelfReportingValidity] = false;
|
|
863
|
+
return valid;
|
|
864
|
+
}
|
|
865
|
+
[(_a = privateCleanupFormListeners, _b = privateDoNotReportInvalid, _c = privateIsSelfReportingValidity, privateCallOnReportValidity)](invalidEvent) {
|
|
866
|
+
// Since invalid events do not bubble to parent listeners, and because
|
|
867
|
+
// our invalid listeners are added lazily after other listeners, we can
|
|
868
|
+
// reliably read `defaultPrevented` synchronously without worrying
|
|
869
|
+
// about waiting for another listener that could cancel it.
|
|
870
|
+
const wasCanceled = invalidEvent === null || invalidEvent === void 0 ? void 0 : invalidEvent.defaultPrevented;
|
|
871
|
+
if (wasCanceled) {
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
this[onReportValidity](invalidEvent);
|
|
875
|
+
// If an implementation calls invalidEvent.preventDefault() to stop the
|
|
876
|
+
// platform popup from displaying, focusing is also prevented, so we need
|
|
877
|
+
// to manually focus.
|
|
878
|
+
const implementationCanceledFocus = !wasCanceled && (invalidEvent === null || invalidEvent === void 0 ? void 0 : invalidEvent.defaultPrevented);
|
|
879
|
+
if (!implementationCanceledFocus) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
// The control should be focused when:
|
|
883
|
+
// - `control.reportValidity()` is called (self-reporting).
|
|
884
|
+
// - a form is reporting validity for its controls and this is the first
|
|
885
|
+
// invalid control.
|
|
886
|
+
if (this[privateIsSelfReportingValidity] || isFirstInvalidControlInForm(this[internals].form, this)) {
|
|
887
|
+
this.focus();
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
[onReportValidity](invalidEvent) {
|
|
891
|
+
throw new Error('Implement [onReportValidity]');
|
|
892
|
+
}
|
|
893
|
+
formAssociatedCallback(form) {
|
|
894
|
+
// can't use super.formAssociatedCallback?.() due to closure
|
|
895
|
+
if (super.formAssociatedCallback) {
|
|
896
|
+
super.formAssociatedCallback(form);
|
|
897
|
+
}
|
|
898
|
+
// Clean up previous form listeners.
|
|
899
|
+
this[privateCleanupFormListeners].abort();
|
|
900
|
+
if (!form) {
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
this[privateCleanupFormListeners] = new AbortController();
|
|
904
|
+
// Add a listener that fires when the form runs constraint validation and
|
|
905
|
+
// the control is valid, so that it may remove its error styles.
|
|
906
|
+
//
|
|
907
|
+
// This happens on `form.reportValidity()` and `form.requestSubmit()`
|
|
908
|
+
// (both when the submit fails and passes).
|
|
909
|
+
addFormReportValidListener(this, form, () => {
|
|
910
|
+
this[privateCallOnReportValidity](null);
|
|
911
|
+
}, this[privateCleanupFormListeners].signal);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
return OnReportValidityElement;
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Add a listener that fires when a form runs constraint validation on a control
|
|
918
|
+
* and it is valid. This is needed to clear previously invalid styles.
|
|
919
|
+
*
|
|
920
|
+
* @param control The control of the form to listen for valid events.
|
|
921
|
+
* @param form The control's form that can run constraint validation.
|
|
922
|
+
* @param onControlValid A listener that is called when the form runs constraint
|
|
923
|
+
* validation and the control is valid.
|
|
924
|
+
* @param cleanup A cleanup signal to remove the listener.
|
|
925
|
+
*/
|
|
926
|
+
function addFormReportValidListener(control, form, onControlValid, cleanup) {
|
|
927
|
+
const validateHooks = getFormValidateHooks(form);
|
|
928
|
+
// When a form validates its controls, check if an invalid event is dispatched
|
|
929
|
+
// on the control. If it is not, then inform the control to report its valid
|
|
930
|
+
// state.
|
|
931
|
+
let controlFiredInvalid = false;
|
|
932
|
+
let cleanupInvalidListener;
|
|
933
|
+
let isNextSubmitFromHook = false;
|
|
934
|
+
validateHooks.addEventListener('before', () => {
|
|
935
|
+
isNextSubmitFromHook = true;
|
|
936
|
+
cleanupInvalidListener = new AbortController();
|
|
937
|
+
controlFiredInvalid = false;
|
|
938
|
+
control.addEventListener('invalid', () => {
|
|
939
|
+
controlFiredInvalid = true;
|
|
940
|
+
}, {
|
|
941
|
+
signal: cleanupInvalidListener.signal
|
|
942
|
+
});
|
|
943
|
+
}, {
|
|
944
|
+
signal: cleanup
|
|
945
|
+
});
|
|
946
|
+
validateHooks.addEventListener('after', () => {
|
|
947
|
+
var _cleanupInvalidListen;
|
|
948
|
+
isNextSubmitFromHook = false;
|
|
949
|
+
(_cleanupInvalidListen = cleanupInvalidListener) === null || _cleanupInvalidListen === void 0 || _cleanupInvalidListen.abort();
|
|
950
|
+
if (controlFiredInvalid) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
onControlValid();
|
|
954
|
+
}, {
|
|
955
|
+
signal: cleanup
|
|
956
|
+
});
|
|
957
|
+
// The above hooks handle imperatively submitting the form, but not
|
|
958
|
+
// declaratively submitting the form. This happens when:
|
|
959
|
+
// 1. A non-custom element `<button type="submit">` is clicked.
|
|
960
|
+
// 2. Enter is pressed on a non-custom element text editable `<input>`.
|
|
961
|
+
form.addEventListener('submit', () => {
|
|
962
|
+
// This submit was from `form.requestSubmit()`, which already calls the
|
|
963
|
+
// listener.
|
|
964
|
+
if (isNextSubmitFromHook) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
onControlValid();
|
|
968
|
+
}, {
|
|
969
|
+
signal: cleanup
|
|
970
|
+
});
|
|
971
|
+
// Note: it is a known limitation that we cannot detect if a form tries to
|
|
972
|
+
// submit declaratively, but fails to do so because an unrelated sibling
|
|
973
|
+
// control failed its constraint validation.
|
|
974
|
+
//
|
|
975
|
+
// Since we cannot detect when that happens, a previously invalid control may
|
|
976
|
+
// not clear its error styling when it becomes valid again.
|
|
977
|
+
//
|
|
978
|
+
// To work around this, call `form.reportValidity()` when submitting a form
|
|
979
|
+
// declaratively. This can be down on the `<button type="submit">`'s click or
|
|
980
|
+
// the text editable `<input>`'s 'Enter' keydown.
|
|
981
|
+
}
|
|
982
|
+
const FORM_VALIDATE_HOOKS = new WeakMap();
|
|
983
|
+
/**
|
|
984
|
+
* Get a hooks `EventTarget` that dispatches 'before' and 'after' events that
|
|
985
|
+
* fire before a form runs constraint validation and immediately after it
|
|
986
|
+
* finishes running constraint validation on its controls.
|
|
987
|
+
*
|
|
988
|
+
* This happens during `form.reportValidity()` and `form.requestSubmit()`.
|
|
989
|
+
*
|
|
990
|
+
* @param form The form to get or set up hooks for.
|
|
991
|
+
* @return A hooks `EventTarget` to add listeners to.
|
|
992
|
+
*/
|
|
993
|
+
function getFormValidateHooks(form) {
|
|
994
|
+
if (!FORM_VALIDATE_HOOKS.has(form)) {
|
|
995
|
+
// Patch form methods to add event listener hooks. These are needed to react
|
|
996
|
+
// to form behaviors that do not dispatch events, such as a form asking its
|
|
997
|
+
// controls to report their validity.
|
|
998
|
+
//
|
|
999
|
+
// We should only patch the methods once, since multiple controls and other
|
|
1000
|
+
// forces may want to patch this method. We cannot reliably clean it up if
|
|
1001
|
+
// there are multiple patched and re-patched methods referring holding
|
|
1002
|
+
// references to each other.
|
|
1003
|
+
//
|
|
1004
|
+
// Instead, we never clean up the patch but add and clean up event listeners
|
|
1005
|
+
// added to the hooks after the patch.
|
|
1006
|
+
const hooks = new EventTarget();
|
|
1007
|
+
FORM_VALIDATE_HOOKS.set(form, hooks);
|
|
1008
|
+
// Add hooks to support notifying before and after a form has run constraint
|
|
1009
|
+
// validation on its controls.
|
|
1010
|
+
// Note: `form.submit()` does not run constraint validation per spec.
|
|
1011
|
+
for (const methodName of ['reportValidity', 'requestSubmit']) {
|
|
1012
|
+
const superMethod = form[methodName];
|
|
1013
|
+
form[methodName] = function () {
|
|
1014
|
+
hooks.dispatchEvent(new Event('before'));
|
|
1015
|
+
const result = Reflect.apply(superMethod, this, arguments);
|
|
1016
|
+
hooks.dispatchEvent(new Event('after'));
|
|
1017
|
+
return result;
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return FORM_VALIDATE_HOOKS.get(form);
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Checks if a control is the first invalid control in a form.
|
|
1025
|
+
*
|
|
1026
|
+
* @param form The control's form. When `null`, the control doesn't have a form
|
|
1027
|
+
* and the method returns true.
|
|
1028
|
+
* @param control The control to check.
|
|
1029
|
+
* @return True if there is no form or if the control is the form's first
|
|
1030
|
+
* invalid control.
|
|
1031
|
+
*/
|
|
1032
|
+
function isFirstInvalidControlInForm(form, control) {
|
|
1033
|
+
if (!form) {
|
|
1034
|
+
return true;
|
|
1035
|
+
}
|
|
1036
|
+
let firstInvalidControl;
|
|
1037
|
+
for (const element of form.elements) {
|
|
1038
|
+
if (element.matches(':invalid')) {
|
|
1039
|
+
firstInvalidControl = element;
|
|
1040
|
+
break;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
return firstInvalidControl === control;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* @license
|
|
1048
|
+
* Copyright 2023 Google LLC
|
|
1049
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1050
|
+
*/
|
|
1051
|
+
/**
|
|
1052
|
+
* A class that computes and caches `ValidityStateFlags` for a component with
|
|
1053
|
+
* a given `State` interface.
|
|
1054
|
+
*
|
|
1055
|
+
* Cached performance before computing validity is important since constraint
|
|
1056
|
+
* validation must be checked frequently and synchronously when properties
|
|
1057
|
+
* change.
|
|
1058
|
+
*
|
|
1059
|
+
* @template State The expected interface of properties relevant to constraint
|
|
1060
|
+
* validation.
|
|
1061
|
+
*/
|
|
1062
|
+
class Validator {
|
|
1063
|
+
/**
|
|
1064
|
+
* Creates a new validator.
|
|
1065
|
+
*
|
|
1066
|
+
* @param getCurrentState A callback that returns the current state of
|
|
1067
|
+
* constraint validation-related properties.
|
|
1068
|
+
*/
|
|
1069
|
+
constructor(getCurrentState) {
|
|
1070
|
+
this.getCurrentState = getCurrentState;
|
|
1071
|
+
/**
|
|
1072
|
+
* The current validity state and message. This is cached and returns if
|
|
1073
|
+
* constraint validation state does not change.
|
|
1074
|
+
*/
|
|
1075
|
+
this.currentValidity = {
|
|
1076
|
+
validity: {},
|
|
1077
|
+
validationMessage: ''
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Returns the current `ValidityStateFlags` and validation message for the
|
|
1082
|
+
* validator.
|
|
1083
|
+
*
|
|
1084
|
+
* If the constraint validation state has not changed, this will return a
|
|
1085
|
+
* cached result. This is important since `getValidity()` can be called
|
|
1086
|
+
* frequently in response to synchronous property changes.
|
|
1087
|
+
*
|
|
1088
|
+
* @return The current validity and validation message.
|
|
1089
|
+
*/
|
|
1090
|
+
getValidity() {
|
|
1091
|
+
const state = this.getCurrentState();
|
|
1092
|
+
const hasStateChanged = !this.prevState || !this.equals(this.prevState, state);
|
|
1093
|
+
if (!hasStateChanged) {
|
|
1094
|
+
return this.currentValidity;
|
|
1095
|
+
}
|
|
1096
|
+
const {
|
|
1097
|
+
validity,
|
|
1098
|
+
validationMessage
|
|
1099
|
+
} = this.computeValidity(state);
|
|
1100
|
+
this.prevState = this.copy(state);
|
|
1101
|
+
this.currentValidity = {
|
|
1102
|
+
validationMessage,
|
|
1103
|
+
validity: {
|
|
1104
|
+
// Change any `ValidityState` instances into `ValidityStateFlags` since
|
|
1105
|
+
// `ValidityState` cannot be easily `{...spread}`.
|
|
1106
|
+
badInput: validity.badInput,
|
|
1107
|
+
customError: validity.customError,
|
|
1108
|
+
patternMismatch: validity.patternMismatch,
|
|
1109
|
+
rangeOverflow: validity.rangeOverflow,
|
|
1110
|
+
rangeUnderflow: validity.rangeUnderflow,
|
|
1111
|
+
stepMismatch: validity.stepMismatch,
|
|
1112
|
+
tooLong: validity.tooLong,
|
|
1113
|
+
tooShort: validity.tooShort,
|
|
1114
|
+
typeMismatch: validity.typeMismatch,
|
|
1115
|
+
valueMissing: validity.valueMissing
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
return this.currentValidity;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
export { Validator as V, mixinConstraintValidation as a, mixinFormAssociated as b, onReportValidity as c, createValidator as d, getValidityAnchor as e, getFormValue as g, mixinOnReportValidity as m, o };
|