@plexui/styles 0.0.0-stage → 0.1.1
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 +21 -0
- package/README.md +28 -2
- package/dist/es/components/Accordion/Accordion.module.css +89 -0
- package/dist/es/components/Alert/Alert.module.css +210 -0
- package/dist/es/components/Avatar/Avatar.module.css +168 -0
- package/dist/es/components/Avatar/AvatarGroup.module.css +26 -0
- package/dist/es/components/Badge/Badge.module.css +196 -0
- package/dist/es/components/Breadcrumb/Breadcrumb.module.css +59 -0
- package/dist/es/components/Button/Button.module.css +863 -0
- package/dist/es/components/ButtonGroup/ButtonGroup.module.css +158 -0
- package/dist/es/components/Card/Card.module.css +125 -0
- package/dist/es/components/Checkbox/Checkbox.module.css +225 -0
- package/dist/es/components/CodeBlock/CodeBlock.module.css +139 -0
- package/dist/es/components/DataTable/DataTable.module.css +117 -0
- package/dist/es/components/DatePicker/Calendar.module.css +271 -0
- package/dist/es/components/DateRangePicker/Calendar.module.css +295 -0
- package/dist/es/components/DateRangePicker/Trigger.module.css +25 -0
- package/dist/es/components/Dialog/Dialog.module.css +240 -0
- package/dist/es/components/EmptyMessage/EmptyMessage.module.css +116 -0
- package/dist/es/components/Field/Field.module.css +152 -0
- package/dist/es/components/FieldError/FieldError.module.css +28 -0
- package/dist/es/components/FileUpload/FileUpload.module.css +133 -0
- package/dist/es/components/FloatingLabelInput/FloatingLabelInput.module.css +220 -0
- package/dist/es/components/FloatingLabelSelect/FloatingLabelSelect.module.css +152 -0
- package/dist/es/components/Image/Image.module.css +9 -0
- package/dist/es/components/Indicator/CircularProgress.module.css +28 -0
- package/dist/es/components/Indicator/LoadingDots.module.css +35 -0
- package/dist/es/components/Indicator/LoadingIndicator.module.css +41 -0
- package/dist/es/components/Input/Input.module.css +519 -0
- package/dist/es/components/InputGroup/InputGroup.module.css +309 -0
- package/dist/es/components/Kbd/Kbd.module.css +47 -0
- package/dist/es/components/Label/Label.module.css +16 -0
- package/dist/es/components/Markdown/Markdown.module.css +233 -0
- package/dist/es/components/MarkdownEditor/MarkdownEditor.module.css +297 -0
- package/dist/es/components/Menu/Menu.module.css +389 -0
- package/dist/es/components/OTPInput/OTPInput.module.css +70 -0
- package/dist/es/components/Popover/Popover.module.css +82 -0
- package/dist/es/components/Progress/Progress.module.css +34 -0
- package/dist/es/components/ProgressSteps/ProgressSteps.module.css +246 -0
- package/dist/es/components/RadioGroup/RadioGroup.module.css +159 -0
- package/dist/es/components/Select/Select.module.css +341 -0
- package/dist/es/components/SelectControl/SelectControl.module.css +558 -0
- package/dist/es/components/Separator/Separator.module.css +16 -0
- package/dist/es/components/ShimmerText/ShimmerText.module.css +43 -0
- package/dist/es/components/Sidebar/Sidebar.module.css +913 -0
- package/dist/es/components/Skeleton/Skeleton.module.css +17 -0
- package/dist/es/components/Slider/Slider.module.css +199 -0
- package/dist/es/components/StatCard/StatCard.module.css +234 -0
- package/dist/es/components/Switch/Switch.module.css +121 -0
- package/dist/es/components/Table/Table.module.css +56 -0
- package/dist/es/components/Tabs/Tabs.module.css +688 -0
- package/dist/es/components/TagInput/TagInput.module.css +320 -0
- package/dist/es/components/TextLink/TextLink.module.css +50 -0
- package/dist/es/components/Textarea/Textarea.module.css +272 -0
- package/dist/es/components/Toast/Toast.module.css +99 -0
- package/dist/es/components/Tooltip/Tooltip.module.css +91 -0
- package/dist/es/components/Transition/Animate.module.css +54 -0
- package/dist/es/components/Transition/AnimateLayout.module.css +101 -0
- package/dist/es/components/Transition/AnimateLayoutGroup.module.css +88 -0
- package/dist/es/components/Transition/TransitionGroup.module.css +4 -0
- package/dist/es/styles/base.css +102 -0
- package/dist/es/styles/globals.css +50 -0
- package/dist/es/styles/index.css +22 -0
- package/dist/es/styles/katex.min.css +1296 -0
- package/dist/es/styles/tailwind-utilities.css +1316 -0
- package/dist/es/styles/touch.css +71 -0
- package/dist/es/styles/variables-components.css +626 -0
- package/dist/es/styles/variables-primitive.css +327 -0
- package/dist/es/styles/variables-semantic.css +629 -0
- package/dist/es/styles/variables-tailwind-theme.css +34 -0
- package/dist/es/styles/variables-tokens-root.css +40 -0
- package/dist/es/types.js +4 -0
- package/dist/es/types.js.map +1 -0
- package/dist/es/vite/index.js +54 -0
- package/dist/es/vite/index.js.map +1 -0
- package/dist/types/types.d.ts +15 -0
- package/dist/types/vite/index.d.ts +55 -0
- package/package.json +109 -4
- package/postcss/functions.mjs +23 -0
- package/postcss/injectBreakpoints.mjs +47 -0
- package/postcss/mixins.mjs +100 -0
- package/postcss/parseLightDark.mjs +174 -0
- package/postcss/wrapModulesInLayer.mjs +21 -0
- package/postcss.config.mjs +52 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
@layer components {.Root {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: stretch;
|
|
4
|
+
width: -moz-fit-content;
|
|
5
|
+
width: fit-content;
|
|
6
|
+
|
|
7
|
+
/* Inputs inside a ButtonGroup share the row and flex to fill space —
|
|
8
|
+
the rule targets raw <input>, the Plex Input Container (data-slot),
|
|
9
|
+
and a nested sub-ButtonGroup that wraps an Input (e.g. Input Group
|
|
10
|
+
pattern: [leading action] [Input + inline addon]). */
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Let focused item sit on top of neighbors so the ring isn't clipped */
|
|
14
|
+
.Root > * {
|
|
15
|
+
position: relative;
|
|
16
|
+
}
|
|
17
|
+
.Root > *:focus-visible,
|
|
18
|
+
.Root > *:focus-within {
|
|
19
|
+
z-index: 1;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Gap only appears between nested groups — joined buttons stay touching */
|
|
23
|
+
.Root:has(> [data-slot="button-group"]) {
|
|
24
|
+
gap: var(--button-group-nested-gap);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Horizontal — default. Plex Button variant="outline" renders its 1px
|
|
28
|
+
border via an inset box-shadow on its ::before pseudo — stripping the
|
|
29
|
+
left `border-inline-start` does nothing. Instead we (a) overlap items
|
|
30
|
+
by -1px and (b) clip 1px off the leading edge of the ::before of
|
|
31
|
+
every non-first child, so the inset shadow of item N+1 doesn't sit
|
|
32
|
+
next to the inset shadow of item N (which would read as a doubled
|
|
33
|
+
2px line). Focus ring lives on ::after, so clip-path on ::before
|
|
34
|
+
leaves the focus ring intact.
|
|
35
|
+
|
|
36
|
+
Separators are excluded — they need to render visibly BETWEEN items,
|
|
37
|
+
not be overlapped into oblivion. Adjacent items to a separator keep
|
|
38
|
+
their edge radii stripped, but skip the -1px/-clip trickery. */
|
|
39
|
+
.Root[data-orientation="horizontal"] > *:not(:first-child):not([data-slot="button-group-separator"]) {
|
|
40
|
+
border-start-start-radius: 0;
|
|
41
|
+
border-end-start-radius: 0;
|
|
42
|
+
}
|
|
43
|
+
.Root[data-orientation="horizontal"]
|
|
44
|
+
> *:not(:first-child):not([data-slot="button-group-separator"]):not(
|
|
45
|
+
[data-slot="button-group-separator"] + *
|
|
46
|
+
) {
|
|
47
|
+
margin-inline-start: -1px;
|
|
48
|
+
}
|
|
49
|
+
.Root[data-orientation="horizontal"]
|
|
50
|
+
> *:not(:first-child):not([data-slot="button-group-separator"]):not(
|
|
51
|
+
[data-slot="button-group-separator"] + *
|
|
52
|
+
)::before {
|
|
53
|
+
clip-path: inset(0 0 0 1px);
|
|
54
|
+
}
|
|
55
|
+
.Root[data-orientation="horizontal"]
|
|
56
|
+
> *:not(:last-child):not([data-slot="button-group-separator"]):not(
|
|
57
|
+
:has(+ [data-slot="button-group-separator"])
|
|
58
|
+
) {
|
|
59
|
+
border-start-end-radius: 0;
|
|
60
|
+
border-end-end-radius: 0;
|
|
61
|
+
}
|
|
62
|
+
/* Strip the edge radius on items sitting directly next to a separator */
|
|
63
|
+
.Root[data-orientation="horizontal"] > [data-slot="button-group-separator"] + * {
|
|
64
|
+
border-start-start-radius: 0;
|
|
65
|
+
border-end-start-radius: 0;
|
|
66
|
+
}
|
|
67
|
+
.Root[data-orientation="horizontal"] > *:has(+ [data-slot="button-group-separator"]) {
|
|
68
|
+
border-start-end-radius: 0;
|
|
69
|
+
border-end-end-radius: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Vertical — same approach, clip the top 1px of ::before on non-first */
|
|
73
|
+
.Root[data-orientation="vertical"] {
|
|
74
|
+
flex-direction: column;
|
|
75
|
+
}
|
|
76
|
+
.Root[data-orientation="vertical"] > *:not(:first-child):not([data-slot="button-group-separator"]) {
|
|
77
|
+
border-start-start-radius: 0;
|
|
78
|
+
border-start-end-radius: 0;
|
|
79
|
+
}
|
|
80
|
+
.Root[data-orientation="vertical"]
|
|
81
|
+
> *:not(:first-child):not([data-slot="button-group-separator"]):not(
|
|
82
|
+
[data-slot="button-group-separator"] + *
|
|
83
|
+
) {
|
|
84
|
+
margin-block-start: -1px;
|
|
85
|
+
}
|
|
86
|
+
.Root[data-orientation="vertical"]
|
|
87
|
+
> *:not(:first-child):not([data-slot="button-group-separator"]):not(
|
|
88
|
+
[data-slot="button-group-separator"] + *
|
|
89
|
+
)::before {
|
|
90
|
+
clip-path: inset(1px 0 0 0);
|
|
91
|
+
}
|
|
92
|
+
.Root[data-orientation="vertical"]
|
|
93
|
+
> *:not(:last-child):not([data-slot="button-group-separator"]):not(
|
|
94
|
+
:has(+ [data-slot="button-group-separator"])
|
|
95
|
+
) {
|
|
96
|
+
border-end-start-radius: 0;
|
|
97
|
+
border-end-end-radius: 0;
|
|
98
|
+
}
|
|
99
|
+
.Root[data-orientation="vertical"] > [data-slot="button-group-separator"] + * {
|
|
100
|
+
border-start-start-radius: 0;
|
|
101
|
+
border-start-end-radius: 0;
|
|
102
|
+
}
|
|
103
|
+
.Root[data-orientation="vertical"] > *:has(+ [data-slot="button-group-separator"]) {
|
|
104
|
+
border-end-start-radius: 0;
|
|
105
|
+
border-end-end-radius: 0;
|
|
106
|
+
}
|
|
107
|
+
.Root > input,
|
|
108
|
+
.Root > [data-slot="input"],
|
|
109
|
+
.Root > [data-slot="button-group"]:has(> [data-slot="input"]) {
|
|
110
|
+
flex: 1 1 auto;
|
|
111
|
+
}/* Text — a muted label pill that slots into a ButtonGroup alongside
|
|
112
|
+
Buttons. Uses an inset box-shadow border (same trick Button uses for
|
|
113
|
+
variant="outline") so the group's edge-clipping rules (::before
|
|
114
|
+
clip-path) also work here and collapse the doubled 1px edge. */.Text {
|
|
115
|
+
position: relative;
|
|
116
|
+
display: inline-flex;
|
|
117
|
+
align-items: center;
|
|
118
|
+
gap: calc(var(--spacing) * 2);
|
|
119
|
+
padding-inline: calc(var(--spacing) * 4);
|
|
120
|
+
align-self: stretch;
|
|
121
|
+
background: var(--button-group-text-background);
|
|
122
|
+
color: var(--button-group-text-color);
|
|
123
|
+
font-size: var(--button-group-text-font-size);
|
|
124
|
+
font-weight: var(--button-group-text-font-weight);
|
|
125
|
+
line-height: 1;
|
|
126
|
+
white-space: nowrap;
|
|
127
|
+
border-radius: var(--radius-md);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.Text::before {
|
|
131
|
+
content: "";
|
|
132
|
+
position: absolute;
|
|
133
|
+
inset: 0;
|
|
134
|
+
border-radius: inherit;
|
|
135
|
+
box-shadow: 0 0 0 1px var(--button-group-text-border-color) inset;
|
|
136
|
+
pointer-events: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.Text svg {
|
|
140
|
+
width: 1em;
|
|
141
|
+
height: 1em;
|
|
142
|
+
flex-shrink: 0;
|
|
143
|
+
}/* Separator used between items inside a ButtonGroup.
|
|
144
|
+
Sits above the neighbor buttons (z-index) so the 1px line isn't
|
|
145
|
+
visually swallowed by the adjacent box-shadow borders. Parent-scoped
|
|
146
|
+
selector beats the base Separator class so the stronger color wins. */.Root > .Separator {
|
|
147
|
+
position: relative;
|
|
148
|
+
z-index: 1;
|
|
149
|
+
align-self: stretch;
|
|
150
|
+
margin: 0;
|
|
151
|
+
flex-shrink: 0;
|
|
152
|
+
background: var(--button-group-separator-color);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.Root > .Separator[data-orientation="vertical"] {
|
|
156
|
+
height: auto;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
@layer components {.Card {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: var(--card-gap);
|
|
5
|
+
width: 100%;
|
|
6
|
+
min-width: 0;
|
|
7
|
+
padding: var(--card-padding);
|
|
8
|
+
border-radius: var(--card-radius);
|
|
9
|
+
background: var(--card-background);
|
|
10
|
+
color: var(--card-text-color);
|
|
11
|
+
box-shadow: 0 0 0 1px var(--card-border-color) inset;
|
|
12
|
+
font-size: var(--card-font-size);
|
|
13
|
+
line-height: var(--font-text-sm-line-height);
|
|
14
|
+
transition-duration: var(--transition-duration-basic);
|
|
15
|
+
transition-property: background-color, box-shadow, border-color;
|
|
16
|
+
transition-timing-function: var(--transition-ease-basic);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* When used as a link, flatten anchor defaults */
|
|
20
|
+
.Card:where(a) {
|
|
21
|
+
color: inherit;
|
|
22
|
+
text-decoration: none;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* =============================================
|
|
26
|
+
Interactive
|
|
27
|
+
============================================= */
|
|
28
|
+
.Card:where([data-interactive]) {
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.Card:where([data-interactive]):hover {
|
|
33
|
+
--card-background: var(--card-background-hover);
|
|
34
|
+
--card-border-color: var(--card-border-color-hover);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.Card:where([data-interactive]):focus-visible {
|
|
38
|
+
outline: 2px solid var(--color-ring);
|
|
39
|
+
outline-offset: 2px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* =============================================
|
|
43
|
+
Sizes
|
|
44
|
+
============================================= */
|
|
45
|
+
.Card:where([data-size="sm"]) {
|
|
46
|
+
--card-padding: calc(var(--spacing) * 4);
|
|
47
|
+
--card-gap: calc(var(--spacing) * 3);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.Card:where([data-size="md"]) {
|
|
51
|
+
--card-padding: calc(var(--spacing) * 5);
|
|
52
|
+
--card-gap: calc(var(--spacing) * 4);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.Card:where([data-size="lg"]) {
|
|
56
|
+
--card-padding: calc(var(--spacing) * 6);
|
|
57
|
+
--card-gap: calc(var(--spacing) * 5);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* =============================================
|
|
61
|
+
Variants
|
|
62
|
+
============================================= */
|
|
63
|
+
.Card:where([data-variant="outline"]) {
|
|
64
|
+
--card-background: var(--color-surface);
|
|
65
|
+
--card-border-color: var(--color-border);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.Card:where([data-variant="solid"]) {
|
|
69
|
+
--card-background: var(--color-surface-secondary);
|
|
70
|
+
--card-border-color: transparent;
|
|
71
|
+
box-shadow: none;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.Card:where([data-variant="ghost"]) {
|
|
75
|
+
--card-background: transparent;
|
|
76
|
+
--card-border-color: transparent;
|
|
77
|
+
box-shadow: none;
|
|
78
|
+
padding: 0;
|
|
79
|
+
}/* ================================================
|
|
80
|
+
Header — stacked title + description
|
|
81
|
+
================================================ */.Header {
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-direction: column;
|
|
84
|
+
position: relative;
|
|
85
|
+
min-width: 0;
|
|
86
|
+
}.Title {
|
|
87
|
+
margin: 0 0 calc(var(--spacing) * 1.5);
|
|
88
|
+
color: var(--card-title-color);
|
|
89
|
+
font-size: var(--card-title-font-size);
|
|
90
|
+
font-weight: var(--card-title-font-weight);
|
|
91
|
+
line-height: var(--font-heading-xs-line-height);
|
|
92
|
+
letter-spacing: var(--font-heading-xs-tracking);
|
|
93
|
+
text-wrap: balance;
|
|
94
|
+
}.Description {
|
|
95
|
+
margin: calc(calc(var(--spacing) * 1.5) * -1) 0 0;
|
|
96
|
+
color: var(--card-description-color);
|
|
97
|
+
font-size: var(--card-description-font-size);
|
|
98
|
+
line-height: var(--font-text-sm-line-height);
|
|
99
|
+
text-wrap: pretty;
|
|
100
|
+
}/* ================================================
|
|
101
|
+
Content — primary body
|
|
102
|
+
================================================ */.Content {
|
|
103
|
+
display: flex;
|
|
104
|
+
flex-direction: column;
|
|
105
|
+
gap: calc(var(--spacing) * 3);
|
|
106
|
+
min-width: 0;
|
|
107
|
+
}/* ================================================
|
|
108
|
+
Footer — aligned actions
|
|
109
|
+
================================================ */.Footer {
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
gap: calc(var(--spacing) * 2);
|
|
113
|
+
min-width: 0;
|
|
114
|
+
margin-top: calc(var(--spacing) * 3);
|
|
115
|
+
}/* ================================================
|
|
116
|
+
Action — top-right slot in Header
|
|
117
|
+
================================================ */.Action {
|
|
118
|
+
position: absolute;
|
|
119
|
+
top: 0;
|
|
120
|
+
right: 0;
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
gap: calc(var(--spacing) * 1);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
@layer components {.Container {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: flex;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.Container[data-has-label] {
|
|
7
|
+
align-items: flex-start;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.Container[data-orientation="right"] {
|
|
11
|
+
flex-direction: row-reverse;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.Container[data-disabled] {
|
|
15
|
+
opacity: 0.5;
|
|
16
|
+
cursor: not-allowed;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Radix pushes the inputs off screen in a weird way that
|
|
20
|
+
messes with error overlays */
|
|
21
|
+
.Container > input {
|
|
22
|
+
right: 0;
|
|
23
|
+
bottom: 0;
|
|
24
|
+
left: 0;
|
|
25
|
+
height: 1px !important;
|
|
26
|
+
transform: none !important;
|
|
27
|
+
}.Checkbox {
|
|
28
|
+
position: relative;
|
|
29
|
+
display: inline-flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
flex-shrink: 0;
|
|
33
|
+
width: var(--checkbox-indicator-size);
|
|
34
|
+
max-width: var(--checkbox-indicator-size);
|
|
35
|
+
height: var(--checkbox-indicator-size);
|
|
36
|
+
/* Center indicator with first line of label text (mirrors RadioGroup's RadioIndicatorWrapper approach) */
|
|
37
|
+
margin-top: calc((var(--checkbox-label-line-height) - var(--checkbox-indicator-size)) / 2);
|
|
38
|
+
padding: 0;
|
|
39
|
+
border: 1px solid var(--alpha-16);
|
|
40
|
+
border-radius: var(--radius-xs);
|
|
41
|
+
background-color: transparent;
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
transition:
|
|
44
|
+
border-color 150ms ease,
|
|
45
|
+
background-color 150ms ease;
|
|
46
|
+
}
|
|
47
|
+
@media (hover: hover) and (pointer: fine) {.Checkbox:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
48
|
+
border-color: var(--alpha-20);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.Checkbox[data-state="indeterminate"],
|
|
53
|
+
.Checkbox[data-state="checked"] {
|
|
54
|
+
border-color: var(--gray-900);
|
|
55
|
+
background-color: var(--gray-900);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.Checkbox:focus {
|
|
59
|
+
outline: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.Checkbox:focus-visible {
|
|
63
|
+
outline: 2px solid var(--color-ring);
|
|
64
|
+
outline-offset: 2px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* =============================================
|
|
68
|
+
Invalid
|
|
69
|
+
============================================= */
|
|
70
|
+
.Checkbox[aria-invalid="true"] {
|
|
71
|
+
border-color: var(--input-border-color-invalid);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.Checkbox[aria-invalid="true"][data-state="indeterminate"],
|
|
75
|
+
.Checkbox[aria-invalid="true"][data-state="checked"] {
|
|
76
|
+
border-color: var(--input-border-color-invalid);
|
|
77
|
+
background-color: var(--input-border-color-invalid);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.Checkbox[data-disabled] {
|
|
81
|
+
cursor: not-allowed;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* =============================================
|
|
85
|
+
Pill
|
|
86
|
+
============================================= */
|
|
87
|
+
.Checkbox[data-pill] {
|
|
88
|
+
border-radius: var(--radius-full);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* =============================================
|
|
92
|
+
Ghost variant
|
|
93
|
+
============================================= */
|
|
94
|
+
.Checkbox[data-variant="ghost"] {
|
|
95
|
+
border-color: transparent;
|
|
96
|
+
background-color: transparent;
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
@media (hover: hover) and (pointer: fine) {.Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
100
|
+
border-color: transparent;
|
|
101
|
+
}.Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover, :where([data-theme="light"]) .Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
102
|
+
background-color: var(--gray-50);
|
|
103
|
+
}:where([data-theme="dark"]) .Checkbox[data-variant="ghost"]:where(:not([data-disabled], [data-state="checked"])):hover {
|
|
104
|
+
background-color: var(--gray-800);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.Checkbox[data-variant="ghost"][data-state="indeterminate"],
|
|
109
|
+
.Checkbox[data-variant="ghost"][data-state="checked"] {
|
|
110
|
+
border-color: transparent;
|
|
111
|
+
background-color: transparent;
|
|
112
|
+
}.CheckMark {
|
|
113
|
+
position: absolute;
|
|
114
|
+
top: 0;
|
|
115
|
+
left: 0;
|
|
116
|
+
width: 64%;
|
|
117
|
+
height: 32%;
|
|
118
|
+
transform: rotate(-45deg) translate(-10%, 100%);
|
|
119
|
+
transform-origin: center;
|
|
120
|
+
transition:
|
|
121
|
+
opacity 150ms ease,
|
|
122
|
+
transform 150ms ease;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Radix mounts the indicator on every check, so the entry animation would
|
|
126
|
+
also play for every checked box on first render or when a tab with
|
|
127
|
+
checkboxes opens. It plays only for the checkbox in use: hovered, or
|
|
128
|
+
focused from the keyboard. */
|
|
129
|
+
@starting-style {
|
|
130
|
+
.Container:is(:hover, :focus-within) .CheckMark {
|
|
131
|
+
opacity: 0
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
[data-state="indeterminate"] .CheckMark {
|
|
136
|
+
transform: translate(30%, 80%);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
[data-state="indeterminate"] .CheckMark::before {
|
|
140
|
+
opacity: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* CheckMark arms */
|
|
144
|
+
.CheckMark::before,
|
|
145
|
+
.CheckMark::after {
|
|
146
|
+
position: absolute;
|
|
147
|
+
display: block;
|
|
148
|
+
background: var(--gray-0);
|
|
149
|
+
content: "";
|
|
150
|
+
will-change: transform;
|
|
151
|
+
}
|
|
152
|
+
@starting-style {
|
|
153
|
+
|
|
154
|
+
.Container:is(:hover, :focus-within) .CheckMark::before, .Container:is(:hover, :focus-within) .CheckMark::after {
|
|
155
|
+
transform: scale(0)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* Ghost variant — checkmark uses text color instead of white */
|
|
160
|
+
[data-variant="ghost"] .CheckMark::before,
|
|
161
|
+
[data-variant="ghost"] .CheckMark::after {
|
|
162
|
+
background: var(--gray-900);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.CheckMark::before {
|
|
166
|
+
top: 0;
|
|
167
|
+
bottom: 0;
|
|
168
|
+
left: 0;
|
|
169
|
+
width: 2px;
|
|
170
|
+
transform-origin: 0 0;
|
|
171
|
+
transition:
|
|
172
|
+
transform 100ms ease 80ms,
|
|
173
|
+
opacity 200ms ease;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.CheckMark [data-state="indeterminate"]::before {
|
|
177
|
+
opacity: 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.CheckMark::after {
|
|
181
|
+
right: 0;
|
|
182
|
+
bottom: 0;
|
|
183
|
+
left: 0;
|
|
184
|
+
height: 2px;
|
|
185
|
+
transform-origin: 0 100%;
|
|
186
|
+
transition: transform 100ms ease 160ms;
|
|
187
|
+
}.Label {
|
|
188
|
+
display: block;
|
|
189
|
+
min-height: var(--checkbox-label-line-height);
|
|
190
|
+
cursor: pointer;
|
|
191
|
+
font-size: 14px;
|
|
192
|
+
line-height: var(--checkbox-label-line-height);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
[data-orientation="left"] .Label {
|
|
196
|
+
padding-left: var(--checkbox-label-gap);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
[data-orientation="right"] .Label {
|
|
200
|
+
padding-right: calc(var(--spacing) * 3);
|
|
201
|
+
}/* Label with a second line: the group carries the gap, the label inside it does not */.LabelGroup {
|
|
202
|
+
display: flex;
|
|
203
|
+
flex-direction: column;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
[data-orientation="left"] .LabelGroup {
|
|
207
|
+
padding-left: var(--checkbox-label-gap);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
[data-orientation="right"] .LabelGroup {
|
|
211
|
+
padding-right: calc(var(--spacing) * 3);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.LabelGroup > .Label {
|
|
215
|
+
padding-inline: 0;
|
|
216
|
+
}.Description {
|
|
217
|
+
color: var(--color-text-secondary);
|
|
218
|
+
font-size: var(--font-text-xs-size);
|
|
219
|
+
line-height: var(--font-text-xs-line-height);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
[data-disabled] .Description {
|
|
223
|
+
cursor: not-allowed;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
@layer components {.CodeBlock {
|
|
2
|
+
position: relative;
|
|
3
|
+
border: none;
|
|
4
|
+
border-radius: 10px;
|
|
5
|
+
background-color: var(--codeblock-background-color);
|
|
6
|
+
}.CopyButtonContainer {
|
|
7
|
+
position: absolute;
|
|
8
|
+
top: 8px;
|
|
9
|
+
right: 8px;
|
|
10
|
+
box-sizing: border-box;
|
|
11
|
+
display: grid;
|
|
12
|
+
place-items: center;
|
|
13
|
+
width: 32px;
|
|
14
|
+
height: 32px;
|
|
15
|
+
border-radius: 8px;
|
|
16
|
+
background-color: var(--color-surface-elevated-secondary);
|
|
17
|
+
color: var(--color-text-secondary);
|
|
18
|
+
/* Extend the codeblock's surface colour 8px to the right of the
|
|
19
|
+
* button so horizontally-overflowing code text doesn't peek through
|
|
20
|
+
* the gap between the button's right edge and the codeblock's right
|
|
21
|
+
* edge. The shadow renders behind the button bg (on top of the
|
|
22
|
+
* scrolling <pre>), masking that 8px band. */
|
|
23
|
+
box-shadow: 8px 0 0 0 var(--codeblock-background-color);
|
|
24
|
+
}/* Force the CopyButton to inherit the container's color on all states.
|
|
25
|
+
The ghost-secondary hover background (rendered via the Button's
|
|
26
|
+
::before pseudo-element) is intentionally NOT suppressed here —
|
|
27
|
+
it's what gives the copy icon a visible hover affordance on the
|
|
28
|
+
light-grey codeblock surface. (A previous version of this rule
|
|
29
|
+
zeroed ::before to keep the hover invisible; see commit history
|
|
30
|
+
for the regression that caused.) */.CopyButtonContainer button {
|
|
31
|
+
color: inherit !important;
|
|
32
|
+
padding: 0 !important;
|
|
33
|
+
-webkit-tap-highlight-color: transparent;
|
|
34
|
+
}/* The button's own outline stays off; keyboard focus shows Button's
|
|
35
|
+
::after ring */.CopyButtonContainer button:focus,
|
|
36
|
+
.CopyButtonContainer button:focus-visible {
|
|
37
|
+
outline: none !important;
|
|
38
|
+
}.SyntaxHighlighter {
|
|
39
|
+
--syntax1: var(--codeblock-syntax-1);
|
|
40
|
+
--syntax2: var(--codeblock-syntax-2);
|
|
41
|
+
--syntax3: var(--codeblock-syntax-3);
|
|
42
|
+
--syntax4: var(--codeblock-syntax-4);
|
|
43
|
+
--syntax5: var(--codeblock-syntax-5);
|
|
44
|
+
|
|
45
|
+
overflow: auto;
|
|
46
|
+
display: block;
|
|
47
|
+
/* Padding inside the overflow: auto container */
|
|
48
|
+
padding: 12px 48px 12px 16px;
|
|
49
|
+
margin: 0;
|
|
50
|
+
background: transparent;
|
|
51
|
+
color: var(--color-text);
|
|
52
|
+
font-size: 0.875em;
|
|
53
|
+
/* 14px to a 16px baseline */
|
|
54
|
+
font-weight: var(--font-weight-normal);
|
|
55
|
+
line-height: 1.714em;
|
|
56
|
+
/* 24px at 14px */
|
|
57
|
+
|
|
58
|
+
/* stylelint-disable selector-class-pattern */
|
|
59
|
+
|
|
60
|
+
/* Order matters here, for nested tokens */
|
|
61
|
+
}
|
|
62
|
+
.SyntaxHighlighter :global(.token.property),
|
|
63
|
+
.SyntaxHighlighter :global(.token.variable),
|
|
64
|
+
.SyntaxHighlighter :global(.token.attr-name),
|
|
65
|
+
.SyntaxHighlighter :global(.token.unit),
|
|
66
|
+
.SyntaxHighlighter :global(.token.id),
|
|
67
|
+
.SyntaxHighlighter :global(.token.selector),
|
|
68
|
+
.SyntaxHighlighter :global(.token.entity),
|
|
69
|
+
.SyntaxHighlighter :global(.token.tag),
|
|
70
|
+
.SyntaxHighlighter :global(.token.type) {
|
|
71
|
+
color: var(--syntax4);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.SyntaxHighlighter :global(.token.url),
|
|
75
|
+
.SyntaxHighlighter :global(.token.boolean),
|
|
76
|
+
.SyntaxHighlighter :global(.token.number),
|
|
77
|
+
.SyntaxHighlighter :global(.token.important) {
|
|
78
|
+
color: var(--syntax5);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.SyntaxHighlighter :global(.token.builtin),
|
|
82
|
+
.SyntaxHighlighter :global(.token.function),
|
|
83
|
+
.SyntaxHighlighter :global(.token.class-name) {
|
|
84
|
+
color: var(--syntax1);
|
|
85
|
+
}
|
|
86
|
+
.SyntaxHighlighter :global(.token.keyword),
|
|
87
|
+
.SyntaxHighlighter :global(.token.constant),
|
|
88
|
+
.SyntaxHighlighter :global(.token.symbol),
|
|
89
|
+
.SyntaxHighlighter :global(.token.deleted) {
|
|
90
|
+
color: var(--syntax2);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.SyntaxHighlighter :global(.token.string),
|
|
94
|
+
.SyntaxHighlighter :global(.token.char),
|
|
95
|
+
.SyntaxHighlighter :global(.token.regex),
|
|
96
|
+
.SyntaxHighlighter :global(.token.attr-value),
|
|
97
|
+
.SyntaxHighlighter :global(.token.inserted) {
|
|
98
|
+
color: var(--syntax3);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.SyntaxHighlighter :global(.token.comment),
|
|
102
|
+
.SyntaxHighlighter :global(.token.prolog),
|
|
103
|
+
.SyntaxHighlighter :global(.token.doctype),
|
|
104
|
+
.SyntaxHighlighter :global(.token.cdata) {
|
|
105
|
+
color: color-mix(in srgb, var(--color-text), transparent 50%);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.SyntaxHighlighter :global(.token.punctuation),
|
|
109
|
+
.SyntaxHighlighter :global(.token.operator) {
|
|
110
|
+
color: color-mix(in srgb, var(--color-text), transparent 40%);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.SyntaxHighlighter :global(.token.console) {
|
|
114
|
+
color: var(--color-text);
|
|
115
|
+
}/* Collapsible Code Block */.CollapsibleCodeBlock {
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
transition: max-height 0.2s ease-out;
|
|
118
|
+
}/* Expanded under `maxExpandedHeight`, the code shrinks to fit and scrolls
|
|
119
|
+
(the <pre> is the scroll container), with the copy button kept in view */.CollapsibleCodeBlock:not([data-collapsed]) {
|
|
120
|
+
display: flex;
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
}/* The collapsed height (min and max) is set inline from `collapsedHeight` */.CollapsibleCodeBlock[data-collapsed] {
|
|
123
|
+
overflow: hidden;
|
|
124
|
+
}.GradientOverlay {
|
|
125
|
+
position: absolute;
|
|
126
|
+
inset: 0;
|
|
127
|
+
pointer-events: none;
|
|
128
|
+
background: linear-gradient(to bottom,
|
|
129
|
+
transparent 0%,
|
|
130
|
+
transparent 20%,
|
|
131
|
+
var(--codeblock-background-color) 100%);
|
|
132
|
+
}.ViewCodeButtonContainer {
|
|
133
|
+
position: absolute;
|
|
134
|
+
inset: 0;
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
}
|
|
139
|
+
}
|