ui-foundations 0.4.1 → 0.7.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.
- package/LICENSE +73 -0
- package/README.md +49 -13
- package/dist/core/index.css +1 -0
- package/dist/macros/ui.njk +94 -0
- package/dist/main.css +723 -138
- package/dist/react/accordion.js +36 -0
- package/dist/react/avatar.js +34 -0
- package/dist/react/button.js +1 -12
- package/dist/react/checkbox.js +3 -20
- package/dist/react/divider.js +31 -0
- package/dist/react/form.js +111 -0
- package/dist/react/icon.js +1 -12
- package/dist/react/index.js +7 -0
- package/dist/react/input.js +7 -0
- package/dist/react/radio.js +3 -20
- package/dist/react/switch.js +3 -20
- package/dist/react/tabs.js +72 -0
- package/dist/react/textarea.js +45 -0
- package/dist/react/tooltip.js +25 -0
- package/dist/react/warn-dev.js +15 -0
- package/dist/tokens/css/appearance-modes.tokens.mode-dark.css +12 -6
- package/dist/tokens/css/appearance-modes.tokens.mode-light.css +7 -1
- package/dist/tokens/css/components-ui.tokens.css +93 -73
- package/dist/tokens/css/core-primitives.tokens.css +72 -1
- package/dist/tokens/css/semantics-roles.tokens.css +1 -1
- package/dist/tokens/css/themes-brands.tokens.brand-a.css +11 -11
- package/dist/tokens/css/themes-brands.tokens.brand-b.css +1 -1
- package/dist/tokens/css/themes-brands.tokens.brand-c.css +22 -0
- package/dist/tokens/json/appearance-modes.tokens.mode-dark.json +24 -0
- package/dist/tokens/json/appearance-modes.tokens.mode-light.json +24 -0
- package/dist/tokens/json/components-ui.tokens.json +403 -269
- package/dist/tokens/json/core-primitives.tokens.json +302 -0
- package/dist/tokens/json/themes-brands.tokens.brand-a.json +10 -10
- package/dist/tokens/json/themes-brands.tokens.brand-b.json +10 -10
- package/dist/tokens/json/themes-brands.tokens.brand-c.json +81 -0
- package/dist/tokens/tokens.yaml +2138 -578
- package/dist/tokens/ts/appearance-modes.tokens.mode-dark.ts +12 -6
- package/dist/tokens/ts/appearance-modes.tokens.mode-light.ts +7 -1
- package/dist/tokens/ts/components-ui.tokens.ts +94 -74
- package/dist/tokens/ts/core-primitives.tokens.ts +73 -2
- package/dist/tokens/ts/semantics-roles.tokens.ts +1 -1
- package/dist/tokens/ts/themes-brands.tokens.brand-a.ts +11 -11
- package/dist/tokens/ts/themes-brands.tokens.brand-b.ts +1 -1
- package/dist/tokens/ts/themes-brands.tokens.brand-c.ts +32 -0
- package/dist/ui/index.css +7 -0
- package/dist/ui/patterns/accordion.css +81 -0
- package/dist/ui/patterns/avatar.css +57 -0
- package/dist/ui/patterns/button.css +3 -3
- package/dist/ui/patterns/checkbox.css +28 -28
- package/dist/ui/patterns/divider.css +25 -0
- package/dist/ui/patterns/form.css +112 -0
- package/dist/ui/patterns/input.css +12 -12
- package/dist/ui/patterns/label.css +1 -1
- package/dist/ui/patterns/tabs.css +71 -0
- package/dist/ui/patterns/textarea.css +50 -0
- package/dist/ui/patterns/tooltip.css +64 -0
- package/docs/agentic/README.md +1 -0
- package/docs/agentic/skills/component-accessibility-audit.md +132 -0
- package/docs/foundations/foundation-007-typography-selectors-and-specificity.md +1 -1
- package/package.json +15 -3
- package/dist/tokens/missing-tokens.json +0 -43
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
font-weight: var(--typography-label-font-weight);
|
|
8
8
|
font-size: var(--typography-label-font-size);
|
|
9
9
|
line-height: var(--typography-label-line-height);
|
|
10
|
-
color: var(--
|
|
10
|
+
color: var(--checkbox-text-color-default);
|
|
11
11
|
cursor: pointer;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
.checkbox-field.is-disabled {
|
|
15
|
-
color: var(--
|
|
15
|
+
color: var(--checkbox-text-color-disabled);
|
|
16
16
|
cursor: not-allowed;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
place-content: center;
|
|
26
26
|
border-style: solid;
|
|
27
27
|
border-width: var(--checkbox-border-size-default);
|
|
28
|
-
border-color: var(--
|
|
28
|
+
border-color: var(--checkbox-border-color-default);
|
|
29
29
|
border-radius: var(--corner-checkbox-radius);
|
|
30
|
-
background: var(--
|
|
31
|
-
color: var(--
|
|
30
|
+
background: var(--checkbox-container-background-default);
|
|
31
|
+
color: var(--checkbox-text-color-active);
|
|
32
32
|
cursor: pointer;
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
|
|
40
40
|
.checkbox:checked,
|
|
41
41
|
.checkbox.is-checked {
|
|
42
|
-
border-color: var(--
|
|
43
|
-
background: var(--
|
|
42
|
+
border-color: var(--checkbox-border-color-active);
|
|
43
|
+
background: var(--checkbox-container-background-active);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
.checkbox:checked::after,
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
|
|
62
62
|
.checkbox:indeterminate,
|
|
63
63
|
.checkbox.is-indeterminate {
|
|
64
|
-
border-color: var(--
|
|
65
|
-
background: var(--
|
|
64
|
+
border-color: var(--checkbox-border-color-active);
|
|
65
|
+
background: var(--checkbox-container-background-active);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
.checkbox:indeterminate::after,
|
|
@@ -77,9 +77,9 @@
|
|
|
77
77
|
.checkbox.is-hover {
|
|
78
78
|
background:
|
|
79
79
|
linear-gradient(0deg, var(--color-overlay-hover), var(--color-overlay-hover)),
|
|
80
|
-
var(--
|
|
81
|
-
color: var(--
|
|
82
|
-
border-color: var(--
|
|
80
|
+
var(--checkbox-container-background-hover);
|
|
81
|
+
color: var(--checkbox-text-color-hover);
|
|
82
|
+
border-color: var(--checkbox-border-color-hover);
|
|
83
83
|
border-width: var(--checkbox-border-size-hover);
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -87,9 +87,9 @@
|
|
|
87
87
|
.checkbox.is-checked.is-hover {
|
|
88
88
|
background:
|
|
89
89
|
linear-gradient(0deg, var(--color-overlay-hover), var(--color-overlay-hover)),
|
|
90
|
-
var(--
|
|
91
|
-
color: var(--
|
|
92
|
-
border-color: var(--
|
|
90
|
+
var(--checkbox-container-background-active);
|
|
91
|
+
color: var(--checkbox-text-color-hover);
|
|
92
|
+
border-color: var(--checkbox-border-color-hover);
|
|
93
93
|
border-width: var(--checkbox-border-size-hover);
|
|
94
94
|
}
|
|
95
95
|
|
|
@@ -97,9 +97,9 @@
|
|
|
97
97
|
.checkbox.is-indeterminate.is-hover {
|
|
98
98
|
background:
|
|
99
99
|
linear-gradient(0deg, var(--color-overlay-hover), var(--color-overlay-hover)),
|
|
100
|
-
var(--
|
|
101
|
-
color: var(--
|
|
102
|
-
border-color: var(--
|
|
100
|
+
var(--checkbox-container-background-active);
|
|
101
|
+
color: var(--checkbox-text-color-hover);
|
|
102
|
+
border-color: var(--checkbox-border-color-hover);
|
|
103
103
|
border-width: var(--checkbox-border-size-hover);
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -107,8 +107,8 @@
|
|
|
107
107
|
.checkbox.is-active {
|
|
108
108
|
background:
|
|
109
109
|
linear-gradient(0deg, var(--color-overlay-active), var(--color-overlay-active)),
|
|
110
|
-
var(--
|
|
111
|
-
border-color: var(--
|
|
110
|
+
var(--checkbox-container-background-default);
|
|
111
|
+
border-color: var(--checkbox-border-color-active);
|
|
112
112
|
border-width: var(--size-border-200);
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -116,21 +116,21 @@
|
|
|
116
116
|
.checkbox.is-checked.is-active {
|
|
117
117
|
background:
|
|
118
118
|
linear-gradient(0deg, var(--color-overlay-active), var(--color-overlay-active)),
|
|
119
|
-
var(--
|
|
120
|
-
border-color: var(--
|
|
119
|
+
var(--checkbox-container-background-active);
|
|
120
|
+
border-color: var(--checkbox-border-color-active);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
.checkbox:indeterminate:active,
|
|
124
124
|
.checkbox.is-indeterminate.is-active {
|
|
125
125
|
background:
|
|
126
126
|
linear-gradient(0deg, var(--color-overlay-active), var(--color-overlay-active)),
|
|
127
|
-
var(--
|
|
128
|
-
border-color: var(--
|
|
127
|
+
var(--checkbox-container-background-active);
|
|
128
|
+
border-color: var(--checkbox-border-color-active);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
.checkbox:focus-visible,
|
|
132
132
|
.checkbox.is-focus-visible {
|
|
133
|
-
border-color: var(--
|
|
133
|
+
border-color: var(--checkbox-border-color-focus);
|
|
134
134
|
outline: none;
|
|
135
135
|
box-shadow: 0 0 0 var(--shadow-focus, 0) var(--color-focus, transparent);
|
|
136
136
|
}
|
|
@@ -138,9 +138,9 @@
|
|
|
138
138
|
.checkbox:disabled,
|
|
139
139
|
.checkbox.is-disabled {
|
|
140
140
|
border-width: var(--checkbox-border-size-disabled);
|
|
141
|
-
border-color: var(--
|
|
142
|
-
background: var(--
|
|
143
|
-
color: var(--
|
|
141
|
+
border-color: var(--checkbox-border-color-disabled);
|
|
142
|
+
background: var(--checkbox-container-background-disabled);
|
|
143
|
+
color: var(--checkbox-text-color-disabled);
|
|
144
144
|
cursor: not-allowed;
|
|
145
145
|
}
|
|
146
146
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.divider {
|
|
3
|
+
border: none;
|
|
4
|
+
margin: 0;
|
|
5
|
+
padding: 0;
|
|
6
|
+
background: var(--divider-color, var(--color-border-default));
|
|
7
|
+
block-size: var(--size-border-100);
|
|
8
|
+
inline-size: 100%;
|
|
9
|
+
align-self: stretch;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* ── Vertical orientation ── */
|
|
13
|
+
|
|
14
|
+
.divider[aria-orientation="vertical"] {
|
|
15
|
+
block-size: auto;
|
|
16
|
+
inline-size: var(--size-border-100);
|
|
17
|
+
align-self: stretch;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* ── Subtle variant ── */
|
|
21
|
+
|
|
22
|
+
.divider.subtle {
|
|
23
|
+
--divider-color: var(--color-border-subtle);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
/* ----------------------------------------------------------------
|
|
3
|
+
* Form — layout container for form fields
|
|
4
|
+
* ---------------------------------------------------------------- */
|
|
5
|
+
|
|
6
|
+
.form {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: var(--form-gap);
|
|
10
|
+
padding-inline: var(--form-padding-inline);
|
|
11
|
+
padding-block: var(--form-padding-block);
|
|
12
|
+
background: var(--form-container-background);
|
|
13
|
+
border: var(--form-border-size) solid var(--form-container-border-color);
|
|
14
|
+
border-radius: var(--form-border-radius);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.form.borderless {
|
|
18
|
+
border: none;
|
|
19
|
+
padding: 0;
|
|
20
|
+
background: transparent;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* ----------------------------------------------------------------
|
|
24
|
+
* Form Group — groups related fields with an optional title
|
|
25
|
+
* ---------------------------------------------------------------- */
|
|
26
|
+
|
|
27
|
+
.form-group {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
gap: var(--form-group-gap);
|
|
31
|
+
margin: 0;
|
|
32
|
+
padding: 0;
|
|
33
|
+
border: 0;
|
|
34
|
+
min-inline-size: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.form-group__title {
|
|
38
|
+
font-family: var(--typography-heading-font-family);
|
|
39
|
+
font-weight: var(--typography-heading-font-weight);
|
|
40
|
+
font-size: var(--typography-heading-font-size-sm);
|
|
41
|
+
line-height: var(--typography-heading-line-height-sm);
|
|
42
|
+
color: var(--form-group-title-color);
|
|
43
|
+
margin: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ----------------------------------------------------------------
|
|
47
|
+
* Form Field — single field with label, input, and helper/error
|
|
48
|
+
* ---------------------------------------------------------------- */
|
|
49
|
+
|
|
50
|
+
.form-field {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: var(--form-field-gap);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.form-field[data-label-position="side"] {
|
|
57
|
+
flex-direction: row;
|
|
58
|
+
align-items: flex-start;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.form-field[data-label-position="side"] > .field-label {
|
|
62
|
+
flex-shrink: 0;
|
|
63
|
+
inline-size: 8rem;
|
|
64
|
+
padding-block-start: var(--size-spacing-200);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.form-field[data-label-position="side"] > .form-field__body {
|
|
68
|
+
flex: 1;
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: var(--form-field-gap);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ----------------------------------------------------------------
|
|
75
|
+
* Helper and error text
|
|
76
|
+
* ---------------------------------------------------------------- */
|
|
77
|
+
|
|
78
|
+
.form-field__helper {
|
|
79
|
+
font-family: var(--typography-body-font-family);
|
|
80
|
+
font-size: var(--font-size-sm);
|
|
81
|
+
line-height: var(--line-height-sm);
|
|
82
|
+
color: var(--form-field-helper-text-color-default);
|
|
83
|
+
margin: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.form-field.is-invalid .form-field__helper {
|
|
87
|
+
color: var(--form-field-helper-text-color-invalid);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* ----------------------------------------------------------------
|
|
91
|
+
* Form Actions — button area at the bottom
|
|
92
|
+
* ---------------------------------------------------------------- */
|
|
93
|
+
|
|
94
|
+
.form-actions {
|
|
95
|
+
display: flex;
|
|
96
|
+
gap: var(--size-spacing-200);
|
|
97
|
+
justify-content: flex-end;
|
|
98
|
+
padding-block-start: var(--size-spacing-200);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.form-actions[data-align="start"] {
|
|
102
|
+
justify-content: flex-start;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.form-actions[data-align="stretch"] {
|
|
106
|
+
flex-direction: column;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.form-actions[data-align="stretch"] > * {
|
|
110
|
+
inline-size: 100%;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -7,25 +7,25 @@
|
|
|
7
7
|
font-weight: var(--input-font-weight);
|
|
8
8
|
font-size: var(--input-font-size);
|
|
9
9
|
line-height: var(--input-line-height, var(--button-line-height, 1.5));
|
|
10
|
-
color: var(--input-text-
|
|
11
|
-
background: var(--input-
|
|
10
|
+
color: var(--input-text-color-default);
|
|
11
|
+
background: var(--input-container-background-default);
|
|
12
12
|
border-style: solid;
|
|
13
13
|
border-width: var(--input-border-size-default);
|
|
14
|
-
border-color: var(--input-
|
|
14
|
+
border-color: var(--input-border-color-default);
|
|
15
15
|
border-radius: var(--input-border-radius);
|
|
16
16
|
padding-inline: var(--input-padding-inline);
|
|
17
17
|
padding-block: var(--input-padding-block);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.input::placeholder {
|
|
21
|
-
color: var(--input-text-
|
|
21
|
+
color: var(--input-text-color-placeholder);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
.input:hover,
|
|
25
25
|
.input.is-hover {
|
|
26
26
|
background:
|
|
27
27
|
linear-gradient(0deg, var(--input-overlay-hover), var(--input-overlay-hover)),
|
|
28
|
-
var(--input-
|
|
28
|
+
var(--input-container-background-default);
|
|
29
29
|
border-width: var(--input-border-size-hover);
|
|
30
30
|
padding-inline: calc(
|
|
31
31
|
var(--input-padding-inline) + var(--input-border-size-default) -
|
|
@@ -35,15 +35,15 @@
|
|
|
35
35
|
var(--input-padding-block) + var(--input-border-size-default) -
|
|
36
36
|
var(--input-border-size-hover)
|
|
37
37
|
);
|
|
38
|
-
border-color: var(--input-
|
|
39
|
-
color: var(--input-text-
|
|
38
|
+
border-color: var(--input-border-color-hover);
|
|
39
|
+
color: var(--input-text-color-hover);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
.input:active,
|
|
43
43
|
.input.is-active {
|
|
44
44
|
background:
|
|
45
45
|
linear-gradient(0deg, var(--input-overlay-active), var(--input-overlay-active)),
|
|
46
|
-
var(--input-
|
|
46
|
+
var(--input-container-background-default);
|
|
47
47
|
border-width: var(--input-border-size-active);
|
|
48
48
|
padding-inline: calc(
|
|
49
49
|
var(--input-padding-inline) + var(--input-border-size-default) -
|
|
@@ -53,14 +53,14 @@
|
|
|
53
53
|
var(--input-padding-block) + var(--input-border-size-default) -
|
|
54
54
|
var(--input-border-size-active)
|
|
55
55
|
);
|
|
56
|
-
border-color: var(--input-
|
|
57
|
-
color: var(--input-text-
|
|
56
|
+
border-color: var(--input-border-color-active);
|
|
57
|
+
color: var(--input-text-color-active);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
.input:focus-visible,
|
|
61
61
|
.input.is-focus-visible {
|
|
62
|
-
background: var(--input-
|
|
63
|
-
border-color: var(--input-
|
|
62
|
+
background: var(--input-container-background-focus);
|
|
63
|
+
border-color: var(--input-border-color-focus);
|
|
64
64
|
outline: none;
|
|
65
65
|
box-shadow: 0 0 0 var(--shadow-focus, 0) var(--color-focus, transparent);
|
|
66
66
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.tabs {
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.tab-list {
|
|
8
|
+
display: flex;
|
|
9
|
+
gap: 0;
|
|
10
|
+
border-block-end: var(--size-border-100) solid var(--color-border-default);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.tab-list[aria-orientation="vertical"] {
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
border-block-end: none;
|
|
16
|
+
border-inline-end: var(--size-border-100) solid var(--color-border-default);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.tab {
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
padding-inline: var(--size-spacing-400);
|
|
24
|
+
padding-block: var(--size-spacing-300);
|
|
25
|
+
font-family: var(--font-family-sans);
|
|
26
|
+
font-size: var(--font-size-md);
|
|
27
|
+
font-weight: var(--font-weight-500);
|
|
28
|
+
line-height: var(--line-height-md);
|
|
29
|
+
color: var(--color-text-default);
|
|
30
|
+
background: transparent;
|
|
31
|
+
border: none;
|
|
32
|
+
border-block-end: var(--size-border-200) solid transparent;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
transition: border-color 0.15s ease, color 0.15s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.tab:hover,
|
|
39
|
+
.tab.is-hover {
|
|
40
|
+
color: var(--color-text-brand);
|
|
41
|
+
border-block-end-color: var(--color-border-subtle);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.tab[aria-selected="true"],
|
|
45
|
+
.tab.is-selected {
|
|
46
|
+
color: var(--color-text-brand);
|
|
47
|
+
font-weight: var(--font-weight-600);
|
|
48
|
+
border-block-end-color: var(--color-border-brand);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.tab:focus-visible,
|
|
52
|
+
.tab.is-focus-visible {
|
|
53
|
+
outline: none;
|
|
54
|
+
box-shadow: inset 0 0 0 var(--shadow-focus) var(--color-focus);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.tab:disabled,
|
|
58
|
+
.tab.is-disabled {
|
|
59
|
+
color: var(--color-text-disabled);
|
|
60
|
+
cursor: not-allowed;
|
|
61
|
+
border-block-end-color: transparent;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.tab-panel {
|
|
65
|
+
padding-block: var(--size-spacing-400);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.tab-panel[hidden] {
|
|
69
|
+
display: none;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.textarea {
|
|
3
|
+
display: block;
|
|
4
|
+
inline-size: 100%;
|
|
5
|
+
min-block-size: calc(var(--line-height-md) * 3 + var(--size-spacing-300) * 2);
|
|
6
|
+
padding-inline: var(--size-spacing-300);
|
|
7
|
+
padding-block: var(--size-spacing-300);
|
|
8
|
+
font-family: var(--font-family-sans);
|
|
9
|
+
font-size: var(--font-size-md);
|
|
10
|
+
line-height: var(--line-height-md);
|
|
11
|
+
color: var(--color-text-default);
|
|
12
|
+
background: var(--color-fill-surface);
|
|
13
|
+
border: var(--size-border-100) solid var(--color-border-default);
|
|
14
|
+
border-radius: var(--size-radius-300);
|
|
15
|
+
resize: vertical;
|
|
16
|
+
transition: border-color 0.15s ease;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.textarea::placeholder {
|
|
20
|
+
color: var(--color-text-disabled);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.textarea:hover,
|
|
24
|
+
.textarea.is-hover {
|
|
25
|
+
border-color: var(--color-border-strong);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.textarea:focus-visible,
|
|
29
|
+
.textarea.is-focus-visible {
|
|
30
|
+
border-color: var(--color-focus);
|
|
31
|
+
outline: none;
|
|
32
|
+
box-shadow: 0 0 0 var(--shadow-focus) var(--color-focus);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.textarea:disabled,
|
|
36
|
+
.textarea.is-disabled {
|
|
37
|
+
color: var(--color-text-disabled);
|
|
38
|
+
background: var(--color-fill-disabled);
|
|
39
|
+
border-color: var(--color-border-disabled);
|
|
40
|
+
cursor: not-allowed;
|
|
41
|
+
resize: none;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.textarea[readonly] {
|
|
45
|
+
background: var(--color-fill-surface);
|
|
46
|
+
border-color: var(--color-border-default);
|
|
47
|
+
cursor: default;
|
|
48
|
+
resize: none;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
.tooltip {
|
|
3
|
+
position: absolute;
|
|
4
|
+
z-index: var(--zindex-tooltip);
|
|
5
|
+
max-inline-size: 15rem;
|
|
6
|
+
padding-inline: var(--size-spacing-300);
|
|
7
|
+
padding-block: var(--size-spacing-200);
|
|
8
|
+
font-family: var(--font-family-sans);
|
|
9
|
+
font-size: var(--font-size-sm);
|
|
10
|
+
line-height: var(--line-height-sm);
|
|
11
|
+
color: var(--color-text-inverse);
|
|
12
|
+
background: var(--color-neutral-900);
|
|
13
|
+
border-radius: var(--size-radius-300);
|
|
14
|
+
pointer-events: none;
|
|
15
|
+
opacity: 0;
|
|
16
|
+
transition: opacity 0.15s ease;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.tooltip.is-visible {
|
|
20
|
+
opacity: 1;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* ── Placement ── */
|
|
24
|
+
|
|
25
|
+
.tooltip[data-placement="top"] {
|
|
26
|
+
inset-block-end: 100%;
|
|
27
|
+
inset-inline-start: 50%;
|
|
28
|
+
transform: translateX(-50%);
|
|
29
|
+
margin-block-end: var(--size-spacing-200);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.tooltip[data-placement="bottom"] {
|
|
33
|
+
inset-block-start: 100%;
|
|
34
|
+
inset-inline-start: 50%;
|
|
35
|
+
transform: translateX(-50%);
|
|
36
|
+
margin-block-start: var(--size-spacing-200);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.tooltip[data-placement="left"] {
|
|
40
|
+
inset-inline-end: 100%;
|
|
41
|
+
inset-block-start: 50%;
|
|
42
|
+
transform: translateY(-50%);
|
|
43
|
+
margin-inline-end: var(--size-spacing-200);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.tooltip[data-placement="right"] {
|
|
47
|
+
inset-inline-start: 100%;
|
|
48
|
+
inset-block-start: 50%;
|
|
49
|
+
transform: translateY(-50%);
|
|
50
|
+
margin-inline-start: var(--size-spacing-200);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* ── Trigger wrapper ── */
|
|
54
|
+
|
|
55
|
+
.tooltip-trigger {
|
|
56
|
+
position: relative;
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.tooltip-trigger:hover > .tooltip,
|
|
61
|
+
.tooltip-trigger:focus-within > .tooltip {
|
|
62
|
+
opacity: 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/docs/agentic/README.md
CHANGED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Component Accessibility Audit Skill
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Create a repeatable, component-level accessibility audit workflow before implementation fixes.
|
|
6
|
+
|
|
7
|
+
Use this skill to evaluate one interactive component at a time and produce findings in a consistent format that can drive small follow-up PRs.
|
|
8
|
+
|
|
9
|
+
## Governance references (must read first)
|
|
10
|
+
|
|
11
|
+
1. `DESIGN.md`
|
|
12
|
+
2. `AGENTS.md`
|
|
13
|
+
3. `docs/playbook.md`
|
|
14
|
+
4. `docs/working-context.md`
|
|
15
|
+
5. `docs/ui-foundations-rules.md`
|
|
16
|
+
6. `docs/foundations/`
|
|
17
|
+
7. `docs/agentic/assistant-behavior-rules.md`
|
|
18
|
+
8. `IMPLEMENTATION.md`
|
|
19
|
+
|
|
20
|
+
Never contradict these sources. Prefer explicit, verifiable findings over assumptions.
|
|
21
|
+
|
|
22
|
+
## Scope
|
|
23
|
+
|
|
24
|
+
Apply this skill to interactive components (e.g., Button, Link, Input, Select, Checkbox, Radio, Switch, Tabs, Accordion, Modal, Flyout, Dropdown, Tooltip, Pagination, Show More/Show Less, Tags).
|
|
25
|
+
|
|
26
|
+
Do not use this skill to implement broad fixes in the same PR. This skill is audit-first.
|
|
27
|
+
|
|
28
|
+
## Audit workflow (repeatable)
|
|
29
|
+
|
|
30
|
+
1. **Plan**
|
|
31
|
+
- Select exactly one component target.
|
|
32
|
+
- Confirm component surfaces in scope (CSS pattern, macro/template, React wrapper, docs, tests).
|
|
33
|
+
|
|
34
|
+
2. **Collect evidence**
|
|
35
|
+
- Inspect source implementation files.
|
|
36
|
+
- Inspect usage examples and docs.
|
|
37
|
+
- Inspect test coverage.
|
|
38
|
+
- Record exact file paths and relevant lines.
|
|
39
|
+
|
|
40
|
+
3. **Run checks**
|
|
41
|
+
- Semantic HTML
|
|
42
|
+
- Accessible names
|
|
43
|
+
- Keyboard behavior
|
|
44
|
+
- Focus management
|
|
45
|
+
- ARIA/state handling
|
|
46
|
+
- Form association (where relevant)
|
|
47
|
+
- Icon-only usage
|
|
48
|
+
- Contrast/token risks
|
|
49
|
+
- Test coverage
|
|
50
|
+
- Documentation gaps
|
|
51
|
+
- Manual screen reader validation needs
|
|
52
|
+
|
|
53
|
+
4. **Score severity**
|
|
54
|
+
- Assign one severity per finding using the model below.
|
|
55
|
+
|
|
56
|
+
5. **Propose minimal fix**
|
|
57
|
+
- Suggest the smallest safe change that resolves the finding.
|
|
58
|
+
- Keep fixes scoped to one component per follow-up PR.
|
|
59
|
+
|
|
60
|
+
6. **Report**
|
|
61
|
+
- Output findings using the template in this document.
|
|
62
|
+
|
|
63
|
+
## Severity model
|
|
64
|
+
|
|
65
|
+
Use one of these labels:
|
|
66
|
+
|
|
67
|
+
- **blocker**
|
|
68
|
+
- Breaks core accessibility behavior (e.g., no accessible name, unusable keyboard path, broken form semantics, missing focus trap in modal).
|
|
69
|
+
- Should be fixed before release.
|
|
70
|
+
|
|
71
|
+
- **high**
|
|
72
|
+
- Major accessibility risk with likely user impact, but possible workaround exists.
|
|
73
|
+
- Prioritize immediately after blockers.
|
|
74
|
+
|
|
75
|
+
- **medium**
|
|
76
|
+
- Important gap or drift that reduces accessibility quality/reliability.
|
|
77
|
+
- Schedule in near-term follow-up.
|
|
78
|
+
|
|
79
|
+
- **low**
|
|
80
|
+
- Minor issue, documentation gap, or optimization with limited immediate impact.
|
|
81
|
+
- Track and resolve in routine improvements.
|
|
82
|
+
|
|
83
|
+
## Findings template
|
|
84
|
+
|
|
85
|
+
Use this exact structure for each finding:
|
|
86
|
+
|
|
87
|
+
- **Component:**
|
|
88
|
+
- **Check area:** (semantic HTML / accessible name / keyboard / focus / ARIA-state / form association / icon-only / contrast-token / tests / docs / manual SR)
|
|
89
|
+
- **Observed behavior:**
|
|
90
|
+
- **Expected behavior:**
|
|
91
|
+
- **Evidence:** (file paths + line refs)
|
|
92
|
+
- **Severity:** blocker | high | medium | low
|
|
93
|
+
- **Minimal fix strategy:**
|
|
94
|
+
- **Follow-up test need:**
|
|
95
|
+
- **Manual SR validation need:**
|
|
96
|
+
|
|
97
|
+
## Minimal-fix strategy
|
|
98
|
+
|
|
99
|
+
When proposing a fix:
|
|
100
|
+
|
|
101
|
+
1. Prefer native semantics over custom ARIA.
|
|
102
|
+
2. Change the smallest surface that safely resolves the issue.
|
|
103
|
+
3. Keep API compatibility unless current API is inherently inaccessible.
|
|
104
|
+
4. Update docs and tests in the same small PR when behavior changes.
|
|
105
|
+
5. Avoid cross-component refactors in accessibility fix PRs.
|
|
106
|
+
|
|
107
|
+
## Manual screen reader validation guidance
|
|
108
|
+
|
|
109
|
+
For each audited component, explicitly state whether manual SR validation is needed and why.
|
|
110
|
+
|
|
111
|
+
Recommended baseline matrix:
|
|
112
|
+
- VoiceOver + Safari (macOS)
|
|
113
|
+
- NVDA + Firefox (Windows)
|
|
114
|
+
- Optional: JAWS + Chrome for enterprise parity
|
|
115
|
+
|
|
116
|
+
Validate at minimum:
|
|
117
|
+
- role announcement
|
|
118
|
+
- name announcement
|
|
119
|
+
- state announcement
|
|
120
|
+
- focus order
|
|
121
|
+
- action feedback after interaction
|
|
122
|
+
|
|
123
|
+
## Example audit prompt (single component)
|
|
124
|
+
|
|
125
|
+
> Audit the `Link` component only using the Component Accessibility Audit Skill. Check semantic HTML, accessible names, keyboard behavior, focus management, ARIA/state handling, icon-only usage, contrast/token risks, tests, docs, and manual screen reader validation needs. Output findings using the required template and assign severity with blocker/high/medium/low. Do not implement fixes.
|
|
126
|
+
|
|
127
|
+
## Output expectations
|
|
128
|
+
|
|
129
|
+
- Be explicit and evidence-based.
|
|
130
|
+
- Distinguish verified findings from assumptions.
|
|
131
|
+
- Keep findings actionable for small follow-up PRs.
|
|
132
|
+
- If not verified, mark as "not verified".
|
|
@@ -22,7 +22,7 @@ Provide a consistent typography API with low selector specificity and predictabl
|
|
|
22
22
|
|
|
23
23
|
4. Use `:where()` for zero-specificity size/scale selectors where possible.
|
|
24
24
|
|
|
25
|
-
5. Reserve data attributes (for example `[data-
|
|
25
|
+
5. Reserve data attributes (for example `[data-brand]`, `[data-mode]`, `[data-density]`) for context/state, not as primary styling API.
|
|
26
26
|
|
|
27
27
|
## Implications
|
|
28
28
|
|