@aortl/admin-css 0.16.1 → 0.16.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/CHANGELOG.md +54 -0
- package/dist/admin.css +0 -4
- package/dist/admin.min.css +1 -1
- package/dist/admin.scoped.css +0 -4
- package/dist/admin.scoped.min.css +0 -1
- package/package.json +3 -2
- package/src/components/accordion.css +4 -13
- package/src/components/alert.css +6 -21
- package/src/components/app-shell.css +2 -4
- package/src/components/badge.css +1 -5
- package/src/components/breadcrumbs.css +2 -11
- package/src/components/button-group.css +7 -19
- package/src/components/button.css +7 -23
- package/src/components/card.css +10 -26
- package/src/components/chart.css +26 -83
- package/src/components/checkbox.css +3 -9
- package/src/components/code-block.css +2 -4
- package/src/components/container.css +3 -7
- package/src/components/dialog.css +11 -18
- package/src/components/field.css +3 -7
- package/src/components/footer.css +2 -3
- package/src/components/indicator.css +9 -28
- package/src/components/input-group.css +3 -6
- package/src/components/input.css +2 -5
- package/src/components/kbd.css +7 -13
- package/src/components/link.css +2 -8
- package/src/components/menu.css +9 -24
- package/src/components/navbar.css +3 -7
- package/src/components/pagination.css +1 -4
- package/src/components/progress.css +3 -7
- package/src/components/property-list.css +5 -14
- package/src/components/prose.css +6 -24
- package/src/components/radio.css +3 -7
- package/src/components/select.css +4 -11
- package/src/components/sidebar.css +2 -7
- package/src/components/spinner.css +1 -4
- package/src/components/stat-card.css +5 -16
- package/src/components/switch.css +3 -5
- package/src/components/table.css +15 -34
- package/src/components/tabs.css +14 -32
- package/src/components/textarea.css +3 -7
- package/src/components/tooltip.css +6 -16
- package/src/fonts.css +8 -28
- package/src/theme.css +32 -100
- package/src/utilities.css +11 -37
|
@@ -768,5 +768,4 @@
|
|
|
768
768
|
:scope._ao-text-right, :scope ._ao-text-right{text-align:right}
|
|
769
769
|
:scope._ao-tabular-nums, :scope ._ao-tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}
|
|
770
770
|
:scope._ao-ring, :scope ._ao-ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}
|
|
771
|
-
:scope._ao-select-all, :scope ._ao-select-all{-webkit-user-select:all;user-select:all}
|
|
772
771
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aortl/admin-css",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.2",
|
|
4
4
|
"description": "Pre-built CSS design system. Drop in via <link> and use semantic class names.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"components",
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
21
|
"src",
|
|
22
|
-
"README.md"
|
|
22
|
+
"README.md",
|
|
23
|
+
"CHANGELOG.md"
|
|
23
24
|
],
|
|
24
25
|
"type": "module",
|
|
25
26
|
"sideEffects": [
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
hover:bg-surface-muted
|
|
29
29
|
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus;
|
|
30
30
|
list-style: none;
|
|
31
|
-
/* Let a long label break and shrink
|
|
32
|
-
the item (the chevron sits at `margin-left: auto`). */
|
|
31
|
+
/* Let a long label break and shrink instead of widening the row. */
|
|
33
32
|
overflow-wrap: break-word;
|
|
34
33
|
min-width: 0;
|
|
35
34
|
}
|
|
@@ -38,14 +37,11 @@
|
|
|
38
37
|
display: none;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
/* Keep a leading icon at its intrinsic size; the chevron is the `::after`
|
|
42
|
-
below, which is already `flex-shrink: 0`. */
|
|
43
40
|
.accordion-summary > :is(i, svg) {
|
|
44
41
|
flex-shrink: 0;
|
|
45
42
|
}
|
|
46
43
|
|
|
47
|
-
/* Chevron
|
|
48
|
-
leading items (label, optional icon) sit together on the start side. */
|
|
44
|
+
/* Chevron */
|
|
49
45
|
.accordion-summary::after {
|
|
50
46
|
content: "";
|
|
51
47
|
width: 0.5rem;
|
|
@@ -64,16 +60,11 @@
|
|
|
64
60
|
|
|
65
61
|
.accordion-content {
|
|
66
62
|
@apply px-4 py-3 text-sm text-text border-t border-border;
|
|
67
|
-
/* Arbitrary body text — break long tokens instead of overflowing. */
|
|
68
63
|
overflow-wrap: break-word;
|
|
69
64
|
}
|
|
70
65
|
|
|
71
|
-
/*
|
|
72
|
-
|
|
73
|
-
snapping. content-visibility is pinned to visible so the closed content
|
|
74
|
-
still contributes to intrinsic width — without this, a shrink-to-fit
|
|
75
|
-
parent reflows narrower on close. Browsers without ::details-content
|
|
76
|
-
degrade to the native instant toggle. */
|
|
66
|
+
/* content-visibility stays visible so the closed content still contributes
|
|
67
|
+
intrinsic width — without it a shrink-to-fit parent reflows narrower on close. */
|
|
77
68
|
.accordion-item::details-content {
|
|
78
69
|
opacity: 0;
|
|
79
70
|
height: 0;
|
package/src/components/alert.css
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
.alert {
|
|
3
3
|
@apply flex flex-col gap-1 w-full px-3 py-2 rounded-md border text-sm text-text;
|
|
4
|
-
/* Inherited by the title, description, and any bare-text body so long
|
|
5
|
-
words/URLs break instead of overflowing the (often grid-tracked) body. */
|
|
6
4
|
overflow-wrap: break-word;
|
|
7
5
|
}
|
|
8
6
|
|
|
9
|
-
/*
|
|
10
|
-
icon spans all rows on the left, title/description stack on the right.
|
|
11
|
-
No wrapper needed — works with `<i class="ti …">`, `@tabler/icons-react`,
|
|
12
|
-
or any other inline SVG. */
|
|
7
|
+
/* A leading icon switches the layout to a two-column grid: icon left, text right. */
|
|
13
8
|
.alert:has(> :is(i, svg):first-child) {
|
|
14
9
|
display: grid;
|
|
15
|
-
/* `minmax(0, 1fr)`
|
|
16
|
-
column shrink below its longest word so the body wraps. */
|
|
10
|
+
/* `minmax(0, 1fr)` lets the text column shrink below its longest word. */
|
|
17
11
|
grid-template-columns: auto minmax(0, 1fr);
|
|
18
12
|
column-gap: 0.5rem;
|
|
19
13
|
row-gap: 0.25rem;
|
|
@@ -25,10 +19,7 @@
|
|
|
25
19
|
line-height: 1.25;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
/*
|
|
29
|
-
them (`grid-row: 1 / -1` only resolves correctly against an explicit grid)
|
|
30
|
-
and force the text parts into column 2 so the description doesn't wrap
|
|
31
|
-
under the icon. */
|
|
22
|
+
/* Explicit rows — the icon's `grid-row: 1 / -1` only resolves against an explicit grid. */
|
|
32
23
|
.alert:has(> :is(i, svg):first-child):has(> .alert-title) {
|
|
33
24
|
grid-template-rows: auto auto;
|
|
34
25
|
align-items: start;
|
|
@@ -38,20 +29,14 @@
|
|
|
38
29
|
grid-row: 1 / -1;
|
|
39
30
|
}
|
|
40
31
|
|
|
41
|
-
/* Grid items default to `min-width: auto` and won't shrink below their
|
|
42
|
-
longest word; `min-width: 0` lets the title/description wrap inside the
|
|
43
|
-
text column. */
|
|
32
|
+
/* Grid items default to `min-width: auto` and won't shrink below their longest word. */
|
|
44
33
|
.alert > :is(.alert-title, .alert-description) {
|
|
45
34
|
grid-column: 2;
|
|
46
35
|
min-width: 0;
|
|
47
36
|
}
|
|
48
37
|
|
|
49
|
-
/* Solid status
|
|
50
|
-
|
|
51
|
-
(white on the colored accents, black on bright yellow). Title/icon inherit
|
|
52
|
-
that content color from the root, so no per-variant text rule is needed.
|
|
53
|
-
The description drops to 85% opacity to read as secondary text without
|
|
54
|
-
introducing a second hue. */
|
|
38
|
+
/* Solid status fills. Title and icon inherit the `-content` color from the
|
|
39
|
+
root, so no per-variant text rule is needed. */
|
|
55
40
|
.alert-info {
|
|
56
41
|
@apply bg-info border-info text-info-content;
|
|
57
42
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
@layer components {
|
|
2
|
-
/*
|
|
3
|
-
|
|
4
|
-
`auto` so the .sidebar's own width drives it — collapse/peek modes change
|
|
5
|
-
the sidebar's intrinsic width instead of recomputing the grid here. */
|
|
2
|
+
/* The sidebar column is `auto` so the .sidebar's own width drives it —
|
|
3
|
+
collapse/peek modes change the sidebar's intrinsic width, not this grid. */
|
|
6
4
|
.app-shell {
|
|
7
5
|
--app-shell-sidebar-w: 240px;
|
|
8
6
|
--app-shell-sidebar-w-collapsed: 56px;
|
package/src/components/badge.css
CHANGED
|
@@ -12,11 +12,7 @@
|
|
|
12
12
|
flex-shrink: 0;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
/* Variants — solid status fills
|
|
16
|
-
success/etc. stay coherent across status indicators and chips in tables.
|
|
17
|
-
Each sits on the full-strength status color with the matching `-content`
|
|
18
|
-
text (white on the colored accents, black on bright yellow). The bare
|
|
19
|
-
`.badge` (no modifier) renders the neutral look, folded into the base. */
|
|
15
|
+
/* Variants — solid status fills matching the alert palette; bare `.badge` is the neutral look. */
|
|
20
16
|
.badge-info {
|
|
21
17
|
@apply bg-info text-info-content border-info;
|
|
22
18
|
}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
.breadcrumbs {
|
|
3
3
|
@apply text-sm text-text-muted;
|
|
4
|
-
/* Crumb labels are often free-form entity names/slugs — let a long one
|
|
5
|
-
break rather than overflow the (flex-wrap) row. Inherited by every item;
|
|
6
|
-
crumb/separator icons stay `flex-shrink: 0` below. */
|
|
7
4
|
overflow-wrap: break-word;
|
|
8
5
|
}
|
|
9
6
|
|
|
@@ -18,15 +15,11 @@
|
|
|
18
15
|
focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
/* `aria-current` on the last item promotes it to body text weight. Non-links
|
|
22
|
-
stay non-interactive — same selector matches both <a aria-current> and
|
|
23
|
-
<span aria-current>. */
|
|
24
18
|
.breadcrumb-item[aria-current="page"] {
|
|
25
19
|
@apply text-text font-medium pointer-events-none;
|
|
26
20
|
}
|
|
27
21
|
|
|
28
|
-
/*
|
|
29
|
-
swap content via a child icon when you want a chevron instead. */
|
|
22
|
+
/* An empty separator renders a slash; a child icon replaces it. */
|
|
30
23
|
.breadcrumb-separator {
|
|
31
24
|
@apply inline-flex items-center text-text-muted/60 select-none;
|
|
32
25
|
}
|
|
@@ -40,9 +33,7 @@
|
|
|
40
33
|
height: 0.875rem;
|
|
41
34
|
}
|
|
42
35
|
|
|
43
|
-
/*
|
|
44
|
-
shrink factor too — keeps crumb and separator icons from squishing when a
|
|
45
|
-
long label tightens the row. */
|
|
36
|
+
/* A width alone doesn't stop a flex item from shrinking. */
|
|
46
37
|
.breadcrumb-item > :is(i, svg),
|
|
47
38
|
.breadcrumb-separator > :is(i, svg) {
|
|
48
39
|
flex-shrink: 0;
|
|
@@ -7,11 +7,8 @@
|
|
|
7
7
|
@apply rounded-none relative focus-visible:z-10;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
/* Split
|
|
11
|
-
|
|
12
|
-
treatment as the buttons around it. inline-flex on the details makes
|
|
13
|
-
the <summary> stretch vertically to match sibling .btn heights, so an
|
|
14
|
-
icon-only trigger doesn't end up shorter than its neighbours. */
|
|
10
|
+
/* Split buttons: a <details class="menu"> sits in the strip; inline-flex
|
|
11
|
+
stretches its <summary> to match sibling .btn heights. */
|
|
15
12
|
.btn-group > .menu {
|
|
16
13
|
@apply relative focus-visible:z-10;
|
|
17
14
|
display: inline-flex;
|
|
@@ -21,10 +18,7 @@
|
|
|
21
18
|
@apply rounded-none;
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
/* Horizontal-only
|
|
25
|
-
and paint the seam between adjacent items as a left-side divider.
|
|
26
|
-
Scoped with :not(.btn-group-vertical) so vertical groups (which share
|
|
27
|
-
the .btn-group class) don't inherit horizontal edge treatment. */
|
|
21
|
+
/* Horizontal-only — vertical groups also carry .btn-group, hence the :not() scope. */
|
|
28
22
|
.btn-group:not(.btn-group-vertical) > .btn:not(:first-child),
|
|
29
23
|
.btn-group:not(.btn-group-vertical) > .menu:not(:first-child) {
|
|
30
24
|
@apply -ml-px;
|
|
@@ -40,11 +34,8 @@
|
|
|
40
34
|
@apply rounded-r-lg;
|
|
41
35
|
}
|
|
42
36
|
|
|
43
|
-
/*
|
|
44
|
-
|
|
45
|
-
means the divider works across every .btn variant — light on
|
|
46
|
-
coloured buttons, dark on ghost/secondary — without per-variant
|
|
47
|
-
rules. */
|
|
37
|
+
/* Seam divider — color-mix on currentColor adapts to every .btn variant
|
|
38
|
+
without per-variant rules. */
|
|
48
39
|
.btn-group:not(.btn-group-vertical) > .btn:not(:first-child),
|
|
49
40
|
.btn-group:not(.btn-group-vertical) > .menu:not(:first-child) > .menu-trigger {
|
|
50
41
|
border-left-color: color-mix(in oklab, currentColor 25%, transparent);
|
|
@@ -78,11 +69,8 @@
|
|
|
78
69
|
border-top-color: color-mix(in oklab, currentColor 25%, transparent);
|
|
79
70
|
}
|
|
80
71
|
|
|
81
|
-
/* Full width —
|
|
82
|
-
|
|
83
|
-
every item is the same width regardless of label length; vertical
|
|
84
|
-
groups already stretch their items to the group's width, so widening
|
|
85
|
-
the group is enough. Mirrors the `fullWidth` treatment on tabs. */
|
|
72
|
+
/* Full width — horizontal items split the row evenly; vertical items
|
|
73
|
+
already stretch, so widening the group is enough. */
|
|
86
74
|
.btn-group-full-width:not(.btn-group-vertical) {
|
|
87
75
|
@apply flex w-full;
|
|
88
76
|
}
|
|
@@ -10,16 +10,12 @@
|
|
|
10
10
|
disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/*
|
|
14
|
-
to `flex-shrink: 1`, so a narrow flex container would otherwise squish the
|
|
15
|
-
glyph horizontally before wrapping or truncating the label. */
|
|
13
|
+
/* Don't let a narrow container squish the glyph before the label wraps. */
|
|
16
14
|
.btn > :is(i, svg) {
|
|
17
15
|
flex-shrink: 0;
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
/* Variants —
|
|
21
|
-
most admin buttons need no variant class. The colored variants reset the
|
|
22
|
-
border to transparent since the base now carries a visible one. */
|
|
18
|
+
/* Variants — bare `.btn` is the low-emphasis default; most buttons need no variant class. */
|
|
23
19
|
.btn-primary {
|
|
24
20
|
@apply bg-primary text-primary-content border-transparent hover:bg-primary-hover;
|
|
25
21
|
}
|
|
@@ -28,11 +24,7 @@
|
|
|
28
24
|
@apply bg-transparent text-text border-transparent hover:bg-surface-muted;
|
|
29
25
|
}
|
|
30
26
|
|
|
31
|
-
/*
|
|
32
|
-
instead of reading as a raised control, mirroring `card-muted`. The
|
|
33
|
-
default `.btn` is one step up (`surface-muted`); hover lifts the muted
|
|
34
|
-
button to that resting fill. For de-emphasised actions that should
|
|
35
|
-
recede into the page. */
|
|
27
|
+
/* Fills with the page background so it sits flush instead of raised — mirrors `card-muted`. */
|
|
36
28
|
.btn-muted {
|
|
37
29
|
@apply bg-surface hover:bg-surface-muted;
|
|
38
30
|
}
|
|
@@ -50,14 +42,11 @@
|
|
|
50
42
|
@apply text-base px-5 py-2.5 gap-2.5;
|
|
51
43
|
}
|
|
52
44
|
|
|
53
|
-
/* Modifiers */
|
|
54
45
|
.btn-full-width {
|
|
55
46
|
@apply w-full;
|
|
56
47
|
}
|
|
57
48
|
|
|
58
|
-
/* Icon-only — equalises padding so the button reads as a square.
|
|
59
|
-
wrapper adds this automatically when `.btn` has an icon but no text
|
|
60
|
-
children; vanilla callers add it themselves. Pair with `aria-label`. */
|
|
49
|
+
/* Icon-only — equalises padding so the button reads as a square. Pair with `aria-label`. */
|
|
61
50
|
.btn-square {
|
|
62
51
|
@apply px-2;
|
|
63
52
|
}
|
|
@@ -70,11 +59,8 @@
|
|
|
70
59
|
@apply px-2.5;
|
|
71
60
|
}
|
|
72
61
|
|
|
73
|
-
/*
|
|
74
|
-
|
|
75
|
-
`disabled` attribute (or the React wrapper, which sets it for you) for
|
|
76
|
-
keyboard a11y; the visual disable lives here so vanilla still feels right
|
|
77
|
-
without it. */
|
|
62
|
+
/* Spinner via ::before, `em`-sized so it tracks btn-sm / btn-lg. Pair with
|
|
63
|
+
the `disabled` attribute for keyboard a11y. */
|
|
78
64
|
.btn-loading {
|
|
79
65
|
@apply opacity-50 cursor-not-allowed pointer-events-none;
|
|
80
66
|
}
|
|
@@ -91,9 +77,7 @@
|
|
|
91
77
|
animation: spinner-spin 0.6s linear infinite;
|
|
92
78
|
}
|
|
93
79
|
|
|
94
|
-
/*
|
|
95
|
-
Trailing icons stay visible — they may convey structural meaning
|
|
96
|
-
(e.g. a dropdown chevron on a split-button trigger). */
|
|
80
|
+
/* Hide the leading icon while loading; trailing icons (e.g. a dropdown chevron) stay. */
|
|
97
81
|
.btn-loading > :is(i, svg):first-child {
|
|
98
82
|
display: none;
|
|
99
83
|
}
|
package/src/components/card.css
CHANGED
|
@@ -5,10 +5,7 @@
|
|
|
5
5
|
border border-border
|
|
6
6
|
rounded-xl
|
|
7
7
|
shadow-xs;
|
|
8
|
-
/*
|
|
9
|
-
overflowing the body, and let the card shrink inside a flex/grid track
|
|
10
|
-
rather than forcing it wide. Inherited by title/description/body.
|
|
11
|
-
Mirrors `.alert`. */
|
|
8
|
+
/* min-width: 0 lets the card shrink inside a flex/grid track instead of forcing it wide. */
|
|
12
9
|
overflow-wrap: break-word;
|
|
13
10
|
min-width: 0;
|
|
14
11
|
}
|
|
@@ -19,28 +16,22 @@
|
|
|
19
16
|
|
|
20
17
|
.card-title {
|
|
21
18
|
@apply flex items-center gap-2 text-lg font-semibold leading-tight;
|
|
22
|
-
/*
|
|
23
|
-
card. `overflow-wrap` is inherited from `.card`. */
|
|
19
|
+
/* Let a long title wrap instead of widening the card. */
|
|
24
20
|
min-width: 0;
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
/* Header row: title on the left, toolbar pushed to the trailing edge. */
|
|
28
23
|
.card-header {
|
|
29
24
|
@apply flex items-center gap-2;
|
|
30
25
|
}
|
|
31
26
|
|
|
32
|
-
/*
|
|
33
|
-
|
|
34
|
-
centering reads slightly low — nudge the controls up to the optical centre.
|
|
35
|
-
`card-title` is always `text-lg`, so this offset is constant. */
|
|
27
|
+
/* -mt-0.5 nudges the controls up to the optical centre — the bold title type
|
|
28
|
+
sits high in its line box. */
|
|
36
29
|
.card-toolbar {
|
|
37
30
|
@apply flex items-center gap-1 ml-auto -mt-0.5;
|
|
38
31
|
}
|
|
39
32
|
|
|
40
|
-
/*
|
|
41
|
-
|
|
42
|
-
bundles size icons off `font-size` — the Tabler webfont (`<i>`) and React's
|
|
43
|
-
`size="1em"` SVG — so this single rule enlarges both identically. */
|
|
33
|
+
/* font-size enlarges both icon flavours identically — the Tabler webfont and
|
|
34
|
+
React's `size="1em"` SVG. */
|
|
44
35
|
.card-toolbar :is(i, svg) {
|
|
45
36
|
font-size: 1.25rem;
|
|
46
37
|
}
|
|
@@ -53,7 +44,6 @@
|
|
|
53
44
|
@apply flex flex-wrap items-center gap-2 mt-auto pt-2;
|
|
54
45
|
}
|
|
55
46
|
|
|
56
|
-
/* Modifiers */
|
|
57
47
|
.card-compact .card-body {
|
|
58
48
|
@apply p-3 gap-2;
|
|
59
49
|
}
|
|
@@ -62,17 +52,12 @@
|
|
|
62
52
|
@apply shadow-none border-border-strong;
|
|
63
53
|
}
|
|
64
54
|
|
|
65
|
-
/*
|
|
66
|
-
fill as `html`/`.app-shell`) instead of the raised `surface-muted` of a
|
|
67
|
-
default card. For de-emphasised or grouped panels that shouldn't pop off
|
|
68
|
-
the background. No accent, no status meaning. */
|
|
55
|
+
/* Fills with the page background so the panel sits flush instead of raised. */
|
|
69
56
|
.card-muted {
|
|
70
57
|
@apply bg-surface;
|
|
71
58
|
}
|
|
72
59
|
|
|
73
|
-
/* Color variants — tinted surface +
|
|
74
|
-
title (and any leading icon, via `currentColor`) picks up the accent for
|
|
75
|
-
fast scanning. */
|
|
60
|
+
/* Color variants — tinted surface + accent title, mirroring Alert. */
|
|
76
61
|
.card-primary {
|
|
77
62
|
@apply bg-primary-muted border-primary-muted;
|
|
78
63
|
}
|
|
@@ -109,7 +94,6 @@
|
|
|
109
94
|
@apply text-danger;
|
|
110
95
|
}
|
|
111
96
|
|
|
112
|
-
/*
|
|
113
|
-
|
|
114
|
-
surface. The tinted bg still carries the warning signal. */
|
|
97
|
+
/* No `.card-warning .card-title` rule — the yellow-400 accent fails AA on
|
|
98
|
+
the muted yellow surface. */
|
|
115
99
|
}
|
package/src/components/chart.css
CHANGED
|
@@ -1,30 +1,14 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
/*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* the fill sizes to `var(--value) / var(--chart-max) * 100%`.
|
|
12
|
-
* - stack: each segment `--value`, sized by `flex` (no max — the ratios
|
|
13
|
-
* are intrinsic to the flex grow factors).
|
|
14
|
-
* - donut: one pre-built cumulative conic-gradient stop string in
|
|
15
|
-
* `--donut-segments` (CSS can't sum a variable-length sibling
|
|
16
|
-
* list, so the string arrives whole).
|
|
17
|
-
*
|
|
18
|
-
* Colour: single-series follows `currentColor` (default `--color-info`,
|
|
19
|
-
* recoloured by the `.chart-success`/etc. variants like `.progress`).
|
|
20
|
-
* Multi-series colours are set inline per bar/segment (`--bar-color` /
|
|
21
|
-
* `--segment-color` / legend `--legend-color`); there is no chart token
|
|
22
|
-
* layer. role="img" + aria-label carries the semantics; a native `title`
|
|
23
|
-
* on each bar/segment gives a hover read-out.
|
|
3
|
+
* Pure-CSS charts driven by inline custom properties — not data-*
|
|
4
|
+
* attributes (CSS can't read an attribute as a number for calc()).
|
|
5
|
+
* Contract: bars — container `--chart-max` (default 100), each bar
|
|
6
|
+
* `--value`; stack — each segment `--value` (flex-grow ratios, no max);
|
|
7
|
+
* donut — `--donut-segments` holds a pre-built cumulative conic-gradient
|
|
8
|
+
* stop string (CSS can't sum a variable-length sibling list).
|
|
9
|
+
* Single-series colour rides currentColor; multi-series is set inline via
|
|
10
|
+
* `--bar-color` / `--segment-color` / `--legend-color`.
|
|
24
11
|
*/
|
|
25
|
-
|
|
26
|
-
/* Shared base — sizing knobs + the single-series fill colour. Any chart
|
|
27
|
-
type reads these; size modifiers below just remap them. */
|
|
28
12
|
.chart {
|
|
29
13
|
--chart-max: 100;
|
|
30
14
|
--chart-height: 8rem; /* bar track cross-axis size (md) */
|
|
@@ -33,9 +17,7 @@
|
|
|
33
17
|
color: var(--color-info);
|
|
34
18
|
}
|
|
35
19
|
|
|
36
|
-
/*
|
|
37
|
-
`info` is the base colour (`.chart` above), so it needs no class — the
|
|
38
|
-
default `variant="info"` simply emits no modifier. */
|
|
20
|
+
/* `info` is the base colour (`.chart`), so the default variant emits no class. */
|
|
39
21
|
.chart-success {
|
|
40
22
|
color: var(--color-success);
|
|
41
23
|
}
|
|
@@ -46,16 +28,9 @@
|
|
|
46
28
|
color: var(--color-danger);
|
|
47
29
|
}
|
|
48
30
|
|
|
49
|
-
/*
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
* Three-column grid: [label | track (1fr) | value]. Each `.chart-bar` is
|
|
53
|
-
* a `subgrid` spanning all three, so the label gutter and the value column
|
|
54
|
-
* stay aligned across every row. The fill lives in the `1fr` track — a
|
|
55
|
-
* definite width once the grid resolves, which is exactly what lets its
|
|
56
|
-
* `inline-size: %` transition (see the transition note). Values sit in the
|
|
57
|
-
* trailing column, so a short bar never clips its number and a full bar
|
|
58
|
-
* never overflows. */
|
|
31
|
+
/* Bar chart (horizontal) — grid [label | track (1fr) | value]; each bar is
|
|
32
|
+
a subgrid row so columns align across rows. The 1fr track gives the fill
|
|
33
|
+
a definite width, which is what lets its % inline-size transition. */
|
|
59
34
|
.chart-bars {
|
|
60
35
|
display: grid;
|
|
61
36
|
grid-template-columns: auto 1fr auto;
|
|
@@ -71,8 +46,7 @@
|
|
|
71
46
|
align-items: center;
|
|
72
47
|
}
|
|
73
48
|
|
|
74
|
-
/*
|
|
75
|
-
`auto` column collapses to 0 when no bar has a label. */
|
|
49
|
+
/* The auto column collapses to 0 when no bar has a label. */
|
|
76
50
|
.chart-bar-label {
|
|
77
51
|
@apply text-xs text-text-muted;
|
|
78
52
|
grid-column: 1;
|
|
@@ -91,15 +65,13 @@
|
|
|
91
65
|
inline-size: calc(var(--value) / var(--chart-max) * 100%);
|
|
92
66
|
background: var(--bar-color, currentColor);
|
|
93
67
|
border-radius: 2px;
|
|
94
|
-
/* Transition the resolved length
|
|
95
|
-
|
|
96
|
-
Both axes are listed so the vertical fill animates too. */
|
|
68
|
+
/* Transition the resolved length, not --value (unregistered — won't
|
|
69
|
+
animate); both axes so the vertical fill animates too. */
|
|
97
70
|
transition:
|
|
98
71
|
inline-size 200ms ease,
|
|
99
72
|
block-size 200ms ease;
|
|
100
73
|
}
|
|
101
74
|
|
|
102
|
-
/* Value label — trailing aligned column. Opt-in via `.chart-values`. */
|
|
103
75
|
.chart-bar-value {
|
|
104
76
|
@apply text-xs text-text-muted tabular-nums;
|
|
105
77
|
grid-column: 3;
|
|
@@ -111,13 +83,9 @@
|
|
|
111
83
|
display: none;
|
|
112
84
|
}
|
|
113
85
|
|
|
114
|
-
/*
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
* Flex row of equal columns inside a fixed-height box. Each column is a
|
|
118
|
-
* flex column [value | track | label]; the track (`flex: 1`) gets a
|
|
119
|
-
* definite block-size so the fill's `block-size: %` resolves and animates.
|
|
120
|
-
* Bars grow up from the floor (`justify-content: end`). */
|
|
86
|
+
/* Bar chart (vertical) — flex row of columns in a fixed-height box; the
|
|
87
|
+
flex:1 track gets a definite block-size so the fill's % block-size
|
|
88
|
+
resolves and animates. */
|
|
121
89
|
.chart-bars-vertical {
|
|
122
90
|
display: flex;
|
|
123
91
|
flex-direction: row;
|
|
@@ -163,12 +131,7 @@
|
|
|
163
131
|
padding: 0;
|
|
164
132
|
}
|
|
165
133
|
|
|
166
|
-
/*
|
|
167
|
-
* STACKED / PROPORTION BAR *
|
|
168
|
-
* --------------------------------------------------------------------- *
|
|
169
|
-
* A single rounded track partitioned by `flex: var(--value)`. No max
|
|
170
|
-
* needed — proportions are the flex-grow ratios. A hairline in the
|
|
171
|
-
* surface colour separates adjacent segments. */
|
|
134
|
+
/* Stacked / proportion bar */
|
|
172
135
|
.chart-stack {
|
|
173
136
|
display: flex;
|
|
174
137
|
flex-direction: row;
|
|
@@ -189,18 +152,10 @@
|
|
|
189
152
|
box-shadow: -1px 0 0 0 var(--color-surface);
|
|
190
153
|
}
|
|
191
154
|
|
|
192
|
-
/*
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
* mask. `--donut-thickness` is the ring width as a % of the diameter; the
|
|
197
|
-
* hole's inner radius is `50% - thickness`, so thickness=50% leaves no hole
|
|
198
|
-
* (a solid pie). The same stop position twice gives a crisp ring edge.
|
|
199
|
-
*
|
|
200
|
-
* The centre label must NOT be a child of the ring — `mask` clips the whole
|
|
201
|
-
* subtree, so a child sitting in the hole would be invisible. It's a sibling
|
|
202
|
-
* overlay: the figure is an inline-grid and both the ring and the label
|
|
203
|
-
* occupy the same cell. */
|
|
155
|
+
/* Donut / pie — conic-gradient ring, centre punched out by a radial-gradient
|
|
156
|
+
mask. `--donut-thickness` is the ring width as a % of the diameter (50% =
|
|
157
|
+
solid pie). The centre label must be a sibling overlay, never a child —
|
|
158
|
+
`mask` clips the whole subtree. */
|
|
204
159
|
.chart-donut-figure {
|
|
205
160
|
position: relative;
|
|
206
161
|
inline-size: var(--chart-size);
|
|
@@ -232,7 +187,6 @@
|
|
|
232
187
|
inline-size: 100%;
|
|
233
188
|
}
|
|
234
189
|
|
|
235
|
-
/* Solid pie — no hole. */
|
|
236
190
|
.chart-donut-pie {
|
|
237
191
|
--donut-thickness: 50%;
|
|
238
192
|
}
|
|
@@ -244,9 +198,7 @@
|
|
|
244
198
|
pointer-events: none;
|
|
245
199
|
}
|
|
246
200
|
|
|
247
|
-
/*
|
|
248
|
-
* LEGEND (donut + stack) *
|
|
249
|
-
* --------------------------------------------------------------------- */
|
|
201
|
+
/* Legend (donut + stack) */
|
|
250
202
|
.chart-legend {
|
|
251
203
|
@apply flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-text-muted;
|
|
252
204
|
list-style: none;
|
|
@@ -266,9 +218,7 @@
|
|
|
266
218
|
flex-shrink: 0;
|
|
267
219
|
}
|
|
268
220
|
|
|
269
|
-
/*
|
|
270
|
-
* SIZES — remap the cross-axis / diameter knobs *
|
|
271
|
-
* --------------------------------------------------------------------- */
|
|
221
|
+
/* Sizes */
|
|
272
222
|
.chart-sm {
|
|
273
223
|
--chart-height: 4rem;
|
|
274
224
|
--chart-size: 4rem;
|
|
@@ -278,11 +228,7 @@
|
|
|
278
228
|
--chart-size: 12rem;
|
|
279
229
|
}
|
|
280
230
|
|
|
281
|
-
/*
|
|
282
|
-
* INLINE — micro-viz that sits in running text / a table cell *
|
|
283
|
-
* --------------------------------------------------------------------- *
|
|
284
|
-
* Inline-flex, baseline-nudged, and em-relative so the swatch tracks the
|
|
285
|
-
* surrounding font size. */
|
|
231
|
+
/* Inline micro-viz — em-relative so it tracks the surrounding font size. */
|
|
286
232
|
.chart-inline {
|
|
287
233
|
display: inline-flex;
|
|
288
234
|
vertical-align: middle;
|
|
@@ -298,9 +244,6 @@
|
|
|
298
244
|
inline-size: 6em;
|
|
299
245
|
}
|
|
300
246
|
|
|
301
|
-
/* --------------------------------------------------------------------- *
|
|
302
|
-
* REDUCED MOTION *
|
|
303
|
-
* --------------------------------------------------------------------- */
|
|
304
247
|
@media (prefers-reduced-motion: reduce) {
|
|
305
248
|
.chart-bar-fill,
|
|
306
249
|
.chart-segment {
|
|
@@ -25,11 +25,8 @@
|
|
|
25
25
|
@apply inline-flex items-center justify-center size-3 text-primary-content;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
/* Native input variant
|
|
29
|
-
|
|
30
|
-
vanilla <input class="checkbox"> renders identically (indeterminate reads
|
|
31
|
-
the same as checked, matching the data-* rule). The mask is the same
|
|
32
|
-
checkmark polyline the React indicator draws. */
|
|
28
|
+
/* Native input variant — must render identically to the Base UI button rules
|
|
29
|
+
above (same checkmark polyline; indeterminate reads as checked). */
|
|
33
30
|
input.checkbox {
|
|
34
31
|
@apply appearance-none border-border-strong hover:border-text-muted;
|
|
35
32
|
--checkbox-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E");
|
|
@@ -49,12 +46,9 @@
|
|
|
49
46
|
mask: var(--checkbox-check) center / contain no-repeat;
|
|
50
47
|
}
|
|
51
48
|
|
|
52
|
-
/* A <label> wrapping a checkbox + text lays out inline with a small gap.
|
|
53
|
-
Covers both the vanilla input.checkbox and Base UI's button.checkbox. */
|
|
54
49
|
label:has(> .checkbox) {
|
|
55
50
|
@apply inline-flex items-center gap-2 cursor-pointer;
|
|
56
|
-
/*
|
|
57
|
-
overflowing a narrow form column. The box stays put; the text wraps. */
|
|
51
|
+
/* Long labels wrap beside the shrink-0 box instead of overflowing. */
|
|
58
52
|
overflow-wrap: break-word;
|
|
59
53
|
min-width: 0;
|
|
60
54
|
}
|
|
@@ -9,10 +9,8 @@
|
|
|
9
9
|
overflow: auto;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
/*
|
|
13
|
-
|
|
14
|
-
`max-height` to clamp vertical growth — `overflow: auto` above
|
|
15
|
-
turns into a scrollbar automatically. */
|
|
12
|
+
/* Long lines scroll horizontally instead of breaking; pair with an inline
|
|
13
|
+
`max-height` to clamp vertical growth. */
|
|
16
14
|
.code-block-nowrap {
|
|
17
15
|
white-space: pre;
|
|
18
16
|
word-wrap: normal;
|