@ponchia/ui 0.6.8 → 0.6.10
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/CHANGELOG.md +79 -4
- package/README.md +2 -2
- package/annotations/index.d.ts.map +1 -1
- package/annotations/index.js +5 -6
- package/behaviors/carousel.d.ts.map +1 -1
- package/behaviors/carousel.js +100 -60
- package/behaviors/combobox.d.ts.map +1 -1
- package/behaviors/combobox.js +167 -113
- package/behaviors/connectors.d.ts.map +1 -1
- package/behaviors/connectors.js +39 -23
- package/behaviors/forms.d.ts.map +1 -1
- package/behaviors/forms.js +211 -207
- package/behaviors/glyph.d.ts.map +1 -1
- package/behaviors/glyph.js +157 -132
- package/behaviors/inert.d.ts +1 -1
- package/behaviors/inert.d.ts.map +1 -1
- package/behaviors/inert.js +1 -1
- package/behaviors/internal.js +2 -2
- package/behaviors/modal.js +1 -1
- package/behaviors/popover.js +5 -5
- package/behaviors/table.d.ts +1 -1
- package/behaviors/table.d.ts.map +1 -1
- package/behaviors/table.js +7 -8
- package/behaviors/tabs.js +2 -2
- package/behaviors/toast.js +5 -5
- package/classes/classes.json +33 -2
- package/classes/index.d.ts +10 -0
- package/classes/index.js +59 -35
- package/connectors/index.d.ts +2 -2
- package/connectors/index.d.ts.map +1 -1
- package/connectors/index.js +7 -10
- package/css/app.css +3 -4
- package/css/base.css +1 -1
- package/css/content.css +3 -3
- package/css/disclosure.css +3 -3
- package/css/dots.css +4 -4
- package/css/feedback.css +6 -7
- package/css/forms.css +9 -12
- package/css/legend.css +1 -1
- package/css/marks.css +1 -1
- package/css/motion.css +6 -6
- package/css/overlay.css +5 -7
- package/css/primitives.css +14 -16
- package/css/sidenote.css +2 -2
- package/css/table.css +2 -2
- package/css/workbench.css +128 -0
- package/dist/css/workbench.css +1 -1
- package/docs/annotations.md +36 -0
- package/docs/architecture.md +28 -0
- package/docs/interop/react-flow.md +89 -0
- package/docs/package-contract.md +2 -0
- package/docs/reference.md +21 -1
- package/docs/reporting.md +8 -8
- package/docs/stability.md +67 -7
- package/docs/workbench.md +56 -9
- package/glyphs/glyphs.js +43 -33
- package/llms.txt +10 -4
- package/package.json +5 -2
- package/schemas/report-claims.v1.schema.json +1 -1
- package/tokens/index.js +2 -2
package/behaviors/forms.js
CHANGED
|
@@ -1,5 +1,196 @@
|
|
|
1
1
|
import { hasDom, resolveHost, noop, bindOnce, nextFieldUid, collectHosts } from './internal.js';
|
|
2
2
|
|
|
3
|
+
function snapshotAttrs(el, names) {
|
|
4
|
+
const out = {};
|
|
5
|
+
for (const name of names) {
|
|
6
|
+
out[name] = {
|
|
7
|
+
had: el.hasAttribute(name),
|
|
8
|
+
value: el.getAttribute(name),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function restoreAttrs(el, attrs) {
|
|
15
|
+
for (const [name, attr] of Object.entries(attrs)) {
|
|
16
|
+
if (attr.had) el.setAttribute(name, attr.value);
|
|
17
|
+
else el.removeAttribute(name);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createValidationState() {
|
|
22
|
+
return {
|
|
23
|
+
priorNoValidate: new Map(),
|
|
24
|
+
controlState: new Map(),
|
|
25
|
+
slotState: new Map(),
|
|
26
|
+
summaryState: new Map(),
|
|
27
|
+
// Borrowed `.ui-hint` help text is restored after an invalid field becomes valid.
|
|
28
|
+
hintHelp: new WeakMap(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function suppressNativeValidation(form, state) {
|
|
33
|
+
if (!state.priorNoValidate.has(form)) state.priorNoValidate.set(form, form.noValidate);
|
|
34
|
+
form.noValidate = true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function rememberControl(control, state) {
|
|
38
|
+
if (!state.controlState.has(control)) {
|
|
39
|
+
state.controlState.set(
|
|
40
|
+
control,
|
|
41
|
+
snapshotAttrs(control, ['aria-invalid', 'aria-describedby', 'id']),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function rememberSlot(slot, state) {
|
|
47
|
+
if (!state.slotState.has(slot)) {
|
|
48
|
+
state.slotState.set(slot, {
|
|
49
|
+
attrs: snapshotAttrs(slot, ['id']),
|
|
50
|
+
text: slot.textContent,
|
|
51
|
+
hadErrorClass: slot.classList.contains('ui-hint--error'),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function rememberSummary(summary, state) {
|
|
57
|
+
if (!state.summaryState.has(summary)) {
|
|
58
|
+
state.summaryState.set(summary, {
|
|
59
|
+
attrs: snapshotAttrs(summary, ['role', 'tabindex']),
|
|
60
|
+
children: [...summary.childNodes],
|
|
61
|
+
hidden: summary.hidden,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function ensureId(el, prefix) {
|
|
67
|
+
if (!el.id) el.id = `${prefix}-${nextFieldUid()}`;
|
|
68
|
+
return el.id;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function slotFor(control) {
|
|
72
|
+
const field = control.closest('.ui-field');
|
|
73
|
+
if (!field) return null;
|
|
74
|
+
const dedicated = field.querySelector('[data-bronto-error]');
|
|
75
|
+
if (dedicated) return dedicated;
|
|
76
|
+
return field.querySelector('.ui-hint');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function link(control, slot) {
|
|
80
|
+
const slotId = ensureId(slot, 'bronto-err');
|
|
81
|
+
const ids = (control.getAttribute('aria-describedby') || '').split(/\s+/).filter(Boolean);
|
|
82
|
+
if (!ids.includes(slotId)) {
|
|
83
|
+
ids.push(slotId);
|
|
84
|
+
control.setAttribute('aria-describedby', ids.join(' '));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function unlink(control, slot) {
|
|
89
|
+
if (!slot.id) return;
|
|
90
|
+
const ids = (control.getAttribute('aria-describedby') || '')
|
|
91
|
+
.split(/\s+/)
|
|
92
|
+
.filter((id) => id && id !== slot.id);
|
|
93
|
+
if (ids.length) control.setAttribute('aria-describedby', ids.join(' '));
|
|
94
|
+
else control.removeAttribute('aria-describedby');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function slotKind(slot) {
|
|
98
|
+
// Decide the slot TYPE by `[data-bronto-error]`, not by `.ui-hint`: canonical
|
|
99
|
+
// dedicated error markup can carry both.
|
|
100
|
+
const dedicated = !!slot?.matches?.('[data-bronto-error]');
|
|
101
|
+
const hasHintClass = !!slot?.classList.contains('ui-hint');
|
|
102
|
+
return { hasHintClass, borrowedHint: hasHintClass && !dedicated };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function clearFieldError(control, slot, kind, state) {
|
|
106
|
+
control.removeAttribute('aria-invalid');
|
|
107
|
+
if (!slot) return;
|
|
108
|
+
if (kind.hasHintClass) slot.classList.remove('ui-hint--error');
|
|
109
|
+
if (kind.borrowedHint) {
|
|
110
|
+
slot.textContent = state.hintHelp.get(slot) ?? '';
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
slot.textContent = '';
|
|
114
|
+
unlink(control, slot);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function showFieldError(control, slot, kind, state) {
|
|
118
|
+
control.setAttribute('aria-invalid', 'true');
|
|
119
|
+
if (!slot) return;
|
|
120
|
+
if (kind.borrowedHint && !state.hintHelp.has(slot)) state.hintHelp.set(slot, slot.textContent);
|
|
121
|
+
slot.textContent = control.validationMessage;
|
|
122
|
+
if (kind.hasHintClass) slot.classList.add('ui-hint--error');
|
|
123
|
+
link(control, slot);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function validateField(control, state) {
|
|
127
|
+
if (!control.willValidate) return true;
|
|
128
|
+
rememberControl(control, state);
|
|
129
|
+
const ok = control.validity.valid;
|
|
130
|
+
const slot = slotFor(control);
|
|
131
|
+
if (slot) rememberSlot(slot, state);
|
|
132
|
+
const kind = slotKind(slot);
|
|
133
|
+
if (ok) clearFieldError(control, slot, kind, state);
|
|
134
|
+
else showFieldError(control, slot, kind, state);
|
|
135
|
+
return ok;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function controlsOf(form) {
|
|
139
|
+
return [...form.elements].filter(
|
|
140
|
+
(el) => el.willValidate && el.type !== 'submit' && el.type !== 'button',
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function summaryItem(control) {
|
|
145
|
+
const id = ensureId(control, 'bronto-field');
|
|
146
|
+
const li = document.createElement('li');
|
|
147
|
+
const a = document.createElement('a');
|
|
148
|
+
a.href = `#${id}`;
|
|
149
|
+
a.textContent = control.validationMessage;
|
|
150
|
+
a.addEventListener('click', (e) => {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
control.focus();
|
|
153
|
+
});
|
|
154
|
+
li.appendChild(a);
|
|
155
|
+
return li;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function refreshSummary(form, invalid, state) {
|
|
159
|
+
const summary = form.querySelector('[data-bronto-error-summary]');
|
|
160
|
+
if (!summary) return;
|
|
161
|
+
rememberSummary(summary, state);
|
|
162
|
+
if (!invalid.length) {
|
|
163
|
+
summary.hidden = true;
|
|
164
|
+
summary.replaceChildren();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const title = document.createElement('p');
|
|
168
|
+
title.className = 'ui-error-summary__title';
|
|
169
|
+
title.textContent = 'There is a problem';
|
|
170
|
+
const list = document.createElement('ul');
|
|
171
|
+
list.className = 'ui-error-summary__list';
|
|
172
|
+
list.append(...invalid.map(summaryItem));
|
|
173
|
+
summary.replaceChildren(title, list);
|
|
174
|
+
summary.setAttribute('role', 'alert');
|
|
175
|
+
summary.tabIndex = -1;
|
|
176
|
+
summary.hidden = false;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function restoreValidationState(state) {
|
|
180
|
+
for (const [form, noValidate] of state.priorNoValidate) form.noValidate = noValidate;
|
|
181
|
+
for (const [summary, snapshot] of state.summaryState) {
|
|
182
|
+
summary.replaceChildren(...snapshot.children);
|
|
183
|
+
summary.hidden = snapshot.hidden;
|
|
184
|
+
restoreAttrs(summary, snapshot.attrs);
|
|
185
|
+
}
|
|
186
|
+
for (const [slot, snapshot] of state.slotState) {
|
|
187
|
+
slot.textContent = snapshot.text;
|
|
188
|
+
slot.classList.toggle('ui-hint--error', snapshot.hadErrorClass);
|
|
189
|
+
restoreAttrs(slot, snapshot.attrs);
|
|
190
|
+
}
|
|
191
|
+
for (const [control, attrs] of state.controlState) restoreAttrs(control, attrs);
|
|
192
|
+
}
|
|
193
|
+
|
|
3
194
|
/**
|
|
4
195
|
* Accessible form validation glue for `<form data-bronto-validate>`.
|
|
5
196
|
* Progressive enhancement over the native Constraint Validation API —
|
|
@@ -29,206 +220,36 @@ export function initFormValidation({ root } = {}) {
|
|
|
29
220
|
if (!hasDom()) return noop;
|
|
30
221
|
const host = resolveHost(root);
|
|
31
222
|
if (!host) return noop;
|
|
32
|
-
let
|
|
33
|
-
let controlState = new Map();
|
|
34
|
-
let slotState = new Map();
|
|
35
|
-
let summaryState = new Map();
|
|
36
|
-
|
|
37
|
-
const suppressNativeValidation = (form) => {
|
|
38
|
-
if (!priorNoValidate.has(form)) priorNoValidate.set(form, form.noValidate);
|
|
39
|
-
form.noValidate = true;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const snapshotAttrs = (el, names) => {
|
|
43
|
-
const out = {};
|
|
44
|
-
for (const name of names) {
|
|
45
|
-
out[name] = {
|
|
46
|
-
had: el.hasAttribute(name),
|
|
47
|
-
value: el.getAttribute(name),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
return out;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const restoreAttrs = (el, attrs) => {
|
|
54
|
-
for (const [name, attr] of Object.entries(attrs)) {
|
|
55
|
-
if (attr.had) el.setAttribute(name, attr.value);
|
|
56
|
-
else el.removeAttribute(name);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const rememberControl = (control) => {
|
|
61
|
-
if (!controlState.has(control)) {
|
|
62
|
-
controlState.set(control, snapshotAttrs(control, ['aria-invalid', 'aria-describedby', 'id']));
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const rememberSlot = (slot) => {
|
|
67
|
-
if (!slotState.has(slot)) {
|
|
68
|
-
slotState.set(slot, {
|
|
69
|
-
attrs: snapshotAttrs(slot, ['id']),
|
|
70
|
-
text: slot.textContent,
|
|
71
|
-
hadErrorClass: slot.classList.contains('ui-hint--error'),
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const rememberSummary = (summary) => {
|
|
77
|
-
if (!summaryState.has(summary)) {
|
|
78
|
-
summaryState.set(summary, {
|
|
79
|
-
attrs: snapshotAttrs(summary, ['role', 'tabindex']),
|
|
80
|
-
children: [...summary.childNodes],
|
|
81
|
-
hidden: summary.hidden,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const ensureId = (el, prefix) => {
|
|
87
|
-
if (!el.id) el.id = `${prefix}-${nextFieldUid()}`;
|
|
88
|
-
return el.id;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// When the field has no dedicated `[data-bronto-error]` node we fall back to
|
|
92
|
-
// the shared `.ui-hint` help slot. Snapshot its original help text the first
|
|
93
|
-
// time we overwrite it with an error, so the valid branch can RESTORE the help
|
|
94
|
-
// rather than blanking it permanently (component-audit C8).
|
|
95
|
-
const hintHelp = new WeakMap();
|
|
96
|
-
|
|
97
|
-
const slotFor = (control) => {
|
|
98
|
-
const field = control.closest('.ui-field');
|
|
99
|
-
if (!field) return null;
|
|
100
|
-
const dedicated = field.querySelector('[data-bronto-error]');
|
|
101
|
-
if (dedicated) return dedicated;
|
|
102
|
-
return field.querySelector('.ui-hint');
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const link = (control, slot) => {
|
|
106
|
-
const slotId = ensureId(slot, 'bronto-err');
|
|
107
|
-
const ids = (control.getAttribute('aria-describedby') || '').split(/\s+/).filter(Boolean);
|
|
108
|
-
if (!ids.includes(slotId)) {
|
|
109
|
-
ids.push(slotId);
|
|
110
|
-
control.setAttribute('aria-describedby', ids.join(' '));
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const unlink = (control, slot) => {
|
|
115
|
-
if (!slot.id) return;
|
|
116
|
-
const ids = (control.getAttribute('aria-describedby') || '')
|
|
117
|
-
.split(/\s+/)
|
|
118
|
-
.filter((id) => id && id !== slot.id);
|
|
119
|
-
if (ids.length) control.setAttribute('aria-describedby', ids.join(' '));
|
|
120
|
-
else control.removeAttribute('aria-describedby');
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const validateField = (control) => {
|
|
124
|
-
if (!control.willValidate) return true;
|
|
125
|
-
rememberControl(control);
|
|
126
|
-
const ok = control.validity.valid;
|
|
127
|
-
const slot = slotFor(control);
|
|
128
|
-
if (slot) rememberSlot(slot);
|
|
129
|
-
// Decide the slot TYPE by the `[data-bronto-error]` attribute, NOT the
|
|
130
|
-
// `.ui-hint` class: the canonical markup is `<p class="ui-hint"
|
|
131
|
-
// data-bronto-error>`, which carries BOTH. Keying off `.ui-hint` sent that
|
|
132
|
-
// dedicated error node down the help-hint branch, which never unlink()s — so
|
|
133
|
-
// the field kept a dangling aria-describedby to an empty error node after it
|
|
134
|
-
// was fixed (component-audit C6). Only a *borrowed* plain `.ui-hint` (a help
|
|
135
|
-
// slot with no dedicated error node) snapshots/restores its help text and
|
|
136
|
-
// stays linked in the valid state.
|
|
137
|
-
const dedicated = !!slot?.matches?.('[data-bronto-error]');
|
|
138
|
-
const hasHintClass = !!slot?.classList.contains('ui-hint');
|
|
139
|
-
const borrowedHint = hasHintClass && !dedicated;
|
|
140
|
-
if (ok) {
|
|
141
|
-
control.removeAttribute('aria-invalid');
|
|
142
|
-
if (slot) {
|
|
143
|
-
if (hasHintClass) slot.classList.remove('ui-hint--error');
|
|
144
|
-
if (borrowedHint) {
|
|
145
|
-
// Restore the snapshotted help text (or clear if there was none); a
|
|
146
|
-
// help-bearing hint stays linked via aria-describedby (it describes
|
|
147
|
-
// the field in the valid state too).
|
|
148
|
-
slot.textContent = hintHelp.get(slot) ?? '';
|
|
149
|
-
} else {
|
|
150
|
-
// Dedicated error node: clear it and drop the now-stale describedby
|
|
151
|
-
// so AT doesn't announce an empty error association.
|
|
152
|
-
slot.textContent = '';
|
|
153
|
-
unlink(control, slot);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
} else {
|
|
157
|
-
control.setAttribute('aria-invalid', 'true');
|
|
158
|
-
if (slot) {
|
|
159
|
-
if (borrowedHint && !hintHelp.has(slot)) hintHelp.set(slot, slot.textContent);
|
|
160
|
-
slot.textContent = control.validationMessage;
|
|
161
|
-
if (hasHintClass) slot.classList.add('ui-hint--error');
|
|
162
|
-
link(control, slot);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return ok;
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
const controlsOf = (form) =>
|
|
169
|
-
[...form.elements].filter(
|
|
170
|
-
(el) => el.willValidate && el.type !== 'submit' && el.type !== 'button',
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
const refreshSummary = (form, invalid) => {
|
|
174
|
-
const summary = form.querySelector('[data-bronto-error-summary]');
|
|
175
|
-
if (!summary) return;
|
|
176
|
-
rememberSummary(summary);
|
|
177
|
-
if (!invalid.length) {
|
|
178
|
-
summary.hidden = true;
|
|
179
|
-
summary.replaceChildren();
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
const title = document.createElement('p');
|
|
183
|
-
title.className = 'ui-error-summary__title';
|
|
184
|
-
title.textContent = 'There is a problem';
|
|
185
|
-
const list = document.createElement('ul');
|
|
186
|
-
list.className = 'ui-error-summary__list';
|
|
187
|
-
for (const c of invalid) {
|
|
188
|
-
const id = ensureId(c, 'bronto-field');
|
|
189
|
-
const li = document.createElement('li');
|
|
190
|
-
const a = document.createElement('a');
|
|
191
|
-
a.href = `#${id}`;
|
|
192
|
-
a.textContent = c.validationMessage;
|
|
193
|
-
a.addEventListener('click', (e) => {
|
|
194
|
-
e.preventDefault();
|
|
195
|
-
c.focus();
|
|
196
|
-
});
|
|
197
|
-
li.appendChild(a);
|
|
198
|
-
list.appendChild(li);
|
|
199
|
-
}
|
|
200
|
-
summary.replaceChildren(title, list);
|
|
201
|
-
summary.setAttribute('role', 'alert');
|
|
202
|
-
summary.tabIndex = -1;
|
|
203
|
-
summary.hidden = false;
|
|
204
|
-
};
|
|
223
|
+
let state = createValidationState();
|
|
205
224
|
|
|
206
|
-
const onSubmit = (
|
|
207
|
-
const form =
|
|
225
|
+
const onSubmit = (event) => {
|
|
226
|
+
const form = event.target.closest?.('[data-bronto-validate]');
|
|
208
227
|
if (!form) return;
|
|
209
|
-
suppressNativeValidation(form);
|
|
210
|
-
const invalid = controlsOf(form).filter((
|
|
211
|
-
refreshSummary(form, invalid);
|
|
228
|
+
suppressNativeValidation(form, state);
|
|
229
|
+
const invalid = controlsOf(form).filter((control) => !validateField(control, state));
|
|
230
|
+
refreshSummary(form, invalid, state);
|
|
212
231
|
if (invalid.length) {
|
|
213
|
-
|
|
232
|
+
event.preventDefault();
|
|
214
233
|
const summary = form.querySelector('[data-bronto-error-summary]');
|
|
215
234
|
(summary && !summary.hidden ? summary : invalid[0]).focus();
|
|
216
235
|
}
|
|
217
236
|
};
|
|
218
237
|
|
|
219
|
-
const onBlur = (
|
|
220
|
-
const control =
|
|
238
|
+
const onBlur = (event) => {
|
|
239
|
+
const control = event.target;
|
|
221
240
|
if (!control.willValidate) return;
|
|
222
241
|
const form = control.closest?.('[data-bronto-validate]');
|
|
223
242
|
if (!form) return;
|
|
224
|
-
suppressNativeValidation(form);
|
|
225
|
-
validateField(control);
|
|
243
|
+
suppressNativeValidation(form, state);
|
|
244
|
+
validateField(control, state);
|
|
226
245
|
const summary = form.querySelector('[data-bronto-error-summary]');
|
|
227
|
-
if (summary && !summary.hidden)
|
|
246
|
+
if (summary && !summary.hidden) {
|
|
228
247
|
refreshSummary(
|
|
229
248
|
form,
|
|
230
|
-
controlsOf(form).filter((
|
|
249
|
+
controlsOf(form).filter((candidate) => !candidate.validity.valid),
|
|
250
|
+
state,
|
|
231
251
|
);
|
|
252
|
+
}
|
|
232
253
|
};
|
|
233
254
|
|
|
234
255
|
return bindOnce(host, 'formValidation', () => {
|
|
@@ -239,34 +260,17 @@ export function initFormValidation({ root } = {}) {
|
|
|
239
260
|
// summary — contradicting the documented contract. (Forms added
|
|
240
261
|
// after init are still covered by the in-handler set.)
|
|
241
262
|
const forms = collectHosts(host, '[data-bronto-validate]');
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
summaryState = new Map();
|
|
246
|
-
for (const f of forms) {
|
|
247
|
-
suppressNativeValidation(f);
|
|
263
|
+
state = createValidationState();
|
|
264
|
+
for (const form of forms) {
|
|
265
|
+
suppressNativeValidation(form, state);
|
|
248
266
|
}
|
|
249
267
|
host.addEventListener('submit', onSubmit, true);
|
|
250
268
|
host.addEventListener('focusout', onBlur);
|
|
251
269
|
return () => {
|
|
252
270
|
host.removeEventListener('submit', onSubmit, true);
|
|
253
271
|
host.removeEventListener('focusout', onBlur);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
for (const [summary, state] of summaryState) {
|
|
257
|
-
summary.replaceChildren(...state.children);
|
|
258
|
-
summary.hidden = state.hidden;
|
|
259
|
-
restoreAttrs(summary, state.attrs);
|
|
260
|
-
}
|
|
261
|
-
summaryState.clear();
|
|
262
|
-
for (const [slot, state] of slotState) {
|
|
263
|
-
slot.textContent = state.text;
|
|
264
|
-
slot.classList.toggle('ui-hint--error', state.hadErrorClass);
|
|
265
|
-
restoreAttrs(slot, state.attrs);
|
|
266
|
-
}
|
|
267
|
-
slotState.clear();
|
|
268
|
-
for (const [control, attrs] of controlState) restoreAttrs(control, attrs);
|
|
269
|
-
controlState.clear();
|
|
272
|
+
restoreValidationState(state);
|
|
273
|
+
state = createValidationState();
|
|
270
274
|
};
|
|
271
275
|
});
|
|
272
276
|
}
|
package/behaviors/glyph.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["glyph.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"glyph.d.ts","sourceRoot":"","sources":["glyph.js"],"names":[],"mappings":"AAwLA;;;;;;;;;;;;;;;;;;GAkBG;AACH,wCAHW,OAAO,eAAe,EAAE,YAAY,GAClC,OAAO,eAAe,EAAE,OAAO,CAwB3C"}
|