@codenhub/styles 0.1.1 → 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/README.md +2 -1
- package/dist/aesthetics/chunky-tile.css +1 -1
- package/dist/aesthetics/index.css +1 -1
- package/dist/components.css +1 -1
- package/dist/index.css +1 -1
- package/dist/native.css +1 -1
- package/dist/palette.css +1 -0
- package/dist/theme.css +1 -1
- package/dist/tw/aesthetics/chunky-tile.css +16 -0
- package/dist/tw/box.css +24 -2
- package/dist/tw/components/button.css +22 -33
- package/dist/tw/components/feedback.css +87 -48
- package/dist/tw/components/form.css +139 -45
- package/dist/tw/components/index.css +1 -1
- package/dist/tw/components/loader.css +2 -16
- package/dist/tw/components/surface.css +93 -0
- package/dist/tw/components/tooltip.css +102 -91
- package/dist/tw/elevation.css +43 -7
- package/dist/tw/index.css +7 -4
- package/dist/tw/intent.css +16 -12
- package/dist/tw/palette.css +451 -0
- package/dist/tw/reset.css +21 -0
- package/dist/tw/theme.css +54 -8
- package/dist/tw/utilities/content.css +90 -16
- package/dist/tw/utilities/index.css +1 -1
- package/dist/tw/utilities/layout.css +33 -0
- package/docs/accessibility.md +34 -23
- package/docs/changelog/0.2.0.md +41 -0
- package/docs/changelog/0.3.0.md +15 -0
- package/docs/changelog/index.md +2 -0
- package/docs/concepts.md +1 -0
- package/docs/setup.md +42 -22
- package/docs/usage/aesthetics.md +4 -3
- package/docs/usage/buttons.md +17 -13
- package/docs/usage/composing.md +28 -21
- package/docs/usage/content-and-layout.md +10 -3
- package/docs/usage/customizing.md +27 -0
- package/docs/usage/feedback.md +18 -10
- package/docs/usage/forms.md +36 -26
- package/docs/usage/tooltips.md +48 -22
- package/llms-full.txt +318 -143
- package/package.json +9 -2
|
@@ -3,16 +3,20 @@
|
|
|
3
3
|
@reference "../box.css";
|
|
4
4
|
@reference "./surface.css";
|
|
5
5
|
|
|
6
|
-
/* The host is a positioning wrapper and nothing else
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
/* The host is a positioning wrapper and nothing else -- it paints no fill, no
|
|
7
|
+
edge, no material of its own. The bubble is a real element beside the
|
|
8
|
+
trigger rather than a pseudo-element attached to it, so intent,
|
|
9
|
+
presentation, aesthetic, and elevation classes go on `.tooltip-bubble`, the
|
|
10
|
+
thing actually shown, not on the wrapper -- the same rule every other
|
|
11
|
+
component in this package follows (theming.md: "Intent does not cascade").
|
|
12
|
+
|
|
13
|
+
Composing the bubble as a real element fixes a real gap, not just a styling
|
|
14
|
+
one: `content: attr(data-tooltip)` text is not reliably exposed to
|
|
15
|
+
assistive tech and cannot be the target of an `aria-describedby`, since that
|
|
16
|
+
needs a real element with a real `id`. A real bubble can carry
|
|
17
|
+
`role="tooltip"` and be referenced by the trigger's own `aria-describedby`;
|
|
18
|
+
wiring that association is the consumer's, this package only styles the
|
|
19
|
+
bubble. See docs/usage/tooltips.md. */
|
|
16
20
|
@utility tooltip {
|
|
17
21
|
--tooltip-gap: 0.5rem;
|
|
18
22
|
--tooltip-top: calc(var(--tooltip-gap) * -1);
|
|
@@ -22,34 +26,7 @@
|
|
|
22
26
|
--tooltip-origin: bottom;
|
|
23
27
|
--tooltip-transform: translate(-50%, -100%);
|
|
24
28
|
|
|
25
|
-
@apply relative;
|
|
26
|
-
|
|
27
|
-
/* The trigger badge, for a page with no element to hang the message on. Quiet
|
|
28
|
-
-- ghost, edged, on `--intent-subtle`, a key cap's resting shape -- because
|
|
29
|
-
it marks that there is a message, it is not one. The line earns its keep:
|
|
30
|
-
`--intent-subtle` is a near-page tint that reads the same across families,
|
|
31
|
-
so a plate alone left three of eight intents indistinguishable;
|
|
32
|
-
`--intent-border` is the slot that differs. Painting the host is right only
|
|
33
|
-
here -- everywhere else the bubble is outside the host's box, so painting it
|
|
34
|
-
boxes the trigger. `.tooltip-icon` is the opt-in that says the host *is* the
|
|
35
|
-
badge. */
|
|
36
|
-
&.tooltip-icon {
|
|
37
|
-
@apply box inline-flex size-5 cursor-default items-center justify-center text-sm font-bold;
|
|
38
|
-
|
|
39
|
-
--_d-fill: 0%;
|
|
40
|
-
--_d-fg-on-fill: 0%;
|
|
41
|
-
--_d-border: 100%;
|
|
42
|
-
--_d-elevation: 0;
|
|
43
|
-
--_d-ground: var(--intent-subtle);
|
|
44
|
-
|
|
45
|
-
border-radius: var(--ui-radius, calc(infinity * 1px));
|
|
46
|
-
/* The one thing `box` hands it that it must refuse. An aesthetic's `clip-path`
|
|
47
|
-
clips a host's pseudo-elements along with the host, and this host's
|
|
48
|
-
pseudo-element is the bubble, positioned outside its box -- so a stepped
|
|
49
|
-
badge under `.pixel` would clip the message away entirely. The bubble
|
|
50
|
-
carries the stepped shape itself; the badge stays round. */
|
|
51
|
-
clip-path: none;
|
|
52
|
-
}
|
|
29
|
+
@apply relative inline-block;
|
|
53
30
|
|
|
54
31
|
&[data-tooltip-position="bottom"] {
|
|
55
32
|
--tooltip-top: auto;
|
|
@@ -72,61 +49,95 @@
|
|
|
72
49
|
--tooltip-origin: left;
|
|
73
50
|
--tooltip-transform: translate(100%, -50%);
|
|
74
51
|
}
|
|
52
|
+
}
|
|
75
53
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
&.edgeless
|
|
54
|
+
/* The bubble. It is a surface, so an aesthetic that blurs surfaces blurs it
|
|
55
|
+
too, and it rests on a ground of its own, edged, and flat -- depth is
|
|
56
|
+
opt-in through its own `.raised`/`.floating`, like any other component, now
|
|
57
|
+
that it is one. No proxy inheritance is needed to carry elevation across a
|
|
58
|
+
host-to-pseudo-element gap: there is no gap, `.tooltip-bubble.raised` reads
|
|
59
|
+
`--ui-elevation` the ordinary way every other component does. See
|
|
60
|
+
model.md#elevation. */
|
|
61
|
+
@utility tooltip-bubble {
|
|
62
|
+
@apply surface pointer-events-none absolute z-(--z-popover) w-max max-w-72 px-2.5 py-2 text-sm font-normal whitespace-normal opacity-0 transition-[opacity,transform] duration-(--motion-duration-normal) ease-(--motion-ease);
|
|
63
|
+
|
|
64
|
+
/* Filled, over a ground of its own. An intent floods the fill
|
|
65
|
+
(`.tooltip-bubble.primary` is the primary colour); with no intent
|
|
66
|
+
`intent.css` resolves the bubble onto `--color-tooltip` and lifts the
|
|
67
|
+
neutral cap, a plate stated per theme because the derived version was a
|
|
68
|
+
mid-grey slab in light and lifted in dark. The ground stays the surface
|
|
69
|
+
tone, not the plate -- pointed at both, the fill axis went inert and
|
|
70
|
+
`axes.spec.ts` caught it. An opaque ground is also what keeps a cascaded
|
|
71
|
+
`.ghost` from leaving the bubble boundaryless. `--ui-surface-ground` is
|
|
72
|
+
read first so a glass tooltip stays glass. */
|
|
73
|
+
--_d-fill: 100%;
|
|
74
|
+
--_d-fg-on-fill: 100%;
|
|
75
|
+
--_d-border: 100%;
|
|
76
|
+
--_d-elevation: 0;
|
|
77
|
+
--_d-ground: var(--ui-surface-ground, var(--intent-subtle));
|
|
78
|
+
|
|
79
|
+
/* The bubble's line is a boundary against content nobody chose, so `box`'s
|
|
80
|
+
edge blend is wrong here: at a full fill the line *is* the plate. Restate
|
|
81
|
+
the colour only; how much line comes from `--_edge-amount`, floored below. */
|
|
82
|
+
--_line: var(--intent-border);
|
|
83
|
+
|
|
84
|
+
/* Floored, for the same reason the ground is opaque: a cascade must not take
|
|
85
|
+
the boundary from a bubble nobody classed (worst in light, where the plate
|
|
86
|
+
is near-white). The element's own `.edgeless` lowers it -- same
|
|
87
|
+
element-vs-cascade idiom `text-control` uses. */
|
|
88
|
+
--_edge-floor: 100%;
|
|
89
|
+
|
|
90
|
+
/* A bubble is a small transient popover, not a modal, so it takes the
|
|
91
|
+
control radius rather than the surface one `surface` hands it. */
|
|
92
|
+
border-radius: var(--ui-radius, var(--radius-control));
|
|
93
|
+
left: var(--tooltip-left);
|
|
94
|
+
right: var(--tooltip-right);
|
|
95
|
+
top: var(--tooltip-top);
|
|
96
|
+
bottom: var(--tooltip-bottom);
|
|
97
|
+
transform: var(--tooltip-transform) scale(0);
|
|
98
|
+
transform-origin: var(--tooltip-origin);
|
|
99
|
+
|
|
100
|
+
&.edgeless {
|
|
123
101
|
--_edge-floor: 0%;
|
|
124
102
|
}
|
|
103
|
+
}
|
|
125
104
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
105
|
+
/* Shown on hover or focus anywhere in the host, or pinned open with
|
|
106
|
+
`data-state="open"`. `:focus-within` rather than the trigger's own
|
|
107
|
+
`:focus-visible`, the same substitution `.input-group` makes for the
|
|
108
|
+
identical reason: the bubble is a sibling, not a pseudo-element, of the
|
|
109
|
+
trigger, so nothing but the shared ancestor can see both at once. The cost
|
|
110
|
+
is the one `.input-group` already accepts -- the bubble also shows on a
|
|
111
|
+
mouse click, which the old `:focus-visible`-only version did not. */
|
|
112
|
+
.tooltip:hover .tooltip-bubble,
|
|
113
|
+
.tooltip:focus-within .tooltip-bubble,
|
|
114
|
+
.tooltip[data-state="open"] .tooltip-bubble {
|
|
115
|
+
opacity: 1;
|
|
116
|
+
transform: var(--tooltip-transform) scale(1);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* The trigger badge, for a message with no other element to hang it on. Quiet
|
|
120
|
+
-- ghost, edged, on `--intent-subtle`, a key cap's resting shape -- because
|
|
121
|
+
it marks that there is a message, it is not one. The line earns its keep:
|
|
122
|
+
`--intent-subtle` is a near-page tint that reads the same across families,
|
|
123
|
+
so a plate alone left three of eight intents indistinguishable;
|
|
124
|
+
`--intent-border` is the slot that differs.
|
|
125
|
+
|
|
126
|
+
`clip-path: none` used to exist to protect the bubble, a pseudo-element of
|
|
127
|
+
this same host, from being clipped away along with it under an aesthetic
|
|
128
|
+
like `.pixel`. The bubble is independent now, so that reason is gone, but
|
|
129
|
+
the declaration stays: the docs call this a circular fixed identity, not a
|
|
130
|
+
shape a container's aesthetic reaches, the same way `.radio` keeps its own
|
|
131
|
+
circle instead of taking `.pixel`'s stepped silhouette. */
|
|
132
|
+
@utility tooltip-icon {
|
|
133
|
+
@apply box inline-flex size-5 cursor-default items-center justify-center text-sm font-bold;
|
|
134
|
+
|
|
135
|
+
--_d-fill: 0%;
|
|
136
|
+
--_d-fg-on-fill: 0%;
|
|
137
|
+
--_d-border: 100%;
|
|
138
|
+
--_d-elevation: 0;
|
|
139
|
+
--_d-ground: var(--intent-subtle);
|
|
140
|
+
|
|
141
|
+
border-radius: var(--ui-radius, calc(infinity * 1px));
|
|
142
|
+
clip-path: none;
|
|
132
143
|
}
|
package/dist/tw/elevation.css
CHANGED
|
@@ -1,18 +1,54 @@
|
|
|
1
1
|
/* Elevation is a modifier, not an axis: depth is a per-element decision (raised
|
|
2
2
|
tiles beside a flat panel in one aesthetic), so one unitless number multiplies
|
|
3
|
-
the aesthetic's shadow geometry where the component composes it.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
the aesthetic's shadow geometry where the component composes it. `.flat`
|
|
4
|
+
removes a part-based slab or blur without a conditional (complete surface
|
|
5
|
+
shadows like glass remain). See model.md#elevation.
|
|
6
|
+
|
|
7
|
+
`--ui-elevation`, and the plain-page fallback geometry (`--elevation-y`,
|
|
8
|
+
`--elevation-blur`) below, are registered non-inheriting: a class sets them
|
|
9
|
+
on the element it is written on and nothing else picks them up. They used to
|
|
10
|
+
be ordinary inherited custom properties, on the reasoning that a container
|
|
11
|
+
could flatten or lift a whole region in one class and any element inside
|
|
12
|
+
could opt back out -- but the same mechanism let a `.floating` dialog's
|
|
13
|
+
ambient ×2 reach its own unclassed "Cancel"/"Remove" buttons, doubling their
|
|
14
|
+
shadow with nothing in the markup asking for that. Depth is not the same
|
|
15
|
+
kind of thing as color or material: a button inside a raised card is not
|
|
16
|
+
itself more raised, it is just resting normally inside an already-raised
|
|
17
|
+
surface. `--ui-shadow-*` -- what an aesthetic supplies -- is unaffected and
|
|
18
|
+
still cascades normally; that is a different mechanism (the material tokens
|
|
19
|
+
in `src/aesthetics/*.css`), and an aesthetic still has to reach every nested
|
|
20
|
+
component uniformly the way it always did. Registering these three is what
|
|
21
|
+
scopes the change to the elevation modifier alone.
|
|
10
22
|
|
|
11
23
|
`.flat`/`.raised`/`.floating` and `.elevation-none`/`-sm`/`-md` are
|
|
12
24
|
interchangeable aliases, the second borrowing the raw `--elevation-*` scale's
|
|
13
25
|
naming. Bare `sm`/`md`/`lg` would collide with the size modifier;
|
|
14
26
|
`.elevation-lg` is reserved, not shipped. */
|
|
15
27
|
|
|
28
|
+
/* `syntax: "*"` with no `initial-value` is deliberate: a numeric syntax would
|
|
29
|
+
require one (CSS Properties and Values API), and any initial-value at all
|
|
30
|
+
would mean the property is never actually unset on an element that does not
|
|
31
|
+
write it -- which is exactly the state `var(--ui-elevation, var(--_d-elevation,
|
|
32
|
+
1))` in `box.css` needs to fall through to a component's own default. With
|
|
33
|
+
no initial-value and `inherits: false`, an element that does not set the
|
|
34
|
+
property directly computes it as guaranteed-invalid, the same as if it had
|
|
35
|
+
never been registered at all -- `var()` takes its fallback precisely where
|
|
36
|
+
inheritance used to hand it an ambient value instead. */
|
|
37
|
+
@property --ui-elevation {
|
|
38
|
+
syntax: "*";
|
|
39
|
+
inherits: false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@property --elevation-y {
|
|
43
|
+
syntax: "*";
|
|
44
|
+
inherits: false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@property --elevation-blur {
|
|
48
|
+
syntax: "*";
|
|
49
|
+
inherits: false;
|
|
50
|
+
}
|
|
51
|
+
|
|
16
52
|
/* No part-based depth. Complete surface shadow values, such as glass, are not
|
|
17
53
|
reached by the elevation multiplier. */
|
|
18
54
|
.elevation-none,
|
package/dist/tw/index.css
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
sees only this package's own files. The `src/` scan is load-bearing -- it is
|
|
5
5
|
how the composition utilities (`box`, `surface`, `text-control`,
|
|
6
6
|
`input-group`, `loader-mask`) get emitted as standalone rules, since nothing
|
|
7
|
-
`@source inline`s them -- so `source(none)` is not an option.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
`@source inline`s them -- so `source(none)` is not an option. A handful of
|
|
8
|
+
Tailwind utility names also collide with a CSS property or a word this
|
|
9
|
+
file's own comments use (`backdrop-filter`, `filter`, `transition`,
|
|
10
|
+
`transform`, `container`), which reads like a risk of the same scan --
|
|
11
|
+
verified against Tailwind 4.3.2, none of them emit.
|
|
12
|
+
`tests/integration/exports.test.ts` guards it, so a scanner change that
|
|
13
|
+
starts emitting one is caught rather than shipping silently.
|
|
11
14
|
|
|
12
15
|
The `@source not` lines below keep everything that is not `src/` out of that
|
|
13
16
|
scan: the sibling app and fixture directories, the `docs/` tree, the build
|
package/dist/tw/intent.css
CHANGED
|
@@ -133,7 +133,8 @@
|
|
|
133
133
|
.data-table,
|
|
134
134
|
.pre,
|
|
135
135
|
.quote,
|
|
136
|
-
.tooltip,
|
|
136
|
+
.tooltip-bubble,
|
|
137
|
+
.tooltip-icon,
|
|
137
138
|
.badge,
|
|
138
139
|
.kbd,
|
|
139
140
|
.code,
|
|
@@ -168,8 +169,8 @@
|
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
/* The bubble a tooltip draws is the one plate in the package that is chosen
|
|
171
|
-
rather than composed, so
|
|
172
|
-
|
|
172
|
+
rather than composed, so it resolves the no-intent case onto its own pair
|
|
173
|
+
instead of onto the shared neutral. Composed, it was 20% of the page's
|
|
173
174
|
ink over `--color-surface`, which lifts off a dark page and sinks into a light
|
|
174
175
|
one -- see `--color-tooltip` in `theme.css` for the measurements.
|
|
175
176
|
|
|
@@ -178,17 +179,20 @@
|
|
|
178
179
|
rather than an ink, so a full fill of it is the plate and there is nothing to
|
|
179
180
|
stop short of.
|
|
180
181
|
|
|
181
|
-
`--intent-subtle` stays the surface token
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
`--intent-subtle` stays the surface token, the same tone every other
|
|
183
|
+
unclassed component sits on. `.tooltip-icon`, the trigger badge, is a
|
|
184
|
+
separate element now and does not read this block at all -- it never fills
|
|
185
|
+
past `0%`, so the generic neutral reset above it is enough, and it keeps its
|
|
186
|
+
own resting ground and line independent of whatever intent the bubble shows.
|
|
184
187
|
|
|
185
188
|
Two selectors, because `none` and `neutral` have to agree here. `:where()`
|
|
186
|
-
loses to any intent class, so `.tooltip.primary` still floods with
|
|
187
|
-
`.tooltip.neutral` carries 0-2-0 and beats `.neutral`, so
|
|
188
|
-
out gives the same bubble as writing nothing. Without the
|
|
189
|
-
two would differ on a component where they mean the
|
|
190
|
-
|
|
191
|
-
.tooltip
|
|
189
|
+
loses to any intent class, so `.tooltip-bubble.primary` still floods with
|
|
190
|
+
primary; `.tooltip-bubble.neutral` carries 0-2-0 and beats `.neutral`, so
|
|
191
|
+
writing the intent out gives the same bubble as writing nothing. Without the
|
|
192
|
+
second selector the two would differ on a component where they mean the
|
|
193
|
+
same thing. */
|
|
194
|
+
:where(.tooltip-bubble),
|
|
195
|
+
.tooltip-bubble.neutral {
|
|
192
196
|
--intent-color: var(--color-tooltip);
|
|
193
197
|
--intent-contrast: var(--color-tooltip-contrast);
|
|
194
198
|
--intent-hover: var(--color-tooltip);
|