@italia/radio 0.1.0-alpha.2
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/AUTHORS +3 -0
- package/LICENSE +11 -0
- package/README.md +106 -0
- package/custom-elements.json +852 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/it-radio-group.d.ts +117 -0
- package/dist/src/it-radio-group.d.ts.map +1 -0
- package/dist/src/it-radio-group.js +1725 -0
- package/dist/src/it-radio-group.js.map +1 -0
- package/dist/src/it-radio.d.ts +70 -0
- package/dist/src/it-radio.d.ts.map +1 -0
- package/dist/src/it-radio.js +1459 -0
- package/dist/src/it-radio.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,1725 @@
|
|
|
1
|
+
import { _ as __decorate, a as __metadata, F as FormControl, b as FormControlController } from '../form-control-CdxVvcex.js';
|
|
2
|
+
import { css, html } from 'lit';
|
|
3
|
+
import { property, queryAssignedElements, state, customElement } from 'lit/decorators.js';
|
|
4
|
+
import 'lit/directive.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Roving Tabindex Controller
|
|
8
|
+
*
|
|
9
|
+
* Implements the ARIA roving tabindex pattern for keyboard navigation.
|
|
10
|
+
* See: https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_roving_tabindex
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```ts
|
|
14
|
+
* private rovingTabindex = new RovingTabindexController(this, {
|
|
15
|
+
* getItems: () => Array.from(this.querySelectorAll('my-item')),
|
|
16
|
+
* onSelect: (item) => this.selectItem(item),
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
class RovingTabindexController {
|
|
21
|
+
constructor(host, config) {
|
|
22
|
+
this.host = host;
|
|
23
|
+
this.config = {
|
|
24
|
+
wrap: true,
|
|
25
|
+
direction: 'both',
|
|
26
|
+
selectOnFocus: false,
|
|
27
|
+
skipItem: (item) => item.hasAttribute('disabled') || item.disabled === true,
|
|
28
|
+
...config,
|
|
29
|
+
};
|
|
30
|
+
host.addController(this);
|
|
31
|
+
}
|
|
32
|
+
// eslint-disable-next-line class-methods-use-this
|
|
33
|
+
hostConnected() {
|
|
34
|
+
// Controller is ready when host connects
|
|
35
|
+
}
|
|
36
|
+
// eslint-disable-next-line class-methods-use-this
|
|
37
|
+
hostDisconnected() {
|
|
38
|
+
// Cleanup if needed
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Update tabindex values for all items
|
|
42
|
+
* @param activeIndex - Index of the item that should be tabbable (default: 0 or first non-disabled)
|
|
43
|
+
*/
|
|
44
|
+
updateTabindices(activeIndex) {
|
|
45
|
+
const items = this.config.getItems();
|
|
46
|
+
if (!items || items.length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// Find the active index
|
|
50
|
+
let targetIndex = activeIndex ?? 0;
|
|
51
|
+
// If no active index specified, use first non-disabled item
|
|
52
|
+
if (activeIndex === undefined) {
|
|
53
|
+
targetIndex = items.findIndex((item) => !this.config.skipItem(item));
|
|
54
|
+
if (targetIndex === -1) {
|
|
55
|
+
targetIndex = 0; // Fallback to first item if all disabled
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Set tabindex for all items
|
|
59
|
+
items.forEach((item, index) => {
|
|
60
|
+
const itemElement = item;
|
|
61
|
+
if (this.config.skipItem(itemElement)) {
|
|
62
|
+
// eslint-disable-next-line no-param-reassign
|
|
63
|
+
itemElement.tabIndex = -1;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// eslint-disable-next-line no-param-reassign
|
|
67
|
+
itemElement.tabIndex = index === targetIndex ? 0 : -1;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Handle keyboard navigation
|
|
73
|
+
* @param currentItem - The currently focused item
|
|
74
|
+
* @param event - The keyboard event
|
|
75
|
+
* @returns true if the event was handled, false otherwise
|
|
76
|
+
*/
|
|
77
|
+
handleKeydown(currentItem, event) {
|
|
78
|
+
const { direction } = this.config;
|
|
79
|
+
const { key } = event;
|
|
80
|
+
// Determine if this key should be handled based on direction
|
|
81
|
+
const isVertical = key === 'ArrowUp' || key === 'ArrowDown';
|
|
82
|
+
const isHorizontal = key === 'ArrowLeft' || key === 'ArrowRight';
|
|
83
|
+
const isHome = key === 'Home';
|
|
84
|
+
const isEnd = key === 'End';
|
|
85
|
+
const shouldHandle = isHome ||
|
|
86
|
+
isEnd ||
|
|
87
|
+
(direction === 'both' && (isVertical || isHorizontal)) ||
|
|
88
|
+
(direction === 'vertical' && isVertical) ||
|
|
89
|
+
(direction === 'horizontal' && isHorizontal);
|
|
90
|
+
if (!shouldHandle) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// Prevent default behavior (page scrolling)
|
|
94
|
+
event.preventDefault();
|
|
95
|
+
const items = this.config.getItems();
|
|
96
|
+
const currentIndex = items.indexOf(currentItem);
|
|
97
|
+
if (currentIndex === -1) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
let nextIndex = currentIndex;
|
|
101
|
+
// Handle Home/End keys
|
|
102
|
+
if (isHome) {
|
|
103
|
+
nextIndex = 0;
|
|
104
|
+
}
|
|
105
|
+
else if (isEnd) {
|
|
106
|
+
nextIndex = items.length - 1;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Handle arrow keys
|
|
110
|
+
const isNext = key === 'ArrowDown' || key === 'ArrowRight';
|
|
111
|
+
const isPrev = key === 'ArrowUp' || key === 'ArrowLeft';
|
|
112
|
+
if (isNext) {
|
|
113
|
+
nextIndex = this.getNextIndex(items, currentIndex, 1);
|
|
114
|
+
}
|
|
115
|
+
else if (isPrev) {
|
|
116
|
+
nextIndex = this.getNextIndex(items, currentIndex, -1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Skip disabled items
|
|
120
|
+
nextIndex = this.findNextValidIndex(items, nextIndex, nextIndex > currentIndex ? 1 : -1);
|
|
121
|
+
if (nextIndex !== -1 && nextIndex !== currentIndex) {
|
|
122
|
+
const nextItem = items[nextIndex];
|
|
123
|
+
// Update tabindices
|
|
124
|
+
this.updateTabindices(nextIndex);
|
|
125
|
+
// Focus the next item
|
|
126
|
+
nextItem.focus();
|
|
127
|
+
// Optionally select/activate the item
|
|
128
|
+
if (this.config.selectOnFocus && this.config.onSelect) {
|
|
129
|
+
this.config.onSelect(nextItem, event);
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the next index based on direction
|
|
137
|
+
*/
|
|
138
|
+
getNextIndex(items, currentIndex, direction) {
|
|
139
|
+
const { wrap } = this.config;
|
|
140
|
+
let nextIndex = currentIndex + direction;
|
|
141
|
+
if (wrap) {
|
|
142
|
+
// Wrap around
|
|
143
|
+
if (nextIndex < 0) {
|
|
144
|
+
nextIndex = items.length - 1;
|
|
145
|
+
}
|
|
146
|
+
else if (nextIndex >= items.length) {
|
|
147
|
+
nextIndex = 0;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Clamp to bounds
|
|
152
|
+
nextIndex = Math.max(0, Math.min(items.length - 1, nextIndex));
|
|
153
|
+
}
|
|
154
|
+
return nextIndex;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Find the next valid (non-disabled) index
|
|
158
|
+
*/
|
|
159
|
+
findNextValidIndex(items, startIndex, direction) {
|
|
160
|
+
const maxAttempts = items.length;
|
|
161
|
+
let attempts = 0;
|
|
162
|
+
let index = startIndex;
|
|
163
|
+
while (attempts < maxAttempts) {
|
|
164
|
+
if (!this.config.skipItem(items[index])) {
|
|
165
|
+
return index;
|
|
166
|
+
}
|
|
167
|
+
index = this.getNextIndex(items, index, direction);
|
|
168
|
+
attempts += 1;
|
|
169
|
+
}
|
|
170
|
+
// All items are disabled
|
|
171
|
+
return -1;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Set focus to a specific item
|
|
175
|
+
*/
|
|
176
|
+
focusItem(item) {
|
|
177
|
+
const items = this.config.getItems();
|
|
178
|
+
const index = items.indexOf(item);
|
|
179
|
+
if (index !== -1) {
|
|
180
|
+
this.updateTabindices(index);
|
|
181
|
+
item.focus();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Set focus to the first non-disabled item
|
|
186
|
+
*/
|
|
187
|
+
focusFirst() {
|
|
188
|
+
const items = this.config.getItems();
|
|
189
|
+
const firstValidIndex = this.findNextValidIndex(items, 0, 1);
|
|
190
|
+
if (firstValidIndex !== -1) {
|
|
191
|
+
this.focusItem(items[firstValidIndex]);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Set focus to the last non-disabled item
|
|
196
|
+
*/
|
|
197
|
+
focusLast() {
|
|
198
|
+
const items = this.config.getItems();
|
|
199
|
+
const lastValidIndex = this.findNextValidIndex(items, items.length - 1, -1);
|
|
200
|
+
if (lastValidIndex !== -1) {
|
|
201
|
+
this.focusItem(items[lastValidIndex]);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
var styles = css`/***************************** 1 ****************************************/
|
|
207
|
+
/***************************** 2 ****************************************/
|
|
208
|
+
/***************************** 1 ****************************************/
|
|
209
|
+
/***************************** 2 ****************************************/
|
|
210
|
+
/***************************** 1 ****************************************/
|
|
211
|
+
/***************************** 2 ****************************************/
|
|
212
|
+
/***************************** 3 ****************************************/
|
|
213
|
+
/***************************** 1 ****************************************/
|
|
214
|
+
/***************************** 2 ****************************************/
|
|
215
|
+
/***************************** 3 ****************************************/
|
|
216
|
+
/***************************** NEUTRAL 1 ****************************************/
|
|
217
|
+
/***************************** NEUTRAL 2 ****************************************/
|
|
218
|
+
/***************************** NEUTRAL 2 / 3 ****************************************/
|
|
219
|
+
.form-check [type=checkbox]:focus + label,
|
|
220
|
+
.form-check [type=radio]:focus + label {
|
|
221
|
+
border-color: hsl(0, 0%, 0%) !important;
|
|
222
|
+
box-shadow: 0 0 0 2px var(--bs-color-border-inverse), 0 0 0 5px var(--bs-color-outline-focus) !important;
|
|
223
|
+
outline: 3px solid transparent !important;
|
|
224
|
+
outline-offset: 3px !important;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.form-check [type=checkbox]:focus[data-focus-mouse=true] + label,
|
|
228
|
+
.form-check [type=radio]:focus[data-focus-mouse=true] + label {
|
|
229
|
+
border-color: inherit !important;
|
|
230
|
+
box-shadow: none !important;
|
|
231
|
+
outline: none !important;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
*,
|
|
235
|
+
*::before,
|
|
236
|
+
*::after {
|
|
237
|
+
box-sizing: border-box;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
241
|
+
:root {
|
|
242
|
+
scroll-behavior: smooth;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
body {
|
|
247
|
+
margin: 0;
|
|
248
|
+
-webkit-text-size-adjust: 100%;
|
|
249
|
+
-webkit-tap-highlight-color: hsla(0, 0%, 0%, 0);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
hr {
|
|
253
|
+
margin: 1rem 0;
|
|
254
|
+
color: inherit;
|
|
255
|
+
border: 0;
|
|
256
|
+
border-top: 1px solid;
|
|
257
|
+
opacity: 0.25;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
p {
|
|
261
|
+
margin-top: 0;
|
|
262
|
+
margin-bottom: var(--bs-paragraph-spacing);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
abbr[title] {
|
|
266
|
+
text-decoration: underline dotted;
|
|
267
|
+
cursor: help;
|
|
268
|
+
text-decoration-skip-ink: none;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
address {
|
|
272
|
+
margin-bottom: var(--bs-spacing-s);
|
|
273
|
+
font-style: normal;
|
|
274
|
+
line-height: inherit;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
ol,
|
|
278
|
+
ul {
|
|
279
|
+
padding-left: var(--bs-spacing-l);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
ol,
|
|
283
|
+
ul,
|
|
284
|
+
dl {
|
|
285
|
+
margin-top: 0;
|
|
286
|
+
margin-bottom: var(--bs-spacing-s);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
ol ol,
|
|
290
|
+
ul ul,
|
|
291
|
+
ol ul,
|
|
292
|
+
ul ol {
|
|
293
|
+
margin-bottom: 0;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
dt {
|
|
297
|
+
font-weight: var(--bs-font-weight-strong);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
dd {
|
|
301
|
+
margin-bottom: var(--bs-spacing-xxs);
|
|
302
|
+
margin-left: 0;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
blockquote {
|
|
306
|
+
margin: 0 0 var(--bs-spacing-s);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
sub,
|
|
310
|
+
sup {
|
|
311
|
+
position: relative;
|
|
312
|
+
font-size: var(--bs-font-size-1);
|
|
313
|
+
line-height: 0;
|
|
314
|
+
vertical-align: baseline;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
sub {
|
|
318
|
+
bottom: -0.25em;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
sup {
|
|
322
|
+
top: -0.5em;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
a {
|
|
326
|
+
color: var(--bs-color-link);
|
|
327
|
+
text-decoration: underline;
|
|
328
|
+
text-decoration-skip-ink: auto;
|
|
329
|
+
text-underline-offset: 2px;
|
|
330
|
+
}
|
|
331
|
+
a:hover {
|
|
332
|
+
color: var(--bs-color-link-hover);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
a:not([href]):not([class]), a:not([href]):not([class]):hover {
|
|
336
|
+
color: inherit;
|
|
337
|
+
text-decoration: none;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
pre,
|
|
341
|
+
code,
|
|
342
|
+
kbd,
|
|
343
|
+
samp {
|
|
344
|
+
font-size: 1em;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
pre {
|
|
348
|
+
display: block;
|
|
349
|
+
margin-top: 0;
|
|
350
|
+
margin-bottom: var(--bs-paragraph-spacing);
|
|
351
|
+
overflow: auto;
|
|
352
|
+
}
|
|
353
|
+
pre code {
|
|
354
|
+
word-break: normal;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
a > code {
|
|
358
|
+
color: inherit;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
figure {
|
|
362
|
+
margin: 0 0 1rem;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
img,
|
|
366
|
+
svg {
|
|
367
|
+
vertical-align: middle;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
table {
|
|
371
|
+
caption-side: bottom;
|
|
372
|
+
border-collapse: collapse;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
caption {
|
|
376
|
+
padding-top: 0.5rem;
|
|
377
|
+
padding-bottom: 0.5rem;
|
|
378
|
+
color: hsl(210, 17%, 44%);
|
|
379
|
+
text-align: left;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
th {
|
|
383
|
+
text-align: inherit;
|
|
384
|
+
text-align: -webkit-match-parent;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
thead,
|
|
388
|
+
tbody,
|
|
389
|
+
tfoot,
|
|
390
|
+
tr,
|
|
391
|
+
td,
|
|
392
|
+
th {
|
|
393
|
+
border-color: inherit;
|
|
394
|
+
border-style: solid;
|
|
395
|
+
border-width: 0;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
label {
|
|
399
|
+
display: inline-block;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
button {
|
|
403
|
+
border-radius: 0;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
button:focus:not(:focus-visible) {
|
|
407
|
+
outline: 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
input,
|
|
411
|
+
button,
|
|
412
|
+
select,
|
|
413
|
+
optgroup,
|
|
414
|
+
textarea {
|
|
415
|
+
margin: 0;
|
|
416
|
+
font-family: inherit;
|
|
417
|
+
font-size: inherit;
|
|
418
|
+
line-height: inherit;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
button,
|
|
422
|
+
select {
|
|
423
|
+
text-transform: none;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
[role=button] {
|
|
427
|
+
cursor: pointer;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
select {
|
|
431
|
+
word-wrap: normal;
|
|
432
|
+
}
|
|
433
|
+
select:disabled {
|
|
434
|
+
opacity: 1;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
|
|
438
|
+
display: none !important;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
button,
|
|
442
|
+
[type=button],
|
|
443
|
+
[type=reset],
|
|
444
|
+
[type=submit] {
|
|
445
|
+
-webkit-appearance: button;
|
|
446
|
+
}
|
|
447
|
+
button:not(:disabled),
|
|
448
|
+
[type=button]:not(:disabled),
|
|
449
|
+
[type=reset]:not(:disabled),
|
|
450
|
+
[type=submit]:not(:disabled) {
|
|
451
|
+
cursor: pointer;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
::-moz-focus-inner {
|
|
455
|
+
padding: 0;
|
|
456
|
+
border-style: none;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
textarea {
|
|
460
|
+
resize: vertical;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
fieldset {
|
|
464
|
+
min-width: 0;
|
|
465
|
+
padding: 0;
|
|
466
|
+
margin: 0;
|
|
467
|
+
border: 0;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
::-webkit-datetime-edit-fields-wrapper,
|
|
471
|
+
::-webkit-datetime-edit-text,
|
|
472
|
+
::-webkit-datetime-edit-minute,
|
|
473
|
+
::-webkit-datetime-edit-hour-field,
|
|
474
|
+
::-webkit-datetime-edit-day-field,
|
|
475
|
+
::-webkit-datetime-edit-month-field,
|
|
476
|
+
::-webkit-datetime-edit-year-field {
|
|
477
|
+
padding: 0;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
::-webkit-inner-spin-button {
|
|
481
|
+
height: auto;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
[type=search] {
|
|
485
|
+
outline-offset: -2px;
|
|
486
|
+
-webkit-appearance: textfield;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* rtl:raw:
|
|
490
|
+
[type="tel"],
|
|
491
|
+
[type="url"],
|
|
492
|
+
[type="email"],
|
|
493
|
+
[type="number"] {
|
|
494
|
+
direction: ltr;
|
|
495
|
+
}
|
|
496
|
+
*/
|
|
497
|
+
::-webkit-search-decoration {
|
|
498
|
+
-webkit-appearance: none;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
::-webkit-color-swatch-wrapper {
|
|
502
|
+
padding: 0;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
::file-selector-button {
|
|
506
|
+
font: inherit;
|
|
507
|
+
-webkit-appearance: button;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
output {
|
|
511
|
+
display: inline-block;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
iframe {
|
|
515
|
+
border: 0;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
summary {
|
|
519
|
+
display: list-item;
|
|
520
|
+
cursor: pointer;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
progress {
|
|
524
|
+
vertical-align: baseline;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
[hidden] {
|
|
528
|
+
display: none !important;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.visually-hidden,
|
|
532
|
+
.visually-hidden-focusable:not(:focus):not(:focus-within) {
|
|
533
|
+
position: absolute !important;
|
|
534
|
+
width: 1px !important;
|
|
535
|
+
height: 1px !important;
|
|
536
|
+
padding: 0 !important;
|
|
537
|
+
margin: -1px !important;
|
|
538
|
+
overflow: hidden !important;
|
|
539
|
+
clip: rect(0, 0, 0, 0) !important;
|
|
540
|
+
white-space: nowrap !important;
|
|
541
|
+
border: 0 !important;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
:root {
|
|
545
|
+
--bs-form-control-height: 2.5rem;
|
|
546
|
+
--bs-form-control-spacing: var(--bs-spacing-xxs);
|
|
547
|
+
--bs-form-control-background-color: var(--bs-color-background-inverse);
|
|
548
|
+
--bs-form-control-border-color: var(--bs-color-border-secondary);
|
|
549
|
+
--bs-form-control-border-radius: var(--bs-radius-smooth);
|
|
550
|
+
--bs-form-control-placeholder-color: var(--bs-color-text-muted);
|
|
551
|
+
--bs-form-control-label-color: var(--bs-color-text-base);
|
|
552
|
+
--bs-form-control-text-color: var(--bs-color-text-secondary);
|
|
553
|
+
--bs-form-control-font-size: var(--bs-body-font-size);
|
|
554
|
+
--bs-form-group-spacing-y: var(--bs-spacing-m);
|
|
555
|
+
--bs-form-checkbox-border-color: var(--bs-color-border-secondary);
|
|
556
|
+
--bs-form-checkbox-border-radius: var(--bs-radius-smooth);
|
|
557
|
+
--bs-form-checked-color: var(--bs-color-background-primary);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
input[readonly],
|
|
561
|
+
textarea[readonly],
|
|
562
|
+
select[readonly] {
|
|
563
|
+
--bs-form-control-border-color: var(--bs-color-border-subtle);
|
|
564
|
+
--bs-form-control-background-color: var(--bs-color-background-muted);
|
|
565
|
+
cursor: not-allowed;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
input,
|
|
569
|
+
textarea,
|
|
570
|
+
select {
|
|
571
|
+
display: block;
|
|
572
|
+
width: 100%;
|
|
573
|
+
padding: var(--bs-form-control-spacing);
|
|
574
|
+
border: 1px solid var(--bs-form-control-border-color);
|
|
575
|
+
border-radius: var(--bs-form-control-border-radius);
|
|
576
|
+
background-color: var(--bs-form-control-background-color);
|
|
577
|
+
color: var(--bs-form-control-text-color);
|
|
578
|
+
font-size: var(--bs-form-control-font-size);
|
|
579
|
+
}
|
|
580
|
+
input.disabled, input:disabled,
|
|
581
|
+
textarea.disabled,
|
|
582
|
+
textarea:disabled,
|
|
583
|
+
select.disabled,
|
|
584
|
+
select:disabled {
|
|
585
|
+
border-color: var(--bs-color-border-disabled);
|
|
586
|
+
opacity: 1;
|
|
587
|
+
background-color: var(--bs-color-background-disabled);
|
|
588
|
+
color: var(--bs-color-text-disabled);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
input:focus,
|
|
592
|
+
textarea:focus {
|
|
593
|
+
outline: 3px solid transparent;
|
|
594
|
+
outline-offset: 3px;
|
|
595
|
+
box-shadow: 0 0 0 2px var(--bs-color-border-inverse), 0 0 0 5px var(--bs-color-outline-focus) !important;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
input::file-selector-button {
|
|
599
|
+
margin: -0.375rem -0.75rem;
|
|
600
|
+
padding: 0.375rem 0.75rem;
|
|
601
|
+
border-width: 0;
|
|
602
|
+
border-style: solid;
|
|
603
|
+
border-radius: 0;
|
|
604
|
+
border-color: inherit;
|
|
605
|
+
color: hsl(0, 0%, 10%);
|
|
606
|
+
pointer-events: none;
|
|
607
|
+
margin-inline-end: 0.75rem;
|
|
608
|
+
border-inline-end-width: 0;
|
|
609
|
+
background-color: hsl(0, 0%, 100%);
|
|
610
|
+
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
|
611
|
+
}
|
|
612
|
+
@media (prefers-reduced-motion: reduce) {
|
|
613
|
+
input::file-selector-button {
|
|
614
|
+
transition: none;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
input:hover:not(:disabled):not([readonly])::file-selector-button {
|
|
618
|
+
background-color: rgb(242.25, 242.25, 242.25);
|
|
619
|
+
}
|
|
620
|
+
input[type=file] {
|
|
621
|
+
overflow: hidden;
|
|
622
|
+
}
|
|
623
|
+
input[type=file]:not(:disabled):not([readonly]) {
|
|
624
|
+
cursor: pointer;
|
|
625
|
+
}
|
|
626
|
+
input::-webkit-date-and-time-value {
|
|
627
|
+
height: 1.5em;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
select {
|
|
631
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='hsl%280, 0%, 15%%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
|
|
632
|
+
background-repeat: no-repeat;
|
|
633
|
+
background-position: right var(--bs-form-control-spacing) center;
|
|
634
|
+
background-size: 16px 12px;
|
|
635
|
+
appearance: none;
|
|
636
|
+
}
|
|
637
|
+
select:focus {
|
|
638
|
+
border-color: hsl(210, 17%, 44%);
|
|
639
|
+
outline: 0;
|
|
640
|
+
box-shadow: 0 0 0 0.25rem rgba(0, 102, 204, 0.25);
|
|
641
|
+
}
|
|
642
|
+
select[multiple], select[size]:not([size="1"]) {
|
|
643
|
+
padding-right: 0.75rem;
|
|
644
|
+
background-image: none;
|
|
645
|
+
}
|
|
646
|
+
select:disabled {
|
|
647
|
+
background-color: hsl(0, 0%, 90%);
|
|
648
|
+
}
|
|
649
|
+
select:disabled:hover {
|
|
650
|
+
cursor: not-allowed;
|
|
651
|
+
}
|
|
652
|
+
select:-moz-focusring {
|
|
653
|
+
color: transparent;
|
|
654
|
+
text-shadow: 0 0 0 hsl(0, 0%, 10%);
|
|
655
|
+
}
|
|
656
|
+
select option {
|
|
657
|
+
font-weight: normal;
|
|
658
|
+
}
|
|
659
|
+
select:disabled {
|
|
660
|
+
opacity: 1;
|
|
661
|
+
background-color: hsl(210, 3%, 85%);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
textarea {
|
|
665
|
+
height: auto;
|
|
666
|
+
font-size: var(--bs-body-font-size);
|
|
667
|
+
line-height: 1.5;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
label {
|
|
671
|
+
display: inline-block;
|
|
672
|
+
width: auto;
|
|
673
|
+
max-width: 100%;
|
|
674
|
+
margin-bottom: var(--bs-spacing-xxs);
|
|
675
|
+
color: var(--bs-form-control-label-color);
|
|
676
|
+
font-size: var(--bs-label-font-size-s);
|
|
677
|
+
font-weight: var(--bs-font-weight-solid);
|
|
678
|
+
line-height: var(--bs-label-line-height);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
input,
|
|
682
|
+
textarea {
|
|
683
|
+
outline: 0;
|
|
684
|
+
box-shadow: none;
|
|
685
|
+
transition: none;
|
|
686
|
+
appearance: none;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
input[type=date],
|
|
690
|
+
input[type=datetime-local],
|
|
691
|
+
input[type=time] {
|
|
692
|
+
display: flex;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
fieldset legend {
|
|
696
|
+
margin-bottom: var(--bs-spacing-s);
|
|
697
|
+
padding: 0 var(--bs-form-input-spacing-x);
|
|
698
|
+
background-color: transparent;
|
|
699
|
+
color: var(--bs-form-control-text-color);
|
|
700
|
+
font-size: var(--bs-label-sm);
|
|
701
|
+
font-weight: var(--bs-font-weight-solid);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
::placeholder {
|
|
705
|
+
color: var(--bs-form-control-placeholder-color);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
input::-webkit-datetime-edit {
|
|
709
|
+
background-color: var(--bs-color-background-primary-lighter);
|
|
710
|
+
color: var(--bs-form-contro-text-color);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.form-group {
|
|
714
|
+
position: relative;
|
|
715
|
+
margin-bottom: var(--bs-form-group-spacing-y);
|
|
716
|
+
}
|
|
717
|
+
.form-group label.input-symbol-label:not(.active) {
|
|
718
|
+
left: 2.25rem;
|
|
719
|
+
}
|
|
720
|
+
.form-group small.form-text {
|
|
721
|
+
margin: 0;
|
|
722
|
+
font-size: 0.875rem;
|
|
723
|
+
}
|
|
724
|
+
.form-group input[type=time] ~ label {
|
|
725
|
+
font-size: 0.875rem;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.form-text {
|
|
729
|
+
margin: var(--bs-spacing-xxs) 0;
|
|
730
|
+
color: var(--bs-color-text-secondary);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.form-group.active .form-file-name {
|
|
734
|
+
padding-bottom: 1.95rem;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.warning-feedback {
|
|
738
|
+
display: none;
|
|
739
|
+
width: 100%;
|
|
740
|
+
margin-top: 0.25rem;
|
|
741
|
+
color: var(--bs-color-text-warning);
|
|
742
|
+
font-size: 0.75rem;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.valid-feedback,
|
|
746
|
+
.invalid-feedback,
|
|
747
|
+
.warning-feedback {
|
|
748
|
+
margin-left: 0.5rem;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.input-group .input-group-text .btn {
|
|
752
|
+
border-radius: var(--bs-form-control-border-radius) 0 0 var(--bs-form-control-border-radius);
|
|
753
|
+
}
|
|
754
|
+
.input-group .input-group-append {
|
|
755
|
+
margin-left: 0;
|
|
756
|
+
}
|
|
757
|
+
.input-group .input-group-append .btn {
|
|
758
|
+
height: 100%;
|
|
759
|
+
padding-top: 0;
|
|
760
|
+
padding-bottom: 0;
|
|
761
|
+
border-bottom: 1px solid hsl(210, 17%, 44%);
|
|
762
|
+
border-radius: 0 var(--bs-form-control-border-radius) var(--bs-form-control-border-radius) 0;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
.form-check {
|
|
766
|
+
position: relative;
|
|
767
|
+
padding-left: 0;
|
|
768
|
+
align-items: center;
|
|
769
|
+
}
|
|
770
|
+
.form-check + .form-check {
|
|
771
|
+
margin-top: var(--bs-spacing-s);
|
|
772
|
+
}
|
|
773
|
+
.form-check [type=checkbox],
|
|
774
|
+
.form-check [type=radio] {
|
|
775
|
+
position: absolute;
|
|
776
|
+
height: 100%;
|
|
777
|
+
margin-top: 0;
|
|
778
|
+
margin-left: 0;
|
|
779
|
+
opacity: 0;
|
|
780
|
+
}
|
|
781
|
+
.form-check [type=checkbox] + label,
|
|
782
|
+
.form-check [type=radio] + label {
|
|
783
|
+
position: relative;
|
|
784
|
+
display: flex;
|
|
785
|
+
align-items: center;
|
|
786
|
+
padding-left: 28px;
|
|
787
|
+
font-size: var(--bs-label-font-size);
|
|
788
|
+
font-weight: var(--bs-font-weight-solid);
|
|
789
|
+
cursor: pointer;
|
|
790
|
+
margin-bottom: 0;
|
|
791
|
+
user-select: none;
|
|
792
|
+
}
|
|
793
|
+
@media (min-width: 576px) {
|
|
794
|
+
.form-check [type=checkbox] + label,
|
|
795
|
+
.form-check [type=radio] + label {
|
|
796
|
+
font-size: var(--bs-label-font-size-m);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
.form-check input[type=checkbox] + label::after,
|
|
800
|
+
.form-check input[type=checkbox] + label::before {
|
|
801
|
+
position: absolute;
|
|
802
|
+
left: 0;
|
|
803
|
+
z-index: 1;
|
|
804
|
+
content: "";
|
|
805
|
+
border-width: 2px;
|
|
806
|
+
border-style: solid;
|
|
807
|
+
transition: all var(--bs-transition-instant) ease-out;
|
|
808
|
+
}
|
|
809
|
+
.form-check input[type=checkbox] + label::after {
|
|
810
|
+
top: 0;
|
|
811
|
+
width: 20px;
|
|
812
|
+
height: 20px;
|
|
813
|
+
border-radius: var(--bs-form-control-border-radius);
|
|
814
|
+
}
|
|
815
|
+
.form-check input[type=checkbox]:checked + label::before {
|
|
816
|
+
top: 3px;
|
|
817
|
+
left: 3px;
|
|
818
|
+
width: 6px;
|
|
819
|
+
height: 12px;
|
|
820
|
+
border-width: 2px;
|
|
821
|
+
border-style: solid;
|
|
822
|
+
border-color: transparent var(--bs-color-border-inverse) var(--bs-color-border-inverse) transparent;
|
|
823
|
+
opacity: 1;
|
|
824
|
+
transform: rotate(40deg);
|
|
825
|
+
transform-origin: 100% 100%;
|
|
826
|
+
backface-visibility: hidden;
|
|
827
|
+
}
|
|
828
|
+
.form-check input[type=checkbox]:checked + label::after {
|
|
829
|
+
z-index: 0;
|
|
830
|
+
border-color: var(--bs-form-checked-color);
|
|
831
|
+
background-color: var(--bs-form-checked-color);
|
|
832
|
+
}
|
|
833
|
+
.form-check input[type=checkbox]:not(:checked) + label::after {
|
|
834
|
+
z-index: 0;
|
|
835
|
+
border-color: var(--bs-form-checkbox-border-color);
|
|
836
|
+
background-color: transparent;
|
|
837
|
+
}
|
|
838
|
+
.form-check input[type=checkbox]:not(:checked) + label::before {
|
|
839
|
+
top: 10px;
|
|
840
|
+
left: 6px;
|
|
841
|
+
width: 0;
|
|
842
|
+
height: 0;
|
|
843
|
+
border-color: transparent;
|
|
844
|
+
}
|
|
845
|
+
.form-check input[type=checkbox]:disabled + label {
|
|
846
|
+
opacity: 1;
|
|
847
|
+
cursor: not-allowed;
|
|
848
|
+
}
|
|
849
|
+
.form-check input[type=checkbox]:disabled:not(:checked) + label::after {
|
|
850
|
+
border-color: var(--bs-color-border-disabled);
|
|
851
|
+
background-color: transparent;
|
|
852
|
+
}
|
|
853
|
+
.form-check input[type=checkbox]:disabled:checked + label::after {
|
|
854
|
+
border-color: var(--bs-color-border-disabled);
|
|
855
|
+
background-color: var(--bs-color-border-disabled);
|
|
856
|
+
}
|
|
857
|
+
.form-check input[type=radio] + label::after, .form-check input[type=radio] + label::before {
|
|
858
|
+
position: absolute;
|
|
859
|
+
top: 0;
|
|
860
|
+
left: 0;
|
|
861
|
+
z-index: 0;
|
|
862
|
+
content: "";
|
|
863
|
+
width: 20px;
|
|
864
|
+
height: 20px;
|
|
865
|
+
border-width: 2px;
|
|
866
|
+
border-style: solid;
|
|
867
|
+
border-radius: var(--bs-radius-rounded);
|
|
868
|
+
transition: all var(--bs-transition-instant) ease-out;
|
|
869
|
+
}
|
|
870
|
+
.form-check input[type=radio]:not(:checked) + label::after, .form-check input[type=radio]:not(:checked) + label::before {
|
|
871
|
+
border-color: var(--bs-form-checkbox-border-color);
|
|
872
|
+
}
|
|
873
|
+
.form-check input[type=radio]:not(:checked) + label:after {
|
|
874
|
+
z-index: -1;
|
|
875
|
+
transform: scale(0);
|
|
876
|
+
}
|
|
877
|
+
.form-check input[type=radio]:checked + label::after {
|
|
878
|
+
z-index: 0;
|
|
879
|
+
border-color: var(--bs-form-checked-color);
|
|
880
|
+
background-color: var(--bs-form-checked-color);
|
|
881
|
+
transform: scale(0.64);
|
|
882
|
+
}
|
|
883
|
+
.form-check input[type=radio]:checked + label::before {
|
|
884
|
+
border-color: var(--bs-form-checked-color);
|
|
885
|
+
}
|
|
886
|
+
.form-check input[type=radio]:disabled + label {
|
|
887
|
+
cursor: not-allowed;
|
|
888
|
+
}
|
|
889
|
+
.form-check input[type=radio]:disabled:not(:checked) + label::after, .form-check input[type=radio]:disabled:not(:checked) + label::before {
|
|
890
|
+
border-color: var(--bs-color-border-disabled);
|
|
891
|
+
}
|
|
892
|
+
.form-check input[type=radio]:disabled:checked + label::after {
|
|
893
|
+
border-color: var(--bs-color-border-disabled);
|
|
894
|
+
background-color: var(--bs-color-border-disabled);
|
|
895
|
+
}
|
|
896
|
+
.form-check input[type=radio]:disabled:checked + label::before {
|
|
897
|
+
border-color: var(--bs-color-border-disabled);
|
|
898
|
+
}
|
|
899
|
+
.form-check.form-check-group {
|
|
900
|
+
margin-bottom: 1rem;
|
|
901
|
+
padding: 0 0 1rem 0;
|
|
902
|
+
box-shadow: inset 0 -1px 0 0 rgba(1, 1, 1, 0.1);
|
|
903
|
+
}
|
|
904
|
+
.form-check.form-check-group input[type=checkbox] + label,
|
|
905
|
+
.form-check.form-check-group input[type=radio] + label {
|
|
906
|
+
padding-right: 3.25rem;
|
|
907
|
+
padding-left: 0;
|
|
908
|
+
}
|
|
909
|
+
.form-check.form-check-group input[type=checkbox] + label::after, .form-check.form-check-group input[type=checkbox] + label::before,
|
|
910
|
+
.form-check.form-check-group input[type=radio] + label::after,
|
|
911
|
+
.form-check.form-check-group input[type=radio] + label::before {
|
|
912
|
+
right: 0;
|
|
913
|
+
left: auto;
|
|
914
|
+
}
|
|
915
|
+
.form-check.form-check-group input[type=checkbox]:checked + label::before {
|
|
916
|
+
right: 11px;
|
|
917
|
+
}
|
|
918
|
+
.form-check.form-check-group input[type=radio]:checked + label::before {
|
|
919
|
+
right: 0;
|
|
920
|
+
}
|
|
921
|
+
.form-check.form-check-group .form-text {
|
|
922
|
+
display: block;
|
|
923
|
+
margin-bottom: 0.5rem;
|
|
924
|
+
padding-right: 3.25rem;
|
|
925
|
+
}
|
|
926
|
+
.form-check.form-check-group input.semi-checked:not(:checked) + label::before {
|
|
927
|
+
right: 4px;
|
|
928
|
+
left: auto;
|
|
929
|
+
}
|
|
930
|
+
.form-check input.semi-checked:not(:checked) + label::before {
|
|
931
|
+
top: 9px;
|
|
932
|
+
left: 4px;
|
|
933
|
+
width: 12px;
|
|
934
|
+
height: 2px;
|
|
935
|
+
border-width: 0;
|
|
936
|
+
border-style: none;
|
|
937
|
+
border-color: transparent;
|
|
938
|
+
opacity: 1;
|
|
939
|
+
background: var(--bs-color-background-inverse);
|
|
940
|
+
transform: none;
|
|
941
|
+
backface-visibility: hidden;
|
|
942
|
+
}
|
|
943
|
+
.form-check input.semi-checked:not(:checked) + label::after {
|
|
944
|
+
z-index: 0;
|
|
945
|
+
border-color: var(--bs-form-checked-color);
|
|
946
|
+
background-color: var(--bs-form-checked-color);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.form-check-inline {
|
|
950
|
+
display: inline-block;
|
|
951
|
+
}
|
|
952
|
+
.form-check-inline:not(:last-child) {
|
|
953
|
+
margin-right: var(--bs-spacing-m);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
@media (prefers-reduced-motion: reduce) {
|
|
957
|
+
fieldset legend,
|
|
958
|
+
.form-group label,
|
|
959
|
+
textarea,
|
|
960
|
+
.form-check [type=checkbox],
|
|
961
|
+
.form-check [type=radio],
|
|
962
|
+
.form-check [type=checkbox] + label::after,
|
|
963
|
+
.form-check [type=checkbox] + label::before,
|
|
964
|
+
.form-check [type=radio] + label::after,
|
|
965
|
+
.form-check [type=radio] + label::before,
|
|
966
|
+
.toggles label input[type=checkbox] + .lever::before,
|
|
967
|
+
.toggles label input[type=checkbox] + .lever::after {
|
|
968
|
+
transition: none !important;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
.form-check [type=checkbox]:focus + label,
|
|
972
|
+
.form-check [type=radio]:focus + label {
|
|
973
|
+
border-color: hsl(0, 0%, 0%) !important;
|
|
974
|
+
box-shadow: 0 0 0 2px var(--bs-color-border-inverse), 0 0 0 5px var(--bs-color-outline-focus) !important;
|
|
975
|
+
outline: 3px solid transparent !important;
|
|
976
|
+
outline-offset: 3px !important;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.form-check [type=checkbox]:focus[data-focus-mouse=true] + label,
|
|
980
|
+
.form-check [type=radio]:focus[data-focus-mouse=true] + label {
|
|
981
|
+
border-color: inherit !important;
|
|
982
|
+
box-shadow: none !important;
|
|
983
|
+
outline: none !important;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.form-control-plaintext {
|
|
987
|
+
border: 0;
|
|
988
|
+
--bs-form-control-border-color: transparent;
|
|
989
|
+
--bs-form-control-border-radius: 0;
|
|
990
|
+
--bs-form-control-background-color: transparent;
|
|
991
|
+
--bs-form-control-spacing: 0;
|
|
992
|
+
}
|
|
993
|
+
.form-control-plaintext:focus {
|
|
994
|
+
outline: 0;
|
|
995
|
+
box-shadow: none !important;
|
|
996
|
+
}
|
|
997
|
+
.form-control-plaintext + label {
|
|
998
|
+
cursor: text;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
.form-control {
|
|
1002
|
+
background-repeat: no-repeat;
|
|
1003
|
+
background-position: center right;
|
|
1004
|
+
background-size: 45px 30%;
|
|
1005
|
+
}
|
|
1006
|
+
.form-control:disabled {
|
|
1007
|
+
cursor: not-allowed;
|
|
1008
|
+
background: var(--bs-color-background-disabled);
|
|
1009
|
+
border: 0;
|
|
1010
|
+
color: var(--bs-color-text-disabled);
|
|
1011
|
+
}
|
|
1012
|
+
.was-validated .form-control:valid, .form-control.is-valid {
|
|
1013
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23008055' viewBox='0 0 192 512'%3E%3Cpath d='M435.848 83.466L172.804 346.51l-96.652-96.652c-4.686-4.686-12.284-4.686-16.971 0l-28.284 28.284c-4.686 4.686-4.686 12.284 0 16.971l133.421 133.421c4.686 4.686 12.284 4.686 16.971 0l299.813-299.813c4.686-4.686 4.686-12.284 0-16.971l-28.284-28.284c-4.686-4.686-12.284-4.686-16.97 0z'/%3E%3C/svg%3E");
|
|
1014
|
+
}
|
|
1015
|
+
.was-validated .form-control:invalid, .form-control.is-invalid {
|
|
1016
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23cc334d' viewBox='0 0 384 512'%3E%3Cpath d='M231.6 256l130.1-130.1c4.7-4.7 4.7-12.3 0-17l-22.6-22.6c-4.7-4.7-12.3-4.7-17 0L192 216.4 61.9 86.3c-4.7-4.7-12.3-4.7-17 0l-22.6 22.6c-4.7 4.7-4.7 12.3 0 17L152.4 256 22.3 386.1c-4.7 4.7-4.7 12.3 0 17l22.6 22.6c4.7 4.7 12.3 4.7 17 0L192 295.6l130.1 130.1c4.7 4.7 12.3 4.7 17 0l22.6-22.6c4.7-4.7 4.7-12.3 0-17L231.6 256z'/%3E%3C/svg%3E");
|
|
1017
|
+
border-color: var(--bs-color-border-danger);
|
|
1018
|
+
}
|
|
1019
|
+
.form-control.warning {
|
|
1020
|
+
background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M2%2012C2%206.47715%206.47715%202%2012%202C14.6522%202%2017.1957%203.05357%2019.0711%204.92893C20.9464%206.8043%2022%209.34784%2022%2012C22%2017.5228%2017.5228%2022%2012%2022C6.47715%2022%202%2017.5228%202%2012ZM3%2012C3%2016.9706%207.02944%2021%2012%2021C16.9706%2021%2021%2016.9706%2021%2012C21%207.02944%2016.9706%203%2012%203C7.02944%203%203%207.02944%203%2012ZM11.5%2014.2V5.7H12.7V14.2H11.5ZM12.6%2018.3V16.5H11.4V18.3H12.6Z%22/%3E%0A%3C/svg%3E") no-repeat;
|
|
1021
|
+
border-color: var(--bs-color-border-warning);
|
|
1022
|
+
}
|
|
1023
|
+
.form-control.is-valid ~ .warning-feedback {
|
|
1024
|
+
display: block;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
.form-control-sm {
|
|
1028
|
+
--bs-form-control-spacing: var(--bs-spacing-xxs) var(--bs-spacing-3xs);
|
|
1029
|
+
--bs-form-control-font-size: var(--bs-label-font-size);
|
|
1030
|
+
}
|
|
1031
|
+
.form-control-sm::file-selector-button {
|
|
1032
|
+
padding: 0.25rem 0.5rem;
|
|
1033
|
+
margin: -0.25rem -0.5rem;
|
|
1034
|
+
margin-inline-end: 0.5rem;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
.form-control-lg {
|
|
1038
|
+
--bs-form-control-font-size: var(--bs-lead-font-size);
|
|
1039
|
+
}
|
|
1040
|
+
.form-control-lg::file-selector-button {
|
|
1041
|
+
padding: 0.5rem 1rem;
|
|
1042
|
+
margin: -0.5rem -1rem;
|
|
1043
|
+
margin-inline-end: 1rem;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
textarea.form-control {
|
|
1047
|
+
min-height: 2.5rem;
|
|
1048
|
+
border: 1px solid hsl(210, 17%, 44%);
|
|
1049
|
+
}
|
|
1050
|
+
textarea.form-control-sm {
|
|
1051
|
+
min-height: calc(1.5em + 0.5rem);
|
|
1052
|
+
}
|
|
1053
|
+
textarea.form-control-lg {
|
|
1054
|
+
min-height: calc(1.5em + 1rem);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
.form-control-color {
|
|
1058
|
+
width: 3rem;
|
|
1059
|
+
height: 2.5rem;
|
|
1060
|
+
padding: 0.375rem;
|
|
1061
|
+
}
|
|
1062
|
+
.form-control-color:not(:disabled):not([readonly]) {
|
|
1063
|
+
cursor: pointer;
|
|
1064
|
+
}
|
|
1065
|
+
.form-control-color::-moz-color-swatch {
|
|
1066
|
+
border: 0 !important;
|
|
1067
|
+
border-radius: 0;
|
|
1068
|
+
}
|
|
1069
|
+
.form-control-color::-webkit-color-swatch {
|
|
1070
|
+
border-radius: 0;
|
|
1071
|
+
}
|
|
1072
|
+
.form-control-color.form-control-sm {
|
|
1073
|
+
height: calc(1.5em + 0.5rem);
|
|
1074
|
+
}
|
|
1075
|
+
.form-control-color.form-control-lg {
|
|
1076
|
+
height: calc(1.5em + 1rem);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
.form-check-reverse {
|
|
1080
|
+
padding-right: 1.5em;
|
|
1081
|
+
padding-left: 0;
|
|
1082
|
+
text-align: right;
|
|
1083
|
+
}
|
|
1084
|
+
.form-check-reverse .form-check-input {
|
|
1085
|
+
float: right;
|
|
1086
|
+
margin-right: -1.5em;
|
|
1087
|
+
margin-left: 0;
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
.form-check-input {
|
|
1091
|
+
width: 1em;
|
|
1092
|
+
height: 1em;
|
|
1093
|
+
margin-top: 0.25em;
|
|
1094
|
+
vertical-align: top;
|
|
1095
|
+
background-color: hsl(0, 0%, 100%);
|
|
1096
|
+
background-repeat: no-repeat;
|
|
1097
|
+
background-position: center;
|
|
1098
|
+
background-size: contain;
|
|
1099
|
+
border: 1px solid rgba(0, 0, 0, 0.25);
|
|
1100
|
+
appearance: none;
|
|
1101
|
+
print-color-adjust: exact;
|
|
1102
|
+
}
|
|
1103
|
+
.form-check-input[type=checkbox] {
|
|
1104
|
+
border-radius: 0.25em;
|
|
1105
|
+
}
|
|
1106
|
+
.form-check-input[type=radio] {
|
|
1107
|
+
border-radius: 50%;
|
|
1108
|
+
}
|
|
1109
|
+
.form-check-input:active {
|
|
1110
|
+
filter: brightness(90%);
|
|
1111
|
+
}
|
|
1112
|
+
.form-check-input:focus {
|
|
1113
|
+
border-color: hsl(210, 17%, 44%);
|
|
1114
|
+
outline: 0;
|
|
1115
|
+
box-shadow: 0 0 0 0.25rem rgba(0, 102, 204, 0.25);
|
|
1116
|
+
}
|
|
1117
|
+
.form-check-input:checked {
|
|
1118
|
+
background-color: hsl(210, 100%, 40%);
|
|
1119
|
+
border-color: hsl(210, 100%, 40%);
|
|
1120
|
+
}
|
|
1121
|
+
.form-check-input:checked[type=checkbox] {
|
|
1122
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='hsl%280, 0%, 100%%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e");
|
|
1123
|
+
}
|
|
1124
|
+
.form-check-input:checked[type=radio] {
|
|
1125
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='hsl%280, 0%, 100%%29'/%3e%3c/svg%3e");
|
|
1126
|
+
}
|
|
1127
|
+
.form-check-input[type=checkbox]:indeterminate {
|
|
1128
|
+
background-color: hsl(210, 100%, 40%);
|
|
1129
|
+
border-color: hsl(210, 100%, 40%);
|
|
1130
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='hsl%280, 0%, 100%%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e");
|
|
1131
|
+
}
|
|
1132
|
+
.form-check-input:disabled {
|
|
1133
|
+
pointer-events: none;
|
|
1134
|
+
filter: none;
|
|
1135
|
+
opacity: 0.5;
|
|
1136
|
+
}
|
|
1137
|
+
.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label {
|
|
1138
|
+
cursor: default;
|
|
1139
|
+
opacity: 0.5;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
.form-switch {
|
|
1143
|
+
padding-left: 2.5em;
|
|
1144
|
+
}
|
|
1145
|
+
.form-switch .form-check-input {
|
|
1146
|
+
width: 2em;
|
|
1147
|
+
margin-left: -2.5em;
|
|
1148
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");
|
|
1149
|
+
background-position: left center;
|
|
1150
|
+
border-radius: 2em;
|
|
1151
|
+
transition: background-position 0.15s ease-in-out;
|
|
1152
|
+
}
|
|
1153
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1154
|
+
.form-switch .form-check-input {
|
|
1155
|
+
transition: none;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
.form-switch .form-check-input:focus {
|
|
1159
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='hsl%28210, 17%, 44%%29'/%3e%3c/svg%3e");
|
|
1160
|
+
}
|
|
1161
|
+
.form-switch .form-check-input:checked {
|
|
1162
|
+
background-position: right center;
|
|
1163
|
+
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='hsl%280, 0%, 100%%29'/%3e%3c/svg%3e");
|
|
1164
|
+
}
|
|
1165
|
+
.form-switch.form-check-reverse {
|
|
1166
|
+
padding-right: 2.5em;
|
|
1167
|
+
padding-left: 0;
|
|
1168
|
+
}
|
|
1169
|
+
.form-switch.form-check-reverse .form-check-input {
|
|
1170
|
+
margin-right: -2.5em;
|
|
1171
|
+
margin-left: 0;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
.form-check-inline {
|
|
1175
|
+
display: inline-block;
|
|
1176
|
+
margin-right: 1rem;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
.btn-check {
|
|
1180
|
+
position: absolute;
|
|
1181
|
+
clip: rect(0, 0, 0, 0);
|
|
1182
|
+
pointer-events: none;
|
|
1183
|
+
}
|
|
1184
|
+
.btn-check[disabled] + .btn, .btn-check:disabled + .btn {
|
|
1185
|
+
pointer-events: none;
|
|
1186
|
+
filter: none;
|
|
1187
|
+
opacity: 0.65;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.form-feedback {
|
|
1191
|
+
width: 100%;
|
|
1192
|
+
margin-top: 0.25rem;
|
|
1193
|
+
font-size: 0.75rem;
|
|
1194
|
+
}
|
|
1195
|
+
.form-feedback.just-validate-error-label {
|
|
1196
|
+
color: var(--bs-color-text-danger);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
.input-group-text:has(~ [data-focus-mouse=true]:not(.btn)),
|
|
1200
|
+
[data-focus-mouse=true]:not(.btn) ~ .input-group-text,
|
|
1201
|
+
button:has(~ [data-focus-mouse=true]:not(.btn)),
|
|
1202
|
+
[data-focus-mouse=true]:not(.btn) + button {
|
|
1203
|
+
border-color: inherit !important;
|
|
1204
|
+
box-shadow: none !important;
|
|
1205
|
+
outline: none !important;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
.input-group-text:has(~ .is-invalid),
|
|
1209
|
+
.is-invalid ~ .input-group-text,
|
|
1210
|
+
button:has(~ .is-invalid),
|
|
1211
|
+
.is-invalid + button {
|
|
1212
|
+
border-color: var(--bs-color-border-danger) !important;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
.sr-only-justvalidate-bi {
|
|
1216
|
+
display: none;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.just-validate-success-field {
|
|
1220
|
+
border-color: var(--bs-color-border-success) !important;
|
|
1221
|
+
padding-right: calc(1.5em + 0.75rem) !important;
|
|
1222
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23008055' viewBox='0 0 192 512'%3E%3Cpath d='M435.848 83.466L172.804 346.51l-96.652-96.652c-4.686-4.686-12.284-4.686-16.971 0l-28.284 28.284c-4.686 4.686-4.686 12.284 0 16.971l133.421 133.421c4.686 4.686 12.284 4.686 16.971 0l299.813-299.813c4.686-4.686 4.686-12.284 0-16.971l-28.284-28.284c-4.686-4.686-12.284-4.686-16.97 0z'/%3E%3C/svg%3E");
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
.input-group-text:has(~ .just-validate-success-field),
|
|
1226
|
+
.just-validate-success-field ~ .input-group-text,
|
|
1227
|
+
button:has(~ .just-validate-success-field),
|
|
1228
|
+
.just-validate-success-field + button {
|
|
1229
|
+
border-color: var(--bs-color-border-success);
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
.just-validate-success-field + .input-group-text.align-buttons,
|
|
1233
|
+
.is-invalid + .input-group-text.align-buttons {
|
|
1234
|
+
right: 30px;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
.is-invalid + .input-group-text.align-buttons {
|
|
1238
|
+
bottom: 22px;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
.autocomplete__wrapper .form-feedback.just-validate-error-label {
|
|
1242
|
+
position: absolute;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
textarea.form-control {
|
|
1246
|
+
background-position: top 0.3em right 0.3em !important;
|
|
1247
|
+
background-size: 37px 30% !important;
|
|
1248
|
+
}
|
|
1249
|
+
textarea.is-invalid {
|
|
1250
|
+
border-bottom-style: solid;
|
|
1251
|
+
border-bottom-width: 1px;
|
|
1252
|
+
}
|
|
1253
|
+
textarea.just-validate-success-field {
|
|
1254
|
+
border-bottom-style: solid;
|
|
1255
|
+
border-bottom-width: 1px;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
input[type=checkbox].is-invalid,
|
|
1259
|
+
input[type=radio].is-invalid {
|
|
1260
|
+
--bs-form-checkbox-border-color: var(--bs-color-border-danger);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
select.is-invalid {
|
|
1264
|
+
border: 1px solid var(--bs-color-border-danger);
|
|
1265
|
+
}
|
|
1266
|
+
select.just-validate-success-field {
|
|
1267
|
+
border: 1px solid var(--bs-color-border-success);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
::slotted([slot=label]) {
|
|
1271
|
+
display: block;
|
|
1272
|
+
padding: 0 var(--bs-form-input-spacing-x);
|
|
1273
|
+
margin-bottom: var(--bs-spacing-s);
|
|
1274
|
+
background-color: rgba(0, 0, 0, 0);
|
|
1275
|
+
color: var(--bs-form-control-text-color);
|
|
1276
|
+
font-size: var(--bs-label-sm);
|
|
1277
|
+
font-weight: var(--bs-font-weight-solid);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
.it-radio-group {
|
|
1281
|
+
margin-bottom: var(--bs-spacing-xs);
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
.it-radio-group-inline {
|
|
1285
|
+
display: flex;
|
|
1286
|
+
flex-wrap: wrap;
|
|
1287
|
+
align-items: center;
|
|
1288
|
+
gap: var(--bs-spacing-s);
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
.just-validate-success-field ::slotted(it-radio) {
|
|
1292
|
+
--it-radio-label-color: var(--bs-color-text-success);
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
.just-validate-success-field {
|
|
1296
|
+
padding: 0 !important;
|
|
1297
|
+
border: none !important;
|
|
1298
|
+
background-image: none !important;
|
|
1299
|
+
}`;
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* Radio group component - manages a collection of radio buttons
|
|
1303
|
+
*
|
|
1304
|
+
* @element it-radio-group
|
|
1305
|
+
* @slot - Contains the `<it-radio>` elements
|
|
1306
|
+
*
|
|
1307
|
+
*/
|
|
1308
|
+
let ItRadioGroup = class ItRadioGroup extends FormControl {
|
|
1309
|
+
constructor() {
|
|
1310
|
+
super(...arguments);
|
|
1311
|
+
/**
|
|
1312
|
+
* The name of the radio group, used for form submission
|
|
1313
|
+
*/
|
|
1314
|
+
this.name = '';
|
|
1315
|
+
/**
|
|
1316
|
+
* The currently selected value
|
|
1317
|
+
*/
|
|
1318
|
+
this.value = '';
|
|
1319
|
+
/**
|
|
1320
|
+
* Whether the radio group is disabled
|
|
1321
|
+
*/
|
|
1322
|
+
this.disabled = false;
|
|
1323
|
+
/**
|
|
1324
|
+
* Whether a selection is required
|
|
1325
|
+
*/
|
|
1326
|
+
this.required = false;
|
|
1327
|
+
/**
|
|
1328
|
+
* Optional prop for visual styling of grouped radios (borders between radios)
|
|
1329
|
+
*/
|
|
1330
|
+
this.grouped = false;
|
|
1331
|
+
/**
|
|
1332
|
+
* Whether the radios are displayed inline (horizontally) or stacked (vertically)
|
|
1333
|
+
*/
|
|
1334
|
+
this.inline = false;
|
|
1335
|
+
/**
|
|
1336
|
+
* Track if validation has been triggered (via reportValidity or setCustomValidity)
|
|
1337
|
+
* ARIA best practice: don't show aria-invalid until user attempts submission
|
|
1338
|
+
*/
|
|
1339
|
+
this._validationTriggered = false;
|
|
1340
|
+
/**
|
|
1341
|
+
* Roving tabindex controller for keyboard navigation
|
|
1342
|
+
*/
|
|
1343
|
+
this.rovingTabindex = new RovingTabindexController(this, {
|
|
1344
|
+
getItems: () => this._radios,
|
|
1345
|
+
onSelect: (radio, event) => this.selectRadio(radio, event),
|
|
1346
|
+
direction: 'both',
|
|
1347
|
+
selectOnFocus: true,
|
|
1348
|
+
});
|
|
1349
|
+
/**
|
|
1350
|
+
* Form control integration
|
|
1351
|
+
*/
|
|
1352
|
+
this._formController = new FormControlController(this, {
|
|
1353
|
+
value: () => this.value,
|
|
1354
|
+
// disabled: () => this.disabled,
|
|
1355
|
+
setValue: (control, value) => {
|
|
1356
|
+
const radioGroup = control;
|
|
1357
|
+
radioGroup.value = value;
|
|
1358
|
+
},
|
|
1359
|
+
});
|
|
1360
|
+
/**
|
|
1361
|
+
* Handle slot changes (when radios are added/removed)
|
|
1362
|
+
*/
|
|
1363
|
+
this._handleSlotChange = () => {
|
|
1364
|
+
this._syncValueFromRadios();
|
|
1365
|
+
this._updateRadiosState();
|
|
1366
|
+
// Sync group state to newly added radios
|
|
1367
|
+
this._syncGroupStateToRadios();
|
|
1368
|
+
};
|
|
1369
|
+
this._handleLabelSlotChange = () => {
|
|
1370
|
+
const labelId = this.generateId('it-radio-group-label');
|
|
1371
|
+
this._label[0]?.setAttribute('id', labelId);
|
|
1372
|
+
this.setAttribute('aria-labelledby', labelId);
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Override: Custom validity check for radio group
|
|
1377
|
+
*/
|
|
1378
|
+
get validity() {
|
|
1379
|
+
// Fallback: create a custom ValidityState-like object
|
|
1380
|
+
const valid = !this.required || !!this.value;
|
|
1381
|
+
return {
|
|
1382
|
+
valid,
|
|
1383
|
+
valueMissing: this.required && !this.value,
|
|
1384
|
+
typeMismatch: false,
|
|
1385
|
+
patternMismatch: false,
|
|
1386
|
+
tooLong: false,
|
|
1387
|
+
tooShort: false,
|
|
1388
|
+
rangeUnderflow: false,
|
|
1389
|
+
rangeOverflow: false,
|
|
1390
|
+
stepMismatch: false,
|
|
1391
|
+
badInput: false,
|
|
1392
|
+
customError: false,
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* Override: Check validity for radio group
|
|
1397
|
+
*/
|
|
1398
|
+
checkValidity() {
|
|
1399
|
+
if (this.required && !this.value) {
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
return true;
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Override: Report validity for radio group
|
|
1406
|
+
*/
|
|
1407
|
+
reportValidity() {
|
|
1408
|
+
this._validationTriggered = true; // Mark that validation has been attempted
|
|
1409
|
+
const isValid = this.checkValidity();
|
|
1410
|
+
this.handleValidationMessages();
|
|
1411
|
+
this._updateInvalidState();
|
|
1412
|
+
return isValid;
|
|
1413
|
+
}
|
|
1414
|
+
/** Sets a custom validation message. Pass an empty string to restore validity. */
|
|
1415
|
+
setCustomValidity(message) {
|
|
1416
|
+
// Only trigger validation state if message is non-empty (actual error)
|
|
1417
|
+
// Empty message during init or after correction should not trigger invalid state initially
|
|
1418
|
+
if (message && message.length > 0) {
|
|
1419
|
+
this._validationTriggered = true;
|
|
1420
|
+
}
|
|
1421
|
+
this.validationMessage = message;
|
|
1422
|
+
this.formControlController.updateValidity();
|
|
1423
|
+
// Update aria-invalid on group and children immediately
|
|
1424
|
+
this._updateInvalidState();
|
|
1425
|
+
}
|
|
1426
|
+
handleValidationMessages() {
|
|
1427
|
+
const _v = this.validity;
|
|
1428
|
+
if (!this.customValidation) {
|
|
1429
|
+
if (_v.valueMissing) {
|
|
1430
|
+
this.setCustomValidity(this.$t('validityRequired'));
|
|
1431
|
+
}
|
|
1432
|
+
else
|
|
1433
|
+
this.setCustomValidity('');
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
_updateInvalidState() {
|
|
1437
|
+
// Only show aria-invalid if validation has been triggered (ARIA best practice)
|
|
1438
|
+
if (!this._validationTriggered) {
|
|
1439
|
+
return;
|
|
1440
|
+
}
|
|
1441
|
+
const invalid = this.checkValidity() === false || !!this.validationMessage;
|
|
1442
|
+
if (invalid)
|
|
1443
|
+
this.setAttribute('aria-invalid', 'true');
|
|
1444
|
+
else
|
|
1445
|
+
this.removeAttribute('aria-invalid');
|
|
1446
|
+
this._radios?.forEach((r) => {
|
|
1447
|
+
if (invalid)
|
|
1448
|
+
r.setAttribute('aria-invalid', 'true');
|
|
1449
|
+
else
|
|
1450
|
+
r.removeAttribute('aria-invalid');
|
|
1451
|
+
});
|
|
1452
|
+
// Update validation message in light DOM
|
|
1453
|
+
this._updateValidationMessage();
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Update validation message in light DOM (for aria-describedby cross-boundary support)
|
|
1457
|
+
*/
|
|
1458
|
+
_updateValidationMessage() {
|
|
1459
|
+
const validityMessage = this.validationMessage;
|
|
1460
|
+
const messageId = `invalid-feedback-${this._id}`;
|
|
1461
|
+
// Find or create validation message element in light DOM
|
|
1462
|
+
let messageEl = this.querySelector(`[slot="validation-message"]`);
|
|
1463
|
+
if (validityMessage && validityMessage.length > 0) {
|
|
1464
|
+
// Create message element if it doesn't exist
|
|
1465
|
+
if (!messageEl) {
|
|
1466
|
+
messageEl = document.createElement('div');
|
|
1467
|
+
messageEl.setAttribute('slot', 'validation-message');
|
|
1468
|
+
this.appendChild(messageEl);
|
|
1469
|
+
}
|
|
1470
|
+
// Update message content and attributes
|
|
1471
|
+
messageEl.id = messageId;
|
|
1472
|
+
messageEl.className = 'invalid-feedback form-feedback form-text form-feedback just-validate-error-label';
|
|
1473
|
+
messageEl.setAttribute('role', 'alert');
|
|
1474
|
+
messageEl.removeAttribute('hidden');
|
|
1475
|
+
const labelText = this._label?.[0]?.textContent || '';
|
|
1476
|
+
messageEl.innerHTML = `<span class="visually-hidden">${labelText}: </span>${validityMessage}`;
|
|
1477
|
+
// Update aria-describedby on host
|
|
1478
|
+
const existingDescribedBy = this._ariaAttributes['aria-describedby'] || '';
|
|
1479
|
+
const ariaDescribedBy = existingDescribedBy ? `${existingDescribedBy} ${messageId}` : messageId;
|
|
1480
|
+
this.setAttribute('aria-describedby', ariaDescribedBy);
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
// Remove message element if validation passed
|
|
1484
|
+
if (messageEl) {
|
|
1485
|
+
messageEl.remove();
|
|
1486
|
+
}
|
|
1487
|
+
// Update aria-describedby (remove message id)
|
|
1488
|
+
const existingDescribedBy = this._ariaAttributes['aria-describedby'] || '';
|
|
1489
|
+
if (existingDescribedBy) {
|
|
1490
|
+
this.setAttribute('aria-describedby', existingDescribedBy);
|
|
1491
|
+
}
|
|
1492
|
+
else {
|
|
1493
|
+
this.removeAttribute('aria-describedby');
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
connectedCallback() {
|
|
1498
|
+
super.connectedCallback?.();
|
|
1499
|
+
this._handleReady();
|
|
1500
|
+
this.setAttribute('role', 'radiogroup');
|
|
1501
|
+
}
|
|
1502
|
+
firstUpdated() {
|
|
1503
|
+
const checkedRadio = this.querySelector('it-radio[checked]');
|
|
1504
|
+
if (checkedRadio) {
|
|
1505
|
+
this.value = checkedRadio.value;
|
|
1506
|
+
}
|
|
1507
|
+
this.updateRadios();
|
|
1508
|
+
}
|
|
1509
|
+
async updateRadios() {
|
|
1510
|
+
if (!this.hasUpdated) {
|
|
1511
|
+
// Initial validation has to happen after the initial render to allow
|
|
1512
|
+
// the buttons to be queries from the rendered <slot> element
|
|
1513
|
+
await this.updateComplete;
|
|
1514
|
+
}
|
|
1515
|
+
const radios = this.querySelectorAll('it-radio');
|
|
1516
|
+
// eslint-disable-next-line no-return-assign, no-param-reassign
|
|
1517
|
+
radios.forEach((r) => {
|
|
1518
|
+
// eslint-disable-next-line no-param-reassign
|
|
1519
|
+
r.checked = r.value === this.value;
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
disconnectedCallback() {
|
|
1523
|
+
super.disconnectedCallback?.();
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Sync group value from checked radio (initialization)
|
|
1527
|
+
*/
|
|
1528
|
+
_syncValueFromRadios() {
|
|
1529
|
+
if (!this._radios) {
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
// Find the first checked radio
|
|
1533
|
+
const checkedRadio = this._radios.find((r) => r.checked);
|
|
1534
|
+
if (checkedRadio) {
|
|
1535
|
+
// Sync the group value from the checked radio
|
|
1536
|
+
this.value = checkedRadio.value;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* PUBLIC API: Called by radio buttons to select themselves
|
|
1541
|
+
*/
|
|
1542
|
+
selectRadio(radio, event) {
|
|
1543
|
+
if (radio.disabled || this.disabled) {
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
this.value = radio.value;
|
|
1547
|
+
// Uncheck other radios using their public API
|
|
1548
|
+
this._radios.forEach((r) => {
|
|
1549
|
+
if (r !== radio) {
|
|
1550
|
+
// eslint-disable-next-line no-param-reassign
|
|
1551
|
+
r.checked = false;
|
|
1552
|
+
}
|
|
1553
|
+
else {
|
|
1554
|
+
// eslint-disable-next-line no-param-reassign
|
|
1555
|
+
r.checked = true;
|
|
1556
|
+
}
|
|
1557
|
+
});
|
|
1558
|
+
// If validation was already triggered, update state after selection
|
|
1559
|
+
if (this._validationTriggered) {
|
|
1560
|
+
// For native validation, clear error if now valid
|
|
1561
|
+
if (!this.customValidation) {
|
|
1562
|
+
this.handleValidationMessages();
|
|
1563
|
+
this._updateInvalidState();
|
|
1564
|
+
}
|
|
1565
|
+
// For custom validation (JustValidate), the external validator will call setCustomValidity
|
|
1566
|
+
// but we still update the state based on current validationMessage
|
|
1567
|
+
else {
|
|
1568
|
+
this._updateInvalidState();
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
if (event.type === 'click' || event.type === 'pointerdown') {
|
|
1572
|
+
this._handleClick(event);
|
|
1573
|
+
}
|
|
1574
|
+
else {
|
|
1575
|
+
this._handleChange(event);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* PUBLIC API: Handle keyboard navigation from radio buttons
|
|
1580
|
+
*/
|
|
1581
|
+
handleRadioKeyDown(radio, event) {
|
|
1582
|
+
// Delegate to roving tabindex controller
|
|
1583
|
+
const handled = this.rovingTabindex.handleKeydown(radio, event);
|
|
1584
|
+
if (handled)
|
|
1585
|
+
this._handleFocus(event);
|
|
1586
|
+
else
|
|
1587
|
+
this._handleBlur(event);
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Synchronize radio button states with group state
|
|
1591
|
+
*/
|
|
1592
|
+
_updateRadiosState() {
|
|
1593
|
+
if (!this._radios || this._radios.length === 0) {
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
this._radios.forEach((radio) => {
|
|
1597
|
+
// Set checked state based on value
|
|
1598
|
+
// eslint-disable-next-line no-param-reassign
|
|
1599
|
+
radio.checked = radio.value === this.value;
|
|
1600
|
+
// Sync disabled state from group to radios
|
|
1601
|
+
// Note: We don't override individual radio's disabled state
|
|
1602
|
+
// If the group is disabled, all radios should be disabled
|
|
1603
|
+
// But individual radios can be disabled independently
|
|
1604
|
+
if (this.disabled) {
|
|
1605
|
+
// eslint-disable-next-line no-param-reassign
|
|
1606
|
+
radio.disabled = true;
|
|
1607
|
+
}
|
|
1608
|
+
});
|
|
1609
|
+
// Update tabindex using roving tabindex controller
|
|
1610
|
+
// Priority: checked and enabled > first enabled > 0
|
|
1611
|
+
let tabbableIndex = 0;
|
|
1612
|
+
// First, try to find a checked radio that is not disabled
|
|
1613
|
+
const checkedEnabledIndex = this._radios.findIndex((r) => r.checked && !r.disabled);
|
|
1614
|
+
if (checkedEnabledIndex >= 0) {
|
|
1615
|
+
tabbableIndex = checkedEnabledIndex;
|
|
1616
|
+
}
|
|
1617
|
+
else {
|
|
1618
|
+
// If no checked enabled radio, find the first enabled radio
|
|
1619
|
+
const firstEnabledIndex = this._radios.findIndex((r) => !r.disabled);
|
|
1620
|
+
if (firstEnabledIndex >= 0) {
|
|
1621
|
+
tabbableIndex = firstEnabledIndex;
|
|
1622
|
+
}
|
|
1623
|
+
// If all radios are disabled, tabbableIndex stays 0 (but controller will set all to -1)
|
|
1624
|
+
}
|
|
1625
|
+
this.rovingTabindex.updateTabindices(tabbableIndex);
|
|
1626
|
+
}
|
|
1627
|
+
/**
|
|
1628
|
+
* Sync group state (name, grouped, inline, required) to child radios
|
|
1629
|
+
* This replaces the need for requestUpdate() calls
|
|
1630
|
+
*/
|
|
1631
|
+
_syncGroupStateToRadios() {
|
|
1632
|
+
if (!this._radios || this._radios.length === 0) {
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
const groupState = {
|
|
1636
|
+
name: this.name,
|
|
1637
|
+
grouped: this.grouped,
|
|
1638
|
+
inline: this.inline,
|
|
1639
|
+
required: this.required,
|
|
1640
|
+
};
|
|
1641
|
+
this._radios.forEach((radio) => {
|
|
1642
|
+
radio.syncFromGroup(groupState);
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
updated(changed) {
|
|
1646
|
+
super.updated(changed);
|
|
1647
|
+
// Update radios when value or name changes
|
|
1648
|
+
if (changed.has('value')) {
|
|
1649
|
+
this._updateRadiosState();
|
|
1650
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
1651
|
+
// Re-validate after value change (for native validation) only if validation was already triggered
|
|
1652
|
+
if (!this.customValidation && this._validationTriggered) {
|
|
1653
|
+
this.handleValidationMessages();
|
|
1654
|
+
this._updateInvalidState();
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
// If validation message changed, update aria-invalid on group and children
|
|
1658
|
+
if (changed.has('validationMessage')) {
|
|
1659
|
+
this._updateInvalidState();
|
|
1660
|
+
}
|
|
1661
|
+
// If relevant group properties changed, sync to child radios
|
|
1662
|
+
const relevant = ['grouped', 'inline', 'name', 'required', 'disabled'];
|
|
1663
|
+
const hasChanged = Array.from(changed.keys()).some((k) => relevant.includes(String(k)));
|
|
1664
|
+
if (hasChanged && this._radios?.length) {
|
|
1665
|
+
this._syncGroupStateToRadios();
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Render the component
|
|
1670
|
+
*/
|
|
1671
|
+
render() {
|
|
1672
|
+
const validityMessage = this.validationMessage;
|
|
1673
|
+
const invalid = validityMessage?.length > 0 || (!this.customValidation && this?.checkValidity() === false);
|
|
1674
|
+
const groupWrapperClasses = this.composeClass('it-radio-group', 'it-form__control', this.inline && !this.grouped ? 'it-radio-group-inline' : '', this.grouped && !this.inline ? 'it-radio-group-stacked' : '', invalid ? 'is-invalid' : '', !invalid && this._touched ? 'just-validate-success-field' : '');
|
|
1675
|
+
return html `<slot name="label" @slotchange=${this._handleLabelSlotChange}></slot>
|
|
1676
|
+
<div class=${groupWrapperClasses}>
|
|
1677
|
+
<slot @slotchange=${this._handleSlotChange}></slot>
|
|
1678
|
+
</div>
|
|
1679
|
+
<slot name="validation-message"></slot>`;
|
|
1680
|
+
}
|
|
1681
|
+
};
|
|
1682
|
+
ItRadioGroup.styles = styles;
|
|
1683
|
+
ItRadioGroup.formAssociated = true;
|
|
1684
|
+
__decorate([
|
|
1685
|
+
property({ type: String }),
|
|
1686
|
+
__metadata("design:type", Object)
|
|
1687
|
+
], ItRadioGroup.prototype, "name", void 0);
|
|
1688
|
+
__decorate([
|
|
1689
|
+
property({ type: String, reflect: true }),
|
|
1690
|
+
__metadata("design:type", Object)
|
|
1691
|
+
], ItRadioGroup.prototype, "value", void 0);
|
|
1692
|
+
__decorate([
|
|
1693
|
+
property({ type: Boolean, reflect: true }),
|
|
1694
|
+
__metadata("design:type", Object)
|
|
1695
|
+
], ItRadioGroup.prototype, "disabled", void 0);
|
|
1696
|
+
__decorate([
|
|
1697
|
+
property({ type: Boolean, reflect: true }),
|
|
1698
|
+
__metadata("design:type", Object)
|
|
1699
|
+
], ItRadioGroup.prototype, "required", void 0);
|
|
1700
|
+
__decorate([
|
|
1701
|
+
property({ type: Boolean, reflect: true }),
|
|
1702
|
+
__metadata("design:type", Object)
|
|
1703
|
+
], ItRadioGroup.prototype, "grouped", void 0);
|
|
1704
|
+
__decorate([
|
|
1705
|
+
property({ type: Boolean, reflect: true }),
|
|
1706
|
+
__metadata("design:type", Object)
|
|
1707
|
+
], ItRadioGroup.prototype, "inline", void 0);
|
|
1708
|
+
__decorate([
|
|
1709
|
+
queryAssignedElements(),
|
|
1710
|
+
__metadata("design:type", Array)
|
|
1711
|
+
], ItRadioGroup.prototype, "_radios", void 0);
|
|
1712
|
+
__decorate([
|
|
1713
|
+
queryAssignedElements({ slot: 'label' }),
|
|
1714
|
+
__metadata("design:type", Array)
|
|
1715
|
+
], ItRadioGroup.prototype, "_label", void 0);
|
|
1716
|
+
__decorate([
|
|
1717
|
+
state(),
|
|
1718
|
+
__metadata("design:type", Object)
|
|
1719
|
+
], ItRadioGroup.prototype, "_validationTriggered", void 0);
|
|
1720
|
+
ItRadioGroup = __decorate([
|
|
1721
|
+
customElement('it-radio-group')
|
|
1722
|
+
], ItRadioGroup);
|
|
1723
|
+
|
|
1724
|
+
export { ItRadioGroup };
|
|
1725
|
+
//# sourceMappingURL=it-radio-group.js.map
|