@papillonbits/components 0.16.0 → 0.18.0

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.
@@ -0,0 +1,669 @@
1
+ // stylelint-disable custom-property-pattern, no-descending-specificity
2
+ // stylelint-disable primer/typography, primer/borders, primer/spacing, selector-max-type, selector-max-specificity, selector-no-qualifying-type, max-nesting-depth
3
+
4
+ // groups label, field, caption and inline error message
5
+ .FormControl {
6
+ display: inline-flex;
7
+ flex-direction: column;
8
+ gap: var(--base-size-4, 4px);
9
+ }
10
+
11
+ // fill container
12
+ .FormControl--fullWidth {
13
+ display: flex;
14
+ }
15
+
16
+ // <label>
17
+ .FormControl-label {
18
+ font-size: var(--primer-text-body-size-medium, 14px);
19
+ font-weight: var(--base-text-weight-semibold, 600);
20
+ line-height: var(--primer-text-body-lineHeight-medium, calc(20 / 14));
21
+ color: var(--color-fg-default);
22
+ user-select: none;
23
+ }
24
+
25
+ // optional caption
26
+ .FormControl-caption {
27
+ margin-bottom: 0;
28
+ font-size: var(--primer-text-caption-size, 12px);
29
+ font-weight: var(--primer-text-caption-weight, 400);
30
+ line-height: var(--primer-text-caption-lineHeight, calc(16 / 12));
31
+ color: var(--color-fg-muted);
32
+ }
33
+
34
+ // inline validation message
35
+ .FormControl-inlineValidation {
36
+ display: flex;
37
+ font-size: var(--primer-text-caption-size, 12px);
38
+ font-weight: var(--base-text-weight-semibold, 600);
39
+ color: var(--color-danger-fg);
40
+ fill: var(--color-danger-fg);
41
+ flex-direction: row;
42
+ align-items: center;
43
+ gap: var(--base-size-4, 4px);
44
+
45
+ p {
46
+ margin-bottom: 0;
47
+ }
48
+ }
49
+
50
+ // shared among all form control components (input, select, textarea, checkbox, radio)
51
+ @mixin Field {
52
+ background-color: var(--color-canvas-default);
53
+ border: solid var(--primer-borderWidth-thin, 1px) var(--color-border-default);
54
+
55
+ &[disabled] {
56
+ color: var(--color-primer-fg-disabled);
57
+ cursor: not-allowed;
58
+ background-color: var(--color-input-disabled-bg);
59
+ border-color: var(--color-border-default);
60
+ opacity: 1;
61
+ -webkit-text-fill-color: var(--color-primer-fg-disabled);
62
+ }
63
+
64
+ &:not(:focus)[invalid] {
65
+ border-color: var(--color-danger-emphasis);
66
+ }
67
+
68
+ &:not([type='checkbox'], [type='radio']):focus {
69
+ @include focusBoxShadowInset;
70
+
71
+ // remove fallback :focus if :focus-visible is supported
72
+ &:not(:focus-visible) {
73
+ border-color: transparent;
74
+
75
+ @include focusBoxShadowInset(1px, transparent);
76
+ }
77
+ }
78
+
79
+ // default focus state
80
+ &:focus-visible {
81
+ @include focusBoxShadowInset;
82
+ }
83
+ }
84
+
85
+ // TextInput structure
86
+ // ===================
87
+ //
88
+ // .FormControl
89
+ // ├─ .FormControl-label
90
+ // │ ├─ .FormControl-input-wrap
91
+ // │ │ ├─ .FormControl-input-leadingVisualWrap
92
+ // │ │ │ ├─ .FormControl-input-leadingVisual
93
+ // │ │ ├─ .FormControl-input
94
+ // │ │ ├─ .FormControl-input-trailingAction
95
+ // ├─ .FormControl-inlineValidation
96
+ // ├─ .FormControl-caption
97
+
98
+ // Select structure
99
+ // ===================
100
+ //
101
+ // .FormControl
102
+ // ├─ .FormControl-label
103
+ // │ ├─ .FormControl-select-wrap
104
+ // │ │ ├─ .FormControl-select
105
+ // ├─ .FormControl-inlineValidation
106
+ // ├─ .FormControl-caption
107
+
108
+ // Textarea structure
109
+ // ===================
110
+ //
111
+ // .FormControl
112
+ // ├─ .FormControl-label
113
+ // ├─ .FormControl-textarea
114
+ // ├─ .FormControl-inlineValidation
115
+ // ├─ .FormControl-caption
116
+
117
+ .FormControl-input,
118
+ .FormControl-select,
119
+ .FormControl-textarea {
120
+ @include Field;
121
+
122
+ width: 100%;
123
+ font-size: var(--primer-text-body-size-medium, 14px);
124
+ line-height: var(--primer-text-body-lineHeight-medium, calc(20 / 14));
125
+ border-radius: var(--primer-borderRadius-medium, 6px);
126
+ transition: 80ms cubic-bezier(0.33, 1, 0.68, 1);
127
+ transition-property: color, background-color, box-shadow, border-color;
128
+ padding-inline: var(--primer-control-medium-paddingInline-condensed, 8px);
129
+ padding-block: calc(var(--primer-control-medium-paddingBlock, 6px) - var(--primer-borderWidth-thin, 1px));
130
+
131
+ &[disabled] {
132
+ &::placeholder {
133
+ color: var(--color-primer-fg-disabled);
134
+ }
135
+ }
136
+
137
+ &[readonly] {
138
+ background-color: var(--color-input-disabled-bg);
139
+ }
140
+
141
+ ::placeholder {
142
+ color: var(--color-fg-subtle);
143
+ opacity: 1;
144
+ }
145
+
146
+ // sizes
147
+
148
+ &.FormControl-small {
149
+ height: var(--primer-control-small-size, 28px);
150
+ padding-inline: var(--primer-control-small-paddingInline-normal, 8px);
151
+ padding-block: var(--primer-control-small-paddingBlock, 4px);
152
+ font-size: var(--primer-text-body-size-small, 12px);
153
+ }
154
+
155
+ &.FormControl-medium {
156
+ height: var(--primer-control-medium-size, 32px);
157
+ }
158
+
159
+ &.FormControl-large {
160
+ height: var(--primer-control-large-size, 40px);
161
+ padding-inline: var(--primer-control-large-paddingInline-normal, 12px);
162
+ padding-block: var(--primer-control-large-paddingBlock, 10px);
163
+ }
164
+
165
+ // variants
166
+
167
+ &.FormControl-inset {
168
+ background-color: var(--color-canvas-inset);
169
+
170
+ &:focus-visible,
171
+ &:focus {
172
+ background-color: var(--color-canvas-default);
173
+ }
174
+ }
175
+
176
+ &.FormControl-monospace {
177
+ font-family: var(--primer-fontStack-monospace, 'ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace');
178
+ }
179
+
180
+ // validation states
181
+
182
+ &.FormControl-error {
183
+ border-color: var(--color-danger-emphasis);
184
+ }
185
+
186
+ &.FormControl-success {
187
+ border-color: var(--color-success-emphasis);
188
+ }
189
+
190
+ &.FormControl-warning {
191
+ border-color: var(--color-attention-emphasis);
192
+ }
193
+ }
194
+
195
+ // positioning for leading/trailing items for TextInput
196
+ .FormControl-input-wrap {
197
+ position: relative;
198
+ display: grid;
199
+
200
+ .FormControl-input-leadingVisualWrap {
201
+ position: absolute;
202
+ top: var(--base-size-8, 8px);
203
+ left: var(--base-size-8, 8px);
204
+ display: block;
205
+ width: var(--base-size-16, 16px);
206
+ height: var(--base-size-16, 16px);
207
+ color: var(--color-fg-muted);
208
+ pointer-events: none;
209
+
210
+ // octicon
211
+ .FormControl-input-leadingVisual {
212
+ display: block;
213
+ user-select: none;
214
+ }
215
+ }
216
+
217
+ // TODO: replace with new Button component
218
+ .FormControl-input-trailingAction {
219
+ position: absolute;
220
+ top: var(--base-size-4, 4px);
221
+ right: var(--base-size-4, 4px);
222
+ z-index: 4;
223
+ display: grid;
224
+ width: var(--primer-control-xsmall-size, 24px);
225
+ height: var(--primer-control-xsmall-size, 24px);
226
+ padding: 0;
227
+ color: var(--color-fg-muted);
228
+ cursor: pointer;
229
+ background: transparent;
230
+ border: 0;
231
+ border-radius: var(--primer-borderRadius-small);
232
+ transition: 0.2s cubic-bezier(0.3, 0, 0.5, 1);
233
+ transition-property: color, background-color, border-color;
234
+ align-items: center;
235
+ justify-content: center;
236
+
237
+ svg {
238
+ user-select: none;
239
+ }
240
+
241
+ &[disabled] {
242
+ color: var(--color-primer-fg-disabled);
243
+ pointer-events: none;
244
+ }
245
+
246
+ &:hover {
247
+ background: var(--color-action-list-item-default-hover-bg);
248
+ }
249
+
250
+ &:active {
251
+ background: var(--color-action-list-item-default-active-bg);
252
+ }
253
+
254
+ // show vertical divider line between field and button
255
+ &.FormControl-input-trailingAction--divider {
256
+ &::before {
257
+ position: absolute;
258
+ top: calc((var(--primer-control-xsmall-size) - var(--base-size-16)) / 2);
259
+ left: calc(var(--base-size-4, 4px) * -1);
260
+ display: block;
261
+ width: var(--primer-borderWidth-thin);
262
+ height: var(--base-size-16);
263
+ content: '';
264
+ background: var(--color-border-default);
265
+ }
266
+ }
267
+
268
+ &::after {
269
+ @include minTouchTarget(var(--primer-control-medium-size, 32px), var(--primer-control-medium-size, 32px));
270
+
271
+ @media (pointer: coarse) {
272
+ min-width: var(--primer-control-minTarget-coarse, 44px);
273
+ min-height: var(--primer-control-minTarget-coarse, 44px);
274
+ }
275
+ }
276
+ }
277
+
278
+ // if leadingVisual is present
279
+
280
+ /*
281
+ ┌──32px──┬────────────────────┐
282
+ ╎ ┌───┐ ┌────────────────┐ ╎
283
+ ╎ 16px 16px ╎
284
+ ╎ └───┘ └────────────────┘ ╎
285
+ └───────8px───────────────────┘
286
+ */
287
+ &.FormControl-input-wrap--leadingVisual {
288
+ .FormControl-input {
289
+ padding-inline-start: calc(
290
+ var(--primer-control-medium-paddingInline-condensed, 8px) + var(--base-size-16, 16px) + var(--primer-control-medium-gap, 8px)
291
+ ); /* 32px */
292
+ }
293
+ }
294
+
295
+ /*
296
+ ┌──────────────────┬──32px──┐
297
+ ╎ ┌──────────────┐ ┌────┐ ╎
298
+ ╎ 24px 24px ╎
299
+ ╎ └──────────────┘ └────┘ ╎
300
+ └──────────────────┴────────┘
301
+ */
302
+ // if trailingAction is present
303
+ &.FormControl-input-wrap--trailingAction {
304
+ .FormControl-input {
305
+ padding-inline-end: calc(
306
+ var(--primer-control-medium-paddingInline-condensed, 8px) + var(--base-size-16, 16px) + var(--primer-control-medium-gap, 8px)
307
+ ); /* 32px */
308
+ }
309
+
310
+ /*
311
+ 32px + 1px border
312
+ ┌──────────────────┬──33px──┐
313
+ ╎ ┌──────────────┐ ┌────┐ ╎
314
+ ╎ 24px 24px ╎
315
+ ╎ └──────────────┘ └────┘ ╎
316
+ └──────────────────┴────────┘
317
+ */
318
+ // if trailingAction divider is present, add 1px padding to accomodate input field text
319
+ // can be refactored to has(.FormControl-input-trailingAction--divider)
320
+ &.FormControl-input-wrap-trailingAction--divider {
321
+ .FormControl-input {
322
+ padding-inline-end: calc(
323
+ var(--primer-control-medium-paddingInline-condensed, 8px) + var(--base-size-16, 16px) + var(--primer-control-medium-gap, 8px) +
324
+ var(--primer-borderWidth-thin, 1px)
325
+ ); /* 33px */
326
+ }
327
+ }
328
+ }
329
+
330
+ // size modifications can be refactored with :has() - FormControl-input-wrap:has(.FormControl-large)
331
+ // sizes
332
+ &.FormControl-small {
333
+ .FormControl-input-leadingVisualWrap {
334
+ top: calc(var(--primer-control-medium-paddingInline-condensed, 8px) - 0.125rem); /* 6px */
335
+ left: calc(var(--primer-control-medium-paddingInline-condensed, 8px) - 0.125rem); /* 6px */
336
+ }
337
+
338
+ /*
339
+ ┌──────────────────┬──28px──┐
340
+ ╎ ┌──────────────┐ ┌────┐ ╎
341
+ ╎ 20px 20px ╎
342
+ ╎ └──────────────┘ └────┘ ╎
343
+ └──────────────────┴────────┘
344
+ */
345
+ &.FormControl-input-wrap--trailingAction {
346
+ .FormControl-input.FormControl-small {
347
+ padding-inline-end: calc(
348
+ var(--primer-control-small-paddingInline-condensed, 8px) + var(--base-size-16, 16px) + var(--primer-control-small-gap, 8px)
349
+ ); /* 28px */
350
+ }
351
+
352
+ /*
353
+ 28px + 1px border
354
+ ┌──────────────────┬──29px──┐
355
+ ╎ ┌──────────────┐ ┌────┐ ╎
356
+ ╎ 20px 20px ╎
357
+ ╎ └──────────────┘ └────┘ ╎
358
+ └──────────────────┴────────┘
359
+ */
360
+ &.FormControl-input-wrap-trailingAction--divider {
361
+ .FormControl-input.FormControl-small {
362
+ padding-inline-end: calc(
363
+ var(--primer-control-small-paddingInline-condensed, 8px) + var(--base-size-16, 16px) + var(--primer-control-small-gap, 8px) +
364
+ var(--primer-borderWidth-thin, 1px)
365
+ ); /* 29px */
366
+ }
367
+ }
368
+ }
369
+
370
+ .FormControl-input-trailingAction {
371
+ width: calc(var(--primer-control-small-size, 28px) - var(--base-size-8, 8px));
372
+ height: calc(var(--primer-control-small-size, 28px) - var(--base-size-8, 8px));
373
+
374
+ &::before {
375
+ top: calc((var(--primer-control-xsmall-size) - var(--base-size-16)) / 4); /* 2px */
376
+ }
377
+ }
378
+ }
379
+
380
+ &.FormControl-large {
381
+ .FormControl-input-leadingVisualWrap {
382
+ top: var(--primer-control-medium-paddingInline-normal, 12px);
383
+ left: var(--primer-control-medium-paddingInline-normal, 12px);
384
+ }
385
+
386
+ /*
387
+ ┌──36px──┬───12px padding──────┐
388
+ ╎ ┌───┐ ┌────────────────┐ ╎
389
+ ╎ 16px 16px ╎
390
+ ╎ └───┘ └────────────────┘ ╎
391
+ └12px───8px───────────────────┘
392
+ */
393
+ &.FormControl-input-wrap--leadingVisual {
394
+ .FormControl-input.FormControl-large {
395
+ padding-inline-start: calc(
396
+ var(--primer-control-large-paddingInline-normal, 12px) + var(--base-size-16, 16px) + var(--primer-control-large-gap, 8px)
397
+ ); /* 36px */
398
+ }
399
+ }
400
+
401
+ /*
402
+ ┌──────────────────┬──36px──┐
403
+ ╎ ┌──────────────┐ ┌────┐ ╎
404
+ ╎ 28px 28px ╎
405
+ ╎ └──────────────┘ └────┘ ╎
406
+ └──────────────────┴────────┘
407
+ */
408
+ &.FormControl-input-wrap--trailingAction {
409
+ .FormControl-input.FormControl-large {
410
+ padding-inline-end: calc(
411
+ var(--primer-control-large-paddingInline-normal, 12px) + var(--base-size-16, 16px) + var(--primer-control-large-gap, 8px)
412
+ ); /* 36px */
413
+ }
414
+
415
+ /*
416
+ ┌──────────────────┬──37px──┐
417
+ ╎ ┌──────────────┐ ┌────┐ ╎
418
+ ╎ 28px 28px ╎
419
+ ╎ └──────────────┘ └────┘ ╎
420
+ └──────────────────┴────────┘
421
+ */
422
+ &.FormControl-input-wrap-trailingAction--divider {
423
+ .FormControl-input.FormControl-large {
424
+ padding-inline-end: calc(
425
+ var(--primer-control-large-paddingInline-normal, 12px) + var(--base-size-16, 16px) + var(--primer-control-large-gap, 8px) +
426
+ var(--primer-borderWidth-thin, 1px)
427
+ ); /* 37px */
428
+ }
429
+ }
430
+ }
431
+
432
+ .FormControl-input-trailingAction {
433
+ top: calc(var(--primer-control-medium-paddingInline-condensed, 8px) - 0.125rem); /* 6px */
434
+ right: calc(var(--primer-control-medium-paddingInline-condensed, 8px) - 0.125rem); /* 6px */
435
+ width: var(--primer-control-small-size, 28px);
436
+ height: var(--primer-control-small-size, 28px);
437
+
438
+ &::before {
439
+ top: unset;
440
+ height: var(--base-size-20);
441
+ }
442
+ }
443
+ }
444
+ }
445
+
446
+ .FormControl-select-wrap {
447
+ display: grid;
448
+ grid-template-columns: minmax(0, auto) var(--base-size-16, 16px);
449
+
450
+ // mask allows for background-color to respect themes
451
+ &::after {
452
+ width: var(--base-size-16, 16px);
453
+ height: var(--base-size-16, 16px);
454
+ padding-right: var(--base-size-4, 4px);
455
+ pointer-events: none;
456
+ content: '';
457
+ background-color: var(--color-fg-muted);
458
+ mask: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0iIzU4NjA2OSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNC40MjcgOS40MjdsMy4zOTYgMy4zOTZhLjI1MS4yNTEgMCAwMC4zNTQgMGwzLjM5Ni0zLjM5NkEuMjUuMjUgMCAwMDExLjM5NiA5SDQuNjA0YS4yNS4yNSAwIDAwLS4xNzcuNDI3ek00LjQyMyA2LjQ3TDcuODIgMy4wNzJhLjI1LjI1IDAgMDEuMzU0IDBMMTEuNTcgNi40N2EuMjUuMjUgMCAwMS0uMTc3LjQyN0g0LjZhLjI1LjI1IDAgMDEtLjE3Ny0uNDI3eiIgLz48L3N2Zz4=');
459
+ mask-size: contain;
460
+ mask-repeat: no-repeat;
461
+ grid-column: 2;
462
+ grid-row: 1;
463
+ place-self: center end;
464
+ }
465
+
466
+ // spans entire grid below mask
467
+ .FormControl-select {
468
+ grid-column: 1/-1;
469
+ grid-row: 1;
470
+ appearance: none;
471
+ padding-right: var(--base-size-20, 20px);
472
+ }
473
+ }
474
+
475
+ // checkbox + radio specific styles
476
+
477
+ // Checkbox + Radio structure
478
+ // ===================
479
+ //
480
+ // .FormControl-radio-wrap
481
+ // ├─ .FormControl-radio
482
+ // ├─ .FormControl-radio-labelWrap
483
+ // │ ├─ .FormControl-label
484
+ // │ ├─ .FormControl-caption
485
+
486
+ .FormControl-checkbox-wrap,
487
+ .FormControl-radio-wrap {
488
+ display: inline-grid;
489
+ grid-template-columns: min-content auto;
490
+ gap: var(--base-size-8, 8px);
491
+
492
+ .FormControl-checkbox-labelWrap,
493
+ .FormControl-radio-labelWrap {
494
+ display: flex;
495
+ flex-direction: column;
496
+ gap: var(--base-size-4, 4px);
497
+ }
498
+
499
+ .FormControl-label {
500
+ cursor: pointer;
501
+ }
502
+ }
503
+
504
+ // these selectors are temporary to override base.scss
505
+ // once Field styles are widely adopted, we can adjust this and the global base styles
506
+ input[type='checkbox'].FormControl-checkbox,
507
+ input[type='radio'].FormControl-radio {
508
+ @include Field;
509
+
510
+ position: relative;
511
+ display: grid;
512
+ width: var(--base-size-16, 16px);
513
+ height: var(--base-size-16, 16px);
514
+ margin: 0;
515
+ margin-top: 0.125rem; // 2px to center align with label (20px line-height)
516
+ cursor: pointer;
517
+ border: solid var(--primer-borderWidth-thin, 1px) var(--color-border-default);
518
+ border-radius: var(--primer-borderRadius-small, 3px);
519
+ transition: background-color, border-color 80ms cubic-bezier(0.33, 1, 0.68, 1); // checked -> unchecked - add 120ms delay to fully see animation-out
520
+ appearance: none;
521
+ place-content: center;
522
+
523
+ &::before {
524
+ width: var(--base-size-16, 16px);
525
+ height: var(--base-size-16, 16px);
526
+ visibility: hidden;
527
+ content: '';
528
+ background-color: var(--color-fg-on-emphasis);
529
+ transition: visibility 0s linear 230ms;
530
+ clip-path: inset(var(--base-size-16, 16px) 0 0 0);
531
+ mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iOSIgdmlld0JveD0iMCAwIDEyIDkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTEuNzgwMyAwLjIxOTYyNUMxMS45MjEgMC4zNjA0MjcgMTIgMC41NTEzMDUgMTIgMC43NTAzMTNDMTIgMC45NDkzMjEgMTEuOTIxIDEuMTQwMTkgMTEuNzgwMyAxLjI4MUw0LjUxODYgOC41NDA0MkM0LjM3Nzc1IDguNjgxIDQuMTg2ODIgOC43NiAzLjk4Nzc0IDguNzZDMy43ODg2NyA4Ljc2IDMuNTk3NzMgOC42ODEgMy40NTY4OSA4LjU0MDQyTDAuMjAxNjIyIDUuMjg2MkMwLjA2ODkyNzcgNS4xNDM4MyAtMC4wMDMzMDkwNSA0Ljk1NTU1IDAuMDAwMTE2NDkzIDQuNzYwOThDMC4wMDM1NTIwNSA0LjU2NjQzIDAuMDgyMzg5NCA0LjM4MDgxIDAuMjIwMDMyIDQuMjQzMjFDMC4zNTc2NjUgNC4xMDU2MiAwLjU0MzM1NSA0LjAyNjgxIDAuNzM3OTcgNC4wMjMzOEMwLjkzMjU4NCA0LjAxOTk0IDEuMTIwOTMgNC4wOTIxNyAxLjI2MzM0IDQuMjI0ODJMMy45ODc3NCA2Ljk0ODM1TDEwLjcxODYgMC4yMTk2MjVDMTAuODU5NSAwLjA3ODk5MjMgMTEuMDUwNCAwIDExLjI0OTUgMEMxMS40NDg1IDAgMTEuNjM5NSAwLjA3ODk5MjMgMTEuNzgwMyAwLjIxOTYyNVoiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo='); // octicon checkmark image
532
+ mask-size: 75%;
533
+ mask-repeat: no-repeat;
534
+ mask-position: center;
535
+
536
+ @media screen and (prefers-reduced-motion: no-preference) {
537
+ animation: checkmarkOut 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards; // slightly snappier animation out
538
+ }
539
+ }
540
+
541
+ // extend touch target
542
+ &::after {
543
+ @include minTouchTarget(var(--primer-control-medium-size, 32px), var(--primer-control-medium-size, 32px));
544
+ }
545
+
546
+ &[disabled] {
547
+ ~ .FormControl-checkbox-labelWrap,
548
+ ~ .FormControl-radio-labelWrap {
549
+ .FormControl-label {
550
+ color: var(--color-primer-fg-disabled);
551
+ cursor: not-allowed;
552
+ }
553
+ }
554
+ }
555
+
556
+ &:checked {
557
+ background: var(--color-accent-fg);
558
+ border-color: var(--color-accent-fg);
559
+ transition: background-color, border-color 80ms cubic-bezier(0.32, 0, 0.67, 0) 0ms; // unchecked -> checked
560
+
561
+ &::before {
562
+ visibility: visible;
563
+ transition: visibility 0s linear 0s;
564
+
565
+ @media screen and (prefers-reduced-motion: no-preference) {
566
+ animation: checkmarkIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
567
+ }
568
+ }
569
+
570
+ &:disabled {
571
+ cursor: not-allowed;
572
+ background-color: var(--color-primer-fg-disabled);
573
+ border-color: var(--color-primer-fg-disabled);
574
+ opacity: 1;
575
+
576
+ &::before {
577
+ background-color: var(--color-fg-on-emphasis);
578
+ }
579
+ }
580
+
581
+ // Windows High Contrast mode
582
+ // stylelint-disable primer/colors
583
+ @media (forced-colors: active) {
584
+ background-color: canvastext;
585
+ border-color: canvastext;
586
+ }
587
+ // stylelint-enable primer/colors
588
+ }
589
+
590
+ &:focus,
591
+ &:focus-visible {
592
+ outline-offset: 2px;
593
+ }
594
+
595
+ &:indeterminate {
596
+ &::before {
597
+ mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMiIgdmlld0JveD0iMCAwIDEwIDIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMCAxQzAgMC40NDc3MTUgMC40NDc3MTUgMCAxIDBIOUM5LjU1MjI5IDAgMTAgMC40NDc3MTUgMTAgMUMxMCAxLjU1MjI4IDkuNTUyMjkgMiA5IDJIMUMwLjQ0NzcxNSAyIDAgMS41NTIyOCAwIDFaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K');
598
+ visibility: visible;
599
+ }
600
+ }
601
+ }
602
+
603
+ input[type='radio'].FormControl-radio {
604
+ border-radius: var(--primer-borderRadius-full, 100vh);
605
+
606
+ &::before {
607
+ clip-path: circle(0%);
608
+ mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iMTAiIHZpZXdCb3g9IjAgMCAxMCAxMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTUgOS4zNzVDNy40MTYyMiA5LjM3NSA5LjM3NSA3LjQxNjIyIDkuMzc1IDVDOS4zNzUgMi41ODM3NiA3LjQxNjIyIDAuNjI1IDUgMC42MjVDMi41ODM3NiAwLjYyNSAwLjYyNSAyLjU4Mzc2IDAuNjI1IDVDMC42MjUgNy40MTYyMiAyLjU4Mzc2IDkuMzc1IDUgOS4zNzVaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K'); // checked circle image
609
+ mask-size: 65%;
610
+
611
+ @media screen and (prefers-reduced-motion: no-preference) {
612
+ animation: radioOut 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards; // slightly snappier animation out
613
+ }
614
+ }
615
+
616
+ &:checked {
617
+ &::before {
618
+ @media screen and (prefers-reduced-motion: no-preference) {
619
+ animation: radioIn 80ms cubic-bezier(0.65, 0, 0.35, 1) forwards 80ms;
620
+ }
621
+ }
622
+ }
623
+
624
+ &:indeterminate {
625
+ &::before {
626
+ visibility: hidden;
627
+ }
628
+ }
629
+ }
630
+
631
+ @keyframes checkmarkIn {
632
+ from {
633
+ clip-path: inset(var(--base-size-16, 16px) 0 0 0);
634
+ }
635
+
636
+ to {
637
+ clip-path: inset(0 0 0 0);
638
+ }
639
+ }
640
+
641
+ @keyframes checkmarkOut {
642
+ from {
643
+ clip-path: inset(0 0 0 0);
644
+ }
645
+
646
+ to {
647
+ clip-path: inset(var(--base-size-16, 16px) 0 0 0);
648
+ }
649
+ }
650
+
651
+ @keyframes radioIn {
652
+ from {
653
+ clip-path: circle(0%);
654
+ }
655
+
656
+ to {
657
+ clip-path: circle(100%);
658
+ }
659
+ }
660
+
661
+ @keyframes radioOut {
662
+ from {
663
+ clip-path: circle(100%);
664
+ }
665
+
666
+ to {
667
+ clip-path: circle(0%);
668
+ }
669
+ }
@@ -6,3 +6,5 @@
6
6
  @import './form-validation.scss';
7
7
  @import './input-group.scss';
8
8
  @import './radio-group.scss';
9
+
10
+ @import './FormControl.scss';