actual-css 0.2.0 → 0.3.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/CHANGELOG.md +38 -1
- package/README.md +24 -9
- package/dist/actual-themes.min.css +1 -0
- package/dist/actual.css +1244 -915
- package/dist/actual.js +1 -3
- package/dist/actual.min.css +1 -1
- package/dist/optional.css +1048 -0
- package/dist/optional.min.css +1 -0
- package/docs/design-notes/browser-support.md +94 -14
- package/docs/design-notes/cascade-layer.md +1 -1
- package/docs/design-notes/enhancement-contract.md +11 -14
- package/docs/design-notes/forced-colors.md +105 -0
- package/docs/design-notes/naming.md +2 -1
- package/docs/design-notes/platform-alignment.md +492 -0
- package/docs/design-notes/references.md +8 -0
- package/docs/design-notes/widget-primitives.md +37 -1
- package/docs/navigation.json +135 -0
- package/docs/pages/components/accordion.md +80 -0
- package/docs/pages/components/alert.md +203 -0
- package/docs/pages/components/aura.md +35 -0
- package/docs/pages/components/avatar.md +95 -0
- package/docs/pages/components/badge.md +102 -0
- package/docs/pages/components/breadcrumb.md +19 -0
- package/docs/pages/components/button.md +205 -0
- package/docs/pages/components/card.md +183 -0
- package/docs/pages/components/chat.md +50 -0
- package/docs/pages/components/dialog.md +367 -0
- package/docs/pages/components/drawer.md +113 -0
- package/docs/pages/components/fab.md +118 -0
- package/docs/pages/components/key.md +33 -0
- package/docs/pages/components/meter.md +23 -0
- package/docs/pages/components/navbar.md +92 -0
- package/docs/pages/components/pagination.md +55 -0
- package/docs/pages/components/progress.md +29 -0
- package/docs/pages/components/skeleton.md +38 -0
- package/docs/pages/components/spinner.md +93 -0
- package/docs/pages/components/table.md +102 -0
- package/docs/pages/enhancements/flyout.md +391 -0
- package/docs/pages/enhancements/overview.md +36 -0
- package/docs/pages/enhancements/scrollspy.md +71 -0
- package/docs/pages/enhancements/status-bar.md +72 -0
- package/docs/pages/enhancements/tabs.md +80 -0
- package/docs/pages/enhancements/tooltip.md +130 -0
- package/docs/pages/examples/overview.md +41 -0
- package/docs/pages/forms/choice-cards.md +102 -0
- package/docs/pages/forms/controls.md +32 -0
- package/docs/pages/forms/detached-actions.md +59 -0
- package/docs/pages/forms/floating-field.md +88 -0
- package/docs/pages/forms/form-actions.md +56 -0
- package/docs/pages/forms/input-policy.md +91 -0
- package/docs/pages/forms/joined-controls.md +37 -0
- package/docs/pages/forms/labels.md +42 -0
- package/docs/pages/forms/otp.md +50 -0
- package/docs/pages/forms/overview.md +188 -0
- package/docs/pages/forms/password.md +40 -0
- package/docs/pages/forms/range.md +17 -0
- package/docs/pages/forms/states-and-sizes.md +321 -0
- package/docs/pages/forms/sticky-actions.md +187 -0
- package/docs/pages/forms/switch.md +31 -0
- package/docs/pages/forms/validation.md +241 -0
- package/docs/{mental-model.md → pages/foundations/philosophy.md} +33 -18
- package/docs/pages/foundations/theming.md +92 -0
- package/docs/pages/foundations/tokens.md +421 -0
- package/docs/{typography.md → pages/foundations/typography.md} +27 -9
- package/docs/pages/guides/bootstrap.md +438 -0
- package/docs/pages/guides/introduction.md +157 -0
- package/docs/pages/guides/optional-components.md +33 -0
- package/docs/pages/guides/progressive-enhancement.md +686 -0
- package/docs/pages/guides/tailwind.md +455 -0
- package/docs/pages/layout/app-shell.md +25 -0
- package/docs/pages/layout/center.md +29 -0
- package/docs/pages/layout/cluster.md +57 -0
- package/docs/pages/layout/frame.md +30 -0
- package/docs/pages/layout/grid.md +142 -0
- package/docs/pages/layout/list.md +41 -0
- package/docs/pages/layout/media.md +21 -0
- package/docs/pages/layout/overview.md +37 -0
- package/docs/pages/layout/scroll-snap.md +54 -0
- package/docs/pages/layout/sidebar-layout.md +27 -0
- package/docs/pages/layout/stack.md +18 -0
- package/docs/pages/layout/switcher.md +36 -0
- package/docs/pages/layout/topbar.md +23 -0
- package/docs/pages/patterns/actions.md +52 -0
- package/docs/pages/patterns/code-block.md +36 -0
- package/docs/pages/patterns/exclusive-accordion.md +16 -0
- package/docs/pages/patterns/hierarchical-nav.md +26 -0
- package/docs/pages/patterns/icon-input.md +25 -0
- package/docs/pages/patterns/intent-nesting.md +3 -0
- package/docs/pages/patterns/navigation-list.md +235 -0
- package/docs/pages/patterns/overview.md +58 -0
- package/docs/pages/patterns/structured-lists.md +47 -0
- package/docs/pages/utilities/accessibility.md +34 -0
- package/docs/pages/utilities/flex.md +105 -0
- package/docs/pages/utilities/links.md +18 -0
- package/docs/pages/utilities/list.md +31 -0
- package/docs/pages/utilities/overflow.md +43 -0
- package/docs/pages/utilities/overview.md +18 -0
- package/docs/pages/utilities/shape.md +25 -0
- package/docs/pages/utilities/sizing-wrapping.md +115 -0
- package/docs/pages/utilities/spacing.md +79 -0
- package/docs/pages/utilities/text.md +43 -0
- package/llms.txt +4 -4
- package/package.json +20 -12
- package/src/css/actual.css +12 -1
- package/src/css/base.css +3 -5
- package/src/css/components/accordion.css +18 -30
- package/src/css/components/actions.css +4 -1
- package/src/css/components/alert.css +126 -99
- package/src/css/components/avatar.css +16 -10
- package/src/css/components/badge.css +55 -35
- package/src/css/components/breadcrumb.css +7 -15
- package/src/css/components/busy.css +6 -0
- package/src/css/components/button.css +78 -32
- package/src/css/components/card.css +17 -37
- package/src/css/components/drawer.css +30 -13
- package/src/css/components/flyout.css +39 -109
- package/src/css/components/index.css +1 -0
- package/src/css/components/join.css +14 -2
- package/src/css/components/key.css +2 -0
- package/src/css/components/menu.css +125 -0
- package/src/css/components/meter.css +0 -23
- package/src/css/components/modal.css +162 -7
- package/src/css/components/navbar.css +17 -18
- package/src/css/components/overline.css +0 -7
- package/src/css/components/pagination.css +1 -1
- package/src/css/components/progress.css +8 -26
- package/src/css/components/skeleton.css +7 -0
- package/src/css/components/spinner.css +6 -7
- package/src/css/components/status-bar.css +15 -24
- package/src/css/components/surface.css +2 -8
- package/src/css/components/tab.css +19 -48
- package/src/css/components/table.css +7 -5
- package/src/css/components/tooltip.css +14 -7
- package/src/css/focus.css +14 -38
- package/src/css/forms/choice-card.css +13 -14
- package/src/css/forms/choice.css +21 -27
- package/src/css/forms/control.css +16 -17
- package/src/css/forms/custom-select.css +9 -11
- package/src/css/forms/form-actions.css +14 -3
- package/src/css/forms/form.css +7 -4
- package/src/css/forms/index.css +4 -4
- package/src/css/forms/input-icon.css +30 -12
- package/src/css/forms/native.css +50 -11
- package/src/css/forms/range.css +17 -9
- package/src/css/forms/select.css +8 -8
- package/src/css/forms/switch.css +14 -12
- package/src/css/forms/validation.css +32 -5
- package/src/css/grid.css +19 -18
- package/src/css/intents.css +2 -2
- package/src/css/layout.css +29 -1
- package/src/css/optional/aura.css +93 -0
- package/src/css/optional/chat.css +105 -0
- package/src/css/optional/fab.css +104 -0
- package/src/css/optional/floating-field.css +87 -0
- package/src/css/optional/index.css +5 -0
- package/src/css/optional/layout-extra.css +7 -4
- package/src/css/optional/otp.css +115 -0
- package/src/css/optional/scroll-snap.css +6 -0
- package/src/css/optional/scroller.css +13 -7
- package/src/css/optional/typography-fluid.css +5 -0
- package/src/css/optional/utilities-extra.css +17 -2
- package/src/css/prose.css +18 -8
- package/src/css/reset.css +0 -10
- package/src/css/theme.css +21 -5
- package/src/css/themes/cyberpunk.css +1 -1
- package/src/css/themes/dim.css +3 -3
- package/src/css/themes/edge.css +8 -10
- package/src/css/themes/index.css +3 -3
- package/src/css/themes/{dark.css → indigo.css} +5 -4
- package/src/css/themes/neon.css +5 -5
- package/src/css/themes/square.css +0 -3
- package/src/css/tokens.css +74 -20
- package/src/css/utilities.css +8 -10
- package/src/css/variants.css +37 -65
- package/src/js/command.js +1 -3
- package/src/js/context-menu.js +67 -35
- package/src/js/dialog.js +68 -79
- package/src/js/dismiss.js +15 -0
- package/src/js/enhance.js +54 -23
- package/src/js/enhancement-loader.js +301 -0
- package/src/js/events.js +3 -0
- package/src/js/filter.js +3 -3
- package/src/js/floating.js +101 -131
- package/src/js/flyout.js +104 -87
- package/src/js/focus-group.js +116 -0
- package/src/js/focus.js +6 -1
- package/src/js/index.js +4 -2
- package/src/js/input.js +1 -1
- package/src/js/keys.js +27 -0
- package/src/js/mask.js +7 -6
- package/src/js/menu.js +87 -34
- package/src/js/parse-config.js +47 -0
- package/src/js/password.js +9 -1
- package/src/js/scrollspy.js +12 -4
- package/src/js/selectors.js +0 -7
- package/src/js/status.js +3 -1
- package/src/js/surface.js +185 -136
- package/src/js/tab.js +36 -53
- package/src/js/tooltip.js +53 -31
- package/src/js/validation.js +34 -8
- package/dist/actual.js.map +0 -31
- package/docs/README.md +0 -28
- package/docs/components.md +0 -860
- package/docs/design-notes/previous-work.md +0 -5
- package/docs/forms.md +0 -1265
- package/docs/javascript.md +0 -496
- package/docs/layout.md +0 -480
- package/docs/patterns.md +0 -504
- package/docs/reserved.md +0 -7
- package/docs/tokens.md +0 -455
- package/docs/ui.md +0 -929
- package/docs/utilities.md +0 -384
- package/src/css/dialog-fallback.css +0 -56
- package/src/js/dialog-fallback.js +0 -163
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Fixed floating action placement and a native-details speed dial.
|
|
3
|
+
* Button owns the action's size, shape, and intent; FAB only owns placement.
|
|
4
|
+
*
|
|
5
|
+
* Public hooks:
|
|
6
|
+
* --fab-offset
|
|
7
|
+
* --fab-gap
|
|
8
|
+
*/
|
|
9
|
+
.fab {
|
|
10
|
+
--fab-offset: var(--space-40);
|
|
11
|
+
--fab-gap: var(--space-20);
|
|
12
|
+
|
|
13
|
+
position: fixed;
|
|
14
|
+
z-index: var(--z-menu);
|
|
15
|
+
inset-block-end: max(var(--fab-offset), env(safe-area-inset-bottom));
|
|
16
|
+
inset-inline-end: var(--fab-offset);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.fab > summary {
|
|
20
|
+
list-style: none;
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.fab > summary::-webkit-details-marker {
|
|
25
|
+
display: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* A lone decorative plus can communicate the open/close state without
|
|
29
|
+
requiring a second icon or JavaScript-managed content. */
|
|
30
|
+
.fab > summary > [aria-hidden="true"]:only-child {
|
|
31
|
+
display: inline-block;
|
|
32
|
+
transition: transform var(--duration);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.fab-actions {
|
|
36
|
+
position: absolute;
|
|
37
|
+
inset-inline-end: 0;
|
|
38
|
+
inset-block-end: calc(100% + var(--fab-gap));
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
align-items: flex-end;
|
|
42
|
+
gap: var(--fab-gap);
|
|
43
|
+
opacity: 0;
|
|
44
|
+
visibility: hidden;
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
transform: translateY(var(--space-10));
|
|
47
|
+
transition:
|
|
48
|
+
opacity var(--duration),
|
|
49
|
+
transform var(--duration),
|
|
50
|
+
visibility 0s linear var(--duration);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* One action is one compact row. Keeping this relationship inside FAB avoids
|
|
54
|
+
wrapping and prevents labels from becoming visually associated with the
|
|
55
|
+
preceding or following button. */
|
|
56
|
+
.fab-action {
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
justify-content: flex-end;
|
|
60
|
+
gap: var(--fab-gap);
|
|
61
|
+
inline-size: max-content;
|
|
62
|
+
max-inline-size: calc(var(--viewport-inline) - var(--fab-offset) - var(--fab-offset));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.fab-label {
|
|
66
|
+
flex: 0 1 auto;
|
|
67
|
+
overflow: hidden;
|
|
68
|
+
max-inline-size: 16rem;
|
|
69
|
+
padding: var(--space-10) var(--space-20);
|
|
70
|
+
border-radius: var(--radius);
|
|
71
|
+
background: var(--surface);
|
|
72
|
+
color: var(--text);
|
|
73
|
+
box-shadow: var(--shadow);
|
|
74
|
+
font-size: var(--font-size-xs);
|
|
75
|
+
font-weight: var(--font-weight-medium);
|
|
76
|
+
line-height: var(--line-height-tight);
|
|
77
|
+
text-overflow: ellipsis;
|
|
78
|
+
white-space: nowrap;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.fab[open] > .fab-actions {
|
|
82
|
+
opacity: 1;
|
|
83
|
+
visibility: visible;
|
|
84
|
+
pointer-events: auto;
|
|
85
|
+
transform: translateY(0);
|
|
86
|
+
transition-delay: 0s;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.fab[open] > summary > [aria-hidden="true"]:only-child {
|
|
90
|
+
transform: rotate(45deg);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@media (forced-colors: active) {
|
|
94
|
+
.fab-label {
|
|
95
|
+
border: var(--border-width) solid CanvasText;
|
|
96
|
+
box-shadow: none;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@media print {
|
|
101
|
+
.fab {
|
|
102
|
+
display: none;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Floating labels — optional composition over the text controls
|
|
3
|
+
* (.input, .textarea, .select) and .field-label.
|
|
4
|
+
*
|
|
5
|
+
* The cell owns a control plus its label; the label overlays the control and
|
|
6
|
+
* floats to the top when the control is focused or non-empty. Help and error
|
|
7
|
+
* messages stay in the surrounding .field, not inside the cell, so the
|
|
8
|
+
* resting label can center on the control alone.
|
|
9
|
+
*
|
|
10
|
+
* The control must precede the label: the float is driven by the sibling
|
|
11
|
+
* combinator and :placeholder-shown. Every .input/.textarea needs
|
|
12
|
+
* placeholder=" " to expose a reliable empty state — without it the label
|
|
13
|
+
* only reacts to focus.
|
|
14
|
+
*
|
|
15
|
+
* Density flows through --control-size: .sm/.lg shrink the control geometry
|
|
16
|
+
* and the reserved headroom with it, leaving typography untouched.
|
|
17
|
+
*
|
|
18
|
+
* Public hooks:
|
|
19
|
+
* --floating-pad-block-start
|
|
20
|
+
*/
|
|
21
|
+
.floating-field {
|
|
22
|
+
--floating-pad-block-start: calc(var(--control-size) / 2 + var(--space-20));
|
|
23
|
+
|
|
24
|
+
/* Grid blockifies the control, removing the inline descender gap a textarea
|
|
25
|
+
would otherwise leave under itself. */
|
|
26
|
+
position: relative;
|
|
27
|
+
display: grid;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.floating-field > :is(.input, .textarea, .select) {
|
|
31
|
+
/* Headroom for the floated label is always reserved, so the value never
|
|
32
|
+
jumps when the label floats. Half the control centers the resting label;
|
|
33
|
+
the extra step clears the floated label's bottom edge. */
|
|
34
|
+
padding-block-start: var(--floating-pad-block-start);
|
|
35
|
+
padding-block-end: var(--space-10);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.floating-field > .field-label {
|
|
39
|
+
position: absolute;
|
|
40
|
+
inset-block-start: 50%;
|
|
41
|
+
inset-inline-start: calc(var(--space-30) + var(--border-width));
|
|
42
|
+
transform: translateY(-50%);
|
|
43
|
+
color: var(--text-muted);
|
|
44
|
+
font-size: var(--control-font-size);
|
|
45
|
+
font-weight: var(--font-weight);
|
|
46
|
+
pointer-events: none;
|
|
47
|
+
transition:
|
|
48
|
+
inset-block-start var(--duration),
|
|
49
|
+
transform var(--duration),
|
|
50
|
+
font-size var(--duration),
|
|
51
|
+
color var(--duration);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* A textarea's resting label aligns with the first text line instead of
|
|
55
|
+
centering in the (tall) control. */
|
|
56
|
+
.floating-field > .textarea + .field-label {
|
|
57
|
+
inset-block-start: var(--floating-pad-block-start);
|
|
58
|
+
transform: none;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* :autofill covers prefilled values before interaction, when the browser may
|
|
62
|
+
not have propagated the value to the placeholder state yet. */
|
|
63
|
+
.floating-field
|
|
64
|
+
> :is(.input, .textarea):is(:focus, :autofill, :not(:placeholder-shown))
|
|
65
|
+
+ .field-label {
|
|
66
|
+
inset-block-start: var(--space-10);
|
|
67
|
+
transform: none;
|
|
68
|
+
font-size: var(--font-size-xs);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* Controls without a dependable :placeholder-shown empty state stay floated:
|
|
72
|
+
select always, and date/time inputs whose placeholder rendering is
|
|
73
|
+
inconsistent across engines (Firefox shows none). */
|
|
74
|
+
.floating-field
|
|
75
|
+
> :is(
|
|
76
|
+
.select,
|
|
77
|
+
.input[type="date"],
|
|
78
|
+
.input[type="time"],
|
|
79
|
+
.input[type="datetime-local"],
|
|
80
|
+
.input[type="month"],
|
|
81
|
+
.input[type="week"]
|
|
82
|
+
)
|
|
83
|
+
+ .field-label {
|
|
84
|
+
inset-block-start: var(--space-10);
|
|
85
|
+
transform: none;
|
|
86
|
+
font-size: var(--font-size-xs);
|
|
87
|
+
}
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Additional layout primitives not included in the core bundle.
|
|
3
3
|
*
|
|
4
4
|
* Import this file explicitly when a project needs these patterns.
|
|
5
|
+
*
|
|
6
|
+
* Public hooks:
|
|
7
|
+
* --switcher-threshold
|
|
5
8
|
*/
|
|
6
9
|
.switcher {
|
|
7
10
|
display: flex;
|
|
@@ -22,8 +25,8 @@
|
|
|
22
25
|
* to the page.
|
|
23
26
|
*
|
|
24
27
|
* Not for marketing/editorial site headers — those are one-off visual
|
|
25
|
-
* identity per page; see docs/patterns.md's Header Navigation
|
|
26
|
-
* This is for the structural app-shell topbar, which recurs unchanged
|
|
28
|
+
* identity per page; see docs/pages/patterns/overview.md's Header Navigation
|
|
29
|
+
* section. This is for the structural app-shell topbar, which recurs unchanged
|
|
27
30
|
* across app UIs regardless of brand.
|
|
28
31
|
*/
|
|
29
32
|
.topbar {
|
|
@@ -34,8 +37,8 @@
|
|
|
34
37
|
display: flex;
|
|
35
38
|
align-items: center;
|
|
36
39
|
gap: var(--gap);
|
|
37
|
-
padding-block: var(--space-
|
|
38
|
-
padding-inline: var(--space-
|
|
40
|
+
padding-block: var(--space-30);
|
|
41
|
+
padding-inline: var(--space-40);
|
|
39
42
|
border-block-end: var(--border-width) solid var(--border);
|
|
40
43
|
background: var(--surface);
|
|
41
44
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* One-time code input with visual cells and one native input.
|
|
3
|
+
*
|
|
4
|
+
* Add one direct span per accepted character. The cells determine the
|
|
5
|
+
* component width; the overlaid input remains the only interactive control.
|
|
6
|
+
*
|
|
7
|
+
* Public hooks:
|
|
8
|
+
* --otp-cell-size
|
|
9
|
+
* --otp-gap
|
|
10
|
+
* --otp-font-size
|
|
11
|
+
*
|
|
12
|
+
* Internal:
|
|
13
|
+
* --otp-cell-border
|
|
14
|
+
* --otp-cell-bg
|
|
15
|
+
*/
|
|
16
|
+
.otp {
|
|
17
|
+
--otp-cell-size: var(--control-size);
|
|
18
|
+
--otp-gap: var(--space-10);
|
|
19
|
+
--otp-font-size: 1.5rem;
|
|
20
|
+
--otp-cell-border: var(--border);
|
|
21
|
+
--otp-cell-bg: var(--surface);
|
|
22
|
+
|
|
23
|
+
position: relative;
|
|
24
|
+
display: inline-grid;
|
|
25
|
+
grid-auto-flow: column;
|
|
26
|
+
grid-auto-columns: var(--otp-cell-size);
|
|
27
|
+
inline-size: fit-content;
|
|
28
|
+
max-inline-size: 100%;
|
|
29
|
+
gap: var(--otp-gap);
|
|
30
|
+
border-radius: var(--radius);
|
|
31
|
+
direction: ltr;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.otp > span {
|
|
35
|
+
inline-size: var(--otp-cell-size);
|
|
36
|
+
block-size: var(--otp-cell-size);
|
|
37
|
+
border: var(--border-width) solid var(--otp-cell-border);
|
|
38
|
+
border-radius: var(--radius);
|
|
39
|
+
background: var(--otp-cell-bg);
|
|
40
|
+
transition:
|
|
41
|
+
border-color var(--duration),
|
|
42
|
+
background-color var(--duration),
|
|
43
|
+
box-shadow var(--duration);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* The native input owns focus, selection, autofill, paste, and one-time-code
|
|
47
|
+
integration. Its spacing aligns monospace glyphs with the visual cells. */
|
|
48
|
+
.otp > input {
|
|
49
|
+
position: absolute;
|
|
50
|
+
z-index: 1;
|
|
51
|
+
inset: 0;
|
|
52
|
+
inline-size: 100%;
|
|
53
|
+
block-size: 100%;
|
|
54
|
+
margin: 0;
|
|
55
|
+
padding: 0 calc((var(--otp-cell-size) - 1ch) / 2);
|
|
56
|
+
border: 0;
|
|
57
|
+
outline: 2px solid transparent;
|
|
58
|
+
box-shadow: none;
|
|
59
|
+
background: transparent;
|
|
60
|
+
color: var(--text);
|
|
61
|
+
font-family: var(--font-mono);
|
|
62
|
+
font-size: var(--otp-font-size);
|
|
63
|
+
font-variant-numeric: tabular-nums;
|
|
64
|
+
line-height: var(--otp-cell-size);
|
|
65
|
+
letter-spacing: calc(var(--otp-cell-size) + var(--otp-gap) - 1ch);
|
|
66
|
+
text-align: start;
|
|
67
|
+
appearance: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.otp:focus-within {
|
|
71
|
+
box-shadow: var(--focus-ring-shadow);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.otp > input:focus ~ span {
|
|
75
|
+
--otp-cell-border: var(--focus);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.otp > input[aria-invalid="true"] ~ span,
|
|
79
|
+
.needs-validation.was-validated .otp > input:invalid ~ span {
|
|
80
|
+
--otp-cell-border: var(--danger);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@supports selector(:user-invalid) {
|
|
84
|
+
.needs-validation .otp > input:user-invalid ~ span {
|
|
85
|
+
--otp-cell-border: var(--danger);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.otp > input:disabled {
|
|
90
|
+
color: var(--state-disabled);
|
|
91
|
+
cursor: not-allowed;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.otp > input:disabled ~ span {
|
|
95
|
+
--otp-cell-bg: var(--surface-subtle);
|
|
96
|
+
|
|
97
|
+
opacity: var(--disabled-opacity);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@media (forced-colors: active) {
|
|
101
|
+
.otp:focus-within {
|
|
102
|
+
outline: var(--focus-outline);
|
|
103
|
+
outline-offset: var(--focus-outline-offset);
|
|
104
|
+
box-shadow: none;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.otp > input:focus ~ span {
|
|
108
|
+
--otp-cell-border: Highlight;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.otp > input[aria-invalid="true"] ~ span,
|
|
112
|
+
.needs-validation.was-validated .otp > input:invalid ~ span {
|
|
113
|
+
--otp-cell-border: Mark;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
* This is not a full carousel. For previous/next controls, pagination,
|
|
6
6
|
* active state, drag behavior, looping, or robust desktop mouse interaction,
|
|
7
7
|
* use a dedicated carousel library.
|
|
8
|
+
*
|
|
9
|
+
* Public hooks:
|
|
10
|
+
* --scroll-snap-gap
|
|
11
|
+
* --scroll-snap-align
|
|
12
|
+
* --scroll-snap-item-size
|
|
13
|
+
* --scroll-snap-padding
|
|
8
14
|
*/
|
|
9
15
|
.scroll-snap {
|
|
10
16
|
--scroll-snap-gap: var(--gap);
|
|
@@ -2,8 +2,16 @@
|
|
|
2
2
|
* Scroller — optional custom scrollbar styling for overflow regions.
|
|
3
3
|
*
|
|
4
4
|
* Apply to any scroll container (.overflow-auto, sidebars, long tables). Both
|
|
5
|
-
*
|
|
6
|
-
* the thumb lands as a thin, theme-aware affordance with a hover
|
|
5
|
+
* scrollbar-color (Firefox) and ::-webkit-scrollbar (Safari/Chromium) are
|
|
6
|
+
* styled; the thumb lands as a thin, theme-aware affordance with a hover
|
|
7
|
+
* state.
|
|
8
|
+
*
|
|
9
|
+
* Public hooks:
|
|
10
|
+
* --scroller-size
|
|
11
|
+
* --scroller-padding
|
|
12
|
+
* --scroller-track
|
|
13
|
+
* --scroller-thumb
|
|
14
|
+
* --scroller-thumb-hover
|
|
7
15
|
*/
|
|
8
16
|
.scroller {
|
|
9
17
|
--scroller-size: 0.625rem;
|
|
@@ -38,11 +46,9 @@
|
|
|
38
46
|
background-clip: content-box;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
background-clip: content-box;
|
|
45
|
-
}
|
|
49
|
+
.scroller::-webkit-scrollbar-thumb:hover {
|
|
50
|
+
background: var(--scroller-thumb-hover);
|
|
51
|
+
background-clip: content-box;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
.scroller::-webkit-scrollbar-corner {
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
* --fluid-display, --fluid-title, --fluid-lead (size tokens, clamp())
|
|
15
15
|
* .text-display, .text-title, .text-lead (composed classes)
|
|
16
16
|
*
|
|
17
|
+
* Public hooks:
|
|
18
|
+
* --fluid-display
|
|
19
|
+
* --fluid-title
|
|
20
|
+
* --fluid-lead
|
|
21
|
+
*
|
|
17
22
|
* Values are generated from scripts/rfs.ts over the 360px -> 1440px range.
|
|
18
23
|
*/
|
|
19
24
|
:root {
|
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
* They are escape hatches for layout nudges, not a full atomic scale.
|
|
6
6
|
*
|
|
7
7
|
* Core principle:
|
|
8
|
-
* - .sm / .lg provide local rhythm through --gap and --
|
|
8
|
+
* - .sm / .lg provide local rhythm through --gap and --density-space.
|
|
9
9
|
* - utilities consume the current context instead of defining their own -sm/-lg scale.
|
|
10
10
|
* - optional utilities extend core utilities, they do not re-express them.
|
|
11
11
|
* - follow verbose .{property}-{value} naming.
|
|
12
|
+
*
|
|
13
|
+
* Internal:
|
|
14
|
+
* --cluster-justify (local relay consumed by .cluster)
|
|
12
15
|
*/
|
|
13
16
|
|
|
14
17
|
/* Display */
|
|
@@ -83,6 +86,18 @@
|
|
|
83
86
|
flex-wrap: nowrap;
|
|
84
87
|
}
|
|
85
88
|
|
|
89
|
+
.gap-sm {
|
|
90
|
+
gap: var(--space-20);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.gap-md {
|
|
94
|
+
gap: var(--space-40);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.gap-lg {
|
|
98
|
+
gap: var(--space-50);
|
|
99
|
+
}
|
|
100
|
+
|
|
86
101
|
.justify-content-start {
|
|
87
102
|
--cluster-justify: flex-start;
|
|
88
103
|
justify-content: flex-start;
|
|
@@ -117,7 +132,7 @@
|
|
|
117
132
|
|
|
118
133
|
/* Spacing */
|
|
119
134
|
.padding-context {
|
|
120
|
-
padding: var(--
|
|
135
|
+
padding: var(--density-space);
|
|
121
136
|
}
|
|
122
137
|
|
|
123
138
|
.margin-inline-auto {
|
package/src/css/prose.css
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Global element styles stay mild so app UI is not shaped accidentally. Page
|
|
5
5
|
* layout, forms, cards, navigation, and app tables remain outside this scope.
|
|
6
|
+
*
|
|
7
|
+
* Public hooks:
|
|
8
|
+
* --prose-size
|
|
9
|
+
* --prose-line-height
|
|
10
|
+
* --prose-measure
|
|
11
|
+
* --prose-flow
|
|
12
|
+
* --prose-heading-line-height
|
|
13
|
+
* --prose-h1
|
|
14
|
+
* --prose-h2
|
|
15
|
+
* --prose-h3
|
|
16
|
+
* --prose-h4
|
|
6
17
|
*/
|
|
7
18
|
|
|
8
19
|
.prose {
|
|
@@ -66,15 +77,13 @@
|
|
|
66
77
|
text-underline-offset: 0.18em;
|
|
67
78
|
}
|
|
68
79
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
80
|
+
.prose a:hover {
|
|
81
|
+
text-decoration-thickness: 0.12em;
|
|
82
|
+
}
|
|
73
83
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
84
|
+
@supports (color: color-mix(in oklch, red, white)) {
|
|
85
|
+
.prose a:hover {
|
|
86
|
+
color: color-mix(in oklch, var(--primary), var(--text) 15%);
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
89
|
|
|
@@ -94,6 +103,7 @@
|
|
|
94
103
|
font-size: 0.875em;
|
|
95
104
|
}
|
|
96
105
|
|
|
106
|
+
/* Visual twin of .key (components/key.css) — keep the two recipes in sync. */
|
|
97
107
|
.prose kbd {
|
|
98
108
|
display: inline-flex;
|
|
99
109
|
align-items: center;
|
package/src/css/reset.css
CHANGED
|
@@ -24,16 +24,6 @@ select {
|
|
|
24
24
|
display: none !important;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
/* Legacy dialog fallback only. Modern dialogs keep the browser's native closed
|
|
28
|
-
state so display/overlay transitions are not flattened by the reset.
|
|
29
|
-
The presentation for the dialog-fallback.js shim lives in the separate
|
|
30
|
-
dialog-fallback.css, so it can be dropped from custom bundles. */
|
|
31
|
-
@supports not (selector(dialog:modal)) {
|
|
32
|
-
dialog:not([open]) {
|
|
33
|
-
display: none;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
27
|
:where(img, svg, video) {
|
|
38
28
|
max-inline-size: 100%;
|
|
39
29
|
block-size: auto;
|
package/src/css/theme.css
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Theme tokens — the palette, surfaces, text, borders, radius and shadow
|
|
3
|
+
* color. Named themes (themes/*.css) override this file; authors can set the
|
|
4
|
+
* same tokens on :root or on [data-theme="…"] islands.
|
|
5
|
+
*
|
|
6
|
+
* Public: Intent colors, Surfaces, Text, Lines and focus, Radius scale,
|
|
7
|
+
* Shadow color, Focus ring derivation.
|
|
8
|
+
* Derived: "Theme-derived aliases", Tone subsystem, Backdrop fill — reference
|
|
9
|
+
* other tokens; hard-coded overrides on a custom theme will break the intent.
|
|
10
|
+
* Internal: --hgroup-gap.
|
|
11
|
+
*/
|
|
1
12
|
:root {
|
|
2
13
|
color-scheme: light dark;
|
|
3
14
|
}
|
|
@@ -65,7 +76,6 @@
|
|
|
65
76
|
/* Pre-color-mix fallback only — superseded below by a derivation from
|
|
66
77
|
--focus so overriding --neutral/--focus never leaves a stale ring. */
|
|
67
78
|
--focus-ring: hsl(258 7% 43% / 0.3);
|
|
68
|
-
--focus-ring-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring);
|
|
69
79
|
--hover-overlay: hsl(260 20% 10% / 0.04);
|
|
70
80
|
|
|
71
81
|
/* Radius scale — themes may override the whole scale (e.g. [data-theme="square"]) */
|
|
@@ -76,13 +86,19 @@
|
|
|
76
86
|
/* Shadow color — consumed by --shadow / --shadow-popout in tokens.css */
|
|
77
87
|
--shadow-color: hsl(260 25% 10%);
|
|
78
88
|
|
|
79
|
-
/*
|
|
89
|
+
/* hgroup internal gap */
|
|
90
|
+
--hgroup-gap: 0.25em;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Theme-derived aliases — re-declared on every theme boundary (see tokens.css
|
|
94
|
+
for the custom-property resolution rationale): islands recompute these from
|
|
95
|
+
their own tokens instead of inheriting :root's resolved values. */
|
|
96
|
+
:root,
|
|
97
|
+
[data-theme] {
|
|
80
98
|
--heading: var(--text);
|
|
81
99
|
--selection-bg: var(--primary);
|
|
82
100
|
--selection-fg: var(--primary-fg);
|
|
83
|
-
|
|
84
|
-
/* hgroup internal gap */
|
|
85
|
-
--hgroup-gap: 0.25em;
|
|
101
|
+
--focus-ring-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring);
|
|
86
102
|
}
|
|
87
103
|
|
|
88
104
|
/* Tone subsystem — fixed-backdrop foreground for components placed over media
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* Cyberpunk — light-only stress-test theme (single block, color-scheme: light,
|
|
2
|
-
* same shape as
|
|
2
|
+
* same shape as indigo.css). Illustrative rather than production: it exists to
|
|
3
3
|
* prove the token contract survives an extreme spec — a saturated yellow
|
|
4
4
|
* canvas, near-black text and borders, dark-on-bright intent pairs, zero
|
|
5
5
|
* radius, 2px strokes, and hard offset shadows — without touching a single
|
package/src/css/themes/dim.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Dim — a dark theme variant that lifts the surface tones up a few percentage
|
|
2
|
-
* points. Same shape as
|
|
3
|
-
* it in when the canonical dark is too dense. Demonstrates how a theme
|
|
4
|
-
* recolor the same token set without changing structure. */
|
|
2
|
+
* points. Same shape as indigo.css (dark-only, single block) so authors can
|
|
3
|
+
* drop it in when the canonical dark is too dense. Demonstrates how a theme
|
|
4
|
+
* can recolor the same token set without changing structure. */
|
|
5
5
|
[data-theme="dim"] {
|
|
6
6
|
color-scheme: dark;
|
|
7
7
|
|
package/src/css/themes/edge.css
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* intent-colored lower edge (.solid remains available when an action needs a
|
|
4
4
|
* filled treatment), text controls (input/textarea/select) pick up the same
|
|
5
5
|
* lower-edge accent via --control-border-block-end-*, alerts get an
|
|
6
|
-
* intent-colored leading flag via --alert-border-inline-start
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* intent-colored leading flag via --alert-border-inline-start-*. The focus
|
|
7
|
+
* ring keeps the shared width — edge only drops the border-color flip so the
|
|
8
|
+
* intent-colored lower edge stays dominant. */
|
|
9
9
|
[data-theme="edge"] {
|
|
10
10
|
color-scheme: light dark;
|
|
11
11
|
|
|
@@ -61,13 +61,11 @@
|
|
|
61
61
|
--ui-hover-bg: var(--surface-raised);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
box-shadow: none;
|
|
70
|
-
}
|
|
64
|
+
[data-theme="edge"]
|
|
65
|
+
.btn:not(
|
|
66
|
+
:where(:disabled, [aria-disabled="true"], .solid, .soft, .outline, .ghost, .link)
|
|
67
|
+
):hover {
|
|
68
|
+
box-shadow: none;
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
/* Intent-dependent alert token, same reasoning as the button rule above:
|
package/src/css/themes/index.css
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* The themes are illustrative: each one demonstrates a different set of knobs
|
|
6
6
|
* the token contract exposes, beyond recoloring.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* indigo — deep blue/violet dark palette (single block)
|
|
9
9
|
* dim — dark variant with lifted surface tones
|
|
10
10
|
* corporate — reference paired light/dark recolor via light-dark()
|
|
11
11
|
* forest — paired recolor + scaled-up radius tokens
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
* gradient — paired recolor + Bootstrap 4 style gradient on solid buttons
|
|
25
25
|
* via component-local button tokens
|
|
26
26
|
*
|
|
27
|
-
* Single-block themes (
|
|
27
|
+
* Single-block themes (indigo, dim, cyberpunk, neon) pin one color-scheme and
|
|
28
28
|
* cannot adapt to prefers-color-scheme; the paired ones follow the OS. */
|
|
29
|
-
@import "./
|
|
29
|
+
@import "./indigo.css";
|
|
30
30
|
@import "./dim.css";
|
|
31
31
|
@import "./corporate.css";
|
|
32
32
|
@import "./forest.css";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* does not adapt to prefers-color-scheme;
|
|
3
|
-
* dim.css is a darker variant with
|
|
4
|
-
|
|
1
|
+
/* Indigo — deep blue/violet palette, dark-only. Single-block shape
|
|
2
|
+
* (color-scheme: dark only) — it does not adapt to prefers-color-scheme;
|
|
3
|
+
* opt in via [data-theme="indigo"]. dim.css is a darker variant with
|
|
4
|
+
* lifted surface tones. */
|
|
5
|
+
[data-theme="indigo"] {
|
|
5
6
|
color-scheme: dark;
|
|
6
7
|
|
|
7
8
|
--primary: hsl(220 90% 66%);
|
package/src/css/themes/neon.css
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* Neon — dark-only theme (single block, color-scheme: dark, same shape as
|
|
2
|
-
*
|
|
3
|
-
* block uses sRGB-safe hsl() and works everywhere
|
|
4
|
-
* displays with oklch() support the intents are re-declared with chroma
|
|
5
|
-
* sRGB. This is the pattern for shipping colors sRGB cannot express
|
|
6
|
-
* breaking older screens or browsers. Also demonstrates the soft-variant
|
|
2
|
+
* indigo.css) that demonstrates wide-gamut progressive enhancement. The
|
|
3
|
+
* baseline block uses sRGB-safe hsl() and works everywhere indigo.css works;
|
|
4
|
+
* on P3 displays with oklch() support the intents are re-declared with chroma
|
|
5
|
+
* beyond sRGB. This is the pattern for shipping colors sRGB cannot express
|
|
6
|
+
* without breaking older screens or browsers. Also demonstrates the soft-variant
|
|
7
7
|
* tuning knobs and glow shadows on popovers. */
|
|
8
8
|
[data-theme="neon"] {
|
|
9
9
|
color-scheme: dark;
|
|
@@ -34,9 +34,6 @@
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
@supports (color: light-dark(red, blue)) {
|
|
37
|
-
/* Square — paired light/dark theme that demonstrates overriding the full
|
|
38
|
-
* --radius scale to 0 for sharp-cornered applications. The recolor is close to
|
|
39
|
-
* the default blue palette; the radius override is the point. */
|
|
40
37
|
[data-theme="square"] {
|
|
41
38
|
--primary: light-dark(hsl(220 90% 56%), hsl(220 75% 80%));
|
|
42
39
|
--primary-fg: light-dark(white, hsl(220 30% 12%));
|