@codenhub/styles 0.1.1 → 0.2.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/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 +58 -41
- 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/reset.css +21 -0
- package/dist/tw/theme.css +40 -7
- 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 +33 -23
- package/docs/changelog/0.2.0.md +41 -0
- package/docs/changelog/index.md +1 -0
- package/docs/concepts.md +1 -0
- package/docs/setup.md +41 -22
- package/docs/usage/aesthetics.md +4 -3
- package/docs/usage/buttons.md +17 -13
- package/docs/usage/composing.md +12 -8
- package/docs/usage/content-and-layout.md +10 -3
- package/docs/usage/feedback.md +16 -9
- package/docs/usage/forms.md +36 -26
- package/docs/usage/tooltips.md +48 -22
- package/llms-full.txt +258 -129
- package/package.json +1 -1
package/docs/usage/composing.md
CHANGED
|
@@ -44,6 +44,8 @@ Values each class ships:
|
|
|
44
44
|
| `.edged` | | | `100%` |
|
|
45
45
|
| `.edgeless` | | | `0%` |
|
|
46
46
|
|
|
47
|
+
`.card`, `.panel`, `.alert`, `.kbd`, `.code`, and `.pre` override `.soft`'s fill at rest to `0%` for the no-named-intent case only, and reveal it on `.card`'s own `:hover`/`.interactive`/`.hoverable` -- the one place a component remaps what a presentation class resolves to for part of its intent range, the same way text controls cap it at `6%` cascaded. A named intent on any of the six keeps the ordinary `12%`. `.badge` reads the identical intent/presentation classes but keeps its 12% wash at rest even with no named intent, since it has no border to fall back on and would otherwise disappear rather than read quieter. See [Content and layout → Surfaces](./content-and-layout.md#surfaces) and [Feedback](./feedback.md).
|
|
48
|
+
|
|
47
49
|
The combinations mean exactly what they spell:
|
|
48
50
|
|
|
49
51
|
```html
|
|
@@ -71,10 +73,10 @@ With no presentation class in scope, each component keeps its own default: butto
|
|
|
71
73
|
| `.checkbox`, `.radio` | A capped fill, checked and unchecked. |
|
|
72
74
|
| `.switch` | Border, border width, and a capped fill. |
|
|
73
75
|
| `.quote` | Fill, text, border, and width. |
|
|
74
|
-
| `.code`, `.pre`, `.tooltip`
|
|
76
|
+
| `.code`, `.pre`, `.tooltip-bubble` | Fill, text, border, and material. |
|
|
75
77
|
| `.loader`, `.skeleton`, `.progress`, `.divider` | Intent only, not presentation. |
|
|
76
78
|
|
|
77
|
-
|
|
79
|
+
A text control caps a **cascaded** fill at `6%`, keeping typed text legible when a `.solid` container reaches a field nobody classed. A fill class written on the control itself names its own cap instead, because that is a consumer describing what they want: `.soft` takes `12%` and `.solid` takes `20%`.
|
|
78
80
|
|
|
79
81
|
| On a text control | fill |
|
|
80
82
|
| ----------------- | ---- |
|
|
@@ -83,13 +85,15 @@ Text controls and toggles cap a **cascaded** fill at `6%`, keeping typed text le
|
|
|
83
85
|
| `.soft` | 12% |
|
|
84
86
|
| `.solid` | 20% |
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
A toggle's cap does not have that split: it is `40%` whether the presentation class is on the checkbox/radio/switch itself or cascaded from a container, the same value for all three. That is where an unchecked `.ghost` (0%), `.soft`/default (12%), and `.solid` (the cap) read as three distinct plates instead of shades of the same wash. Being checked pins the fill to `100%` instead, whatever the presentation class asks — a checkbox, a radio, and a switch each have one "on" look, and presentation only shapes them unchecked. See [Forms](./forms.md) for the full toggle reference.
|
|
89
|
+
|
|
90
|
+
The same split governs the edge: a cascaded `.edgeless` is floored and the element's own is honoured — except on `.checkbox` and `.radio`, which never drop their line at all, and on `.switch.ghost`, which keeps its line specifically against its own `.edgeless`: `.ghost` already asks for zero fill, so removing the line too would leave nothing marking the track but the knob. `.switch.ghost.edgeless` renders the same as `.switch.ghost.edged` rather than as a distinct, boundary-less look. See [Forms](./forms.md) for the full toggle and text control reference.
|
|
87
91
|
|
|
88
|
-
A tooltip bubble is filled, over a tinted ground. An intent fills it with that intent's own color: `.tooltip.primary` is the primary color, black on a light page and white on a dark one, and `.tooltip.destructive` is a red bubble.
|
|
92
|
+
A tooltip bubble is filled, over a tinted ground. An intent fills it with that intent's own color: `.tooltip-bubble.primary` is the primary color, black on a light page and white on a dark one, and `.tooltip-bubble.destructive` is a red bubble.
|
|
89
93
|
|
|
90
94
|
With no intent the bubble is `--color-tooltip`, the one plate in the package chosen per theme rather than derived from an intent. Composed like everything else it was `20%` of the page's ink over the surface tone, which steps _lighter_ than the surface on a dark page and _darker_ on a light one — so the dark bubble read as lifted and the light one as a mid-grey slab two steps darker than every card on the screen. The token states each direction instead: near-white over a light page, a mid grey over a dark one. `--color-tooltip-contrast` is its ink.
|
|
91
95
|
|
|
92
|
-
Near-white is only 1.04:1 against a light page, so the bubble draws a hairline as well, and floors it: a container's `.solid` or `.edgeless` cannot take the boundary away from a bubble nobody classed, while `.tooltip.edgeless` still can. The ground keeps the bubble opaque at every fill, so a cascaded presentation leaves it readable over whatever it floats above. It reads the material tokens too, so an [aesthetic](./aesthetics.md) in scope shapes the bubble like any other component. See [Tooltips](./tooltips.md) for the full tooltip reference.
|
|
96
|
+
Near-white is only 1.04:1 against a light page, so the bubble draws a hairline as well, and floors it: a container's `.solid` or `.edgeless` cannot take the boundary away from a bubble nobody classed, while `.tooltip-bubble.edgeless` still can. The ground keeps the bubble opaque at every fill, so a cascaded presentation leaves it readable over whatever it floats above. It reads the material tokens too, so an [aesthetic](./aesthetics.md) in scope shapes the bubble like any other component. See [Tooltips](./tooltips.md) for the full tooltip reference.
|
|
93
97
|
|
|
94
98
|
## Component axis reference
|
|
95
99
|
|
|
@@ -111,14 +115,14 @@ Presentation is two independent axes, so they get a column each. A `Yes` means t
|
|
|
111
115
|
| `.switch` | Yes | Yes | Yes | Radius and edge |
|
|
112
116
|
| `.progress` | Yes | No | No | No |
|
|
113
117
|
| `.code`, `.pre` | Yes | Yes | Yes | Radius and clip |
|
|
114
|
-
| `.tooltip`
|
|
118
|
+
| `.tooltip-bubble` | Yes | Yes | Yes | Shape and overlay |
|
|
115
119
|
| `.table-wrap`, `.quote-inline`, layout and text utilities | No | No | No | No |
|
|
116
120
|
|
|
117
121
|
`.checkbox` and `.radio` are the only components that read one axis and not the other. Their line is the only thing marking an unchecked box, so it is drawn whatever the edge class says, from a container or from the element itself. `.edgeless` on either is unsupported rather than merely discouraged.
|
|
118
122
|
|
|
119
123
|
Every other text control floors a _cascaded_ `.edgeless` and honours its own: a `.edgeless` toolbar will not erase the line of a field nobody classed, while `.ipt.edgeless` is a consumer describing what they want and gets it.
|
|
120
124
|
|
|
121
|
-
Intent aliases such as `.danger` and `.error` occupy the same intent axis as `.destructive`; they do not add component behavior. State and modifier classes such as `.interactive`, `.hoverable`, `.pressable`, `.
|
|
125
|
+
Intent aliases such as `.danger` and `.error` occupy the same intent axis as `.destructive`; they do not add component behavior. State and modifier classes such as `.interactive`, `.hoverable`, `.pressable`, `.invalid`, `.compact`, and `.vertical` sit above this map and are documented with their component.
|
|
122
126
|
|
|
123
127
|
## Elevation
|
|
124
128
|
|
|
@@ -140,4 +144,4 @@ Each is one unitless multiplier over whatever shadow geometry is in scope, so th
|
|
|
140
144
|
<article class="card elevation-none">Flat, whatever the page or container says</article>
|
|
141
145
|
```
|
|
142
146
|
|
|
143
|
-
The multiplier
|
|
147
|
+
The multiplier does not inherit: an elevation class lifts or flattens the element it is written on only, and an unclassed element inside it takes no depth of its own. Give each element that needs depth its own elevation class. Spread is deliberately left out of the multiplication, because an aesthetic that draws its edge as an inset ring spends spread on it and scaling that would erase the edge.
|
|
@@ -18,6 +18,7 @@ Layout helpers use the shared `--layout-gap` token. `.tight` sets it to `0.5rem`
|
|
|
18
18
|
- `.section` adds responsive block padding and an inline gutter.
|
|
19
19
|
- `.section-content` centers content at `--container-max`; `.narrow` and `.wide` select the corresponding container tokens.
|
|
20
20
|
- `.divider` is horizontal; `.vertical` makes it self-stretch vertically. It takes intent, but presentation classes do not affect it.
|
|
21
|
+
- `.visually-hidden` hides content visually while keeping it in the accessibility tree, using the standard clip-based recipe. Not named `.sr-only`: on a `/tw` entry the consumer's own Tailwind build already ships a real `.sr-only`, and a same-named utility of this package's own would silently collide with it in the cascade — the same reason `.data-table` is not named `.table`.
|
|
21
22
|
|
|
22
23
|
The removed `--layout-stack-gap` and `--layout-cluster-gap` tokens have no compatibility aliases.
|
|
23
24
|
|
|
@@ -105,7 +106,9 @@ This is the one place intent cascades, because a table's rows are parts of the t
|
|
|
105
106
|
|
|
106
107
|
On `.data-table` it removes the header plate along with the body tint, so `.data-table.ghost` is boundaries and type alone. The component rests at `soft`, so that is something to ask for rather than the default.
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
`.soft` rests untinted throughout -- `--color-foreground`, no intent color mixed in, for every intent, including the resting default, on the head plate and the table's own base fill alike. A table has no hover or interaction state to reveal a tint into the way `.card.soft` does on `.interactive`/`.hoverable`, so unlike a card there is no state where a `.data-table.success.soft` reveals green; only the boundary and rule lines still read the intent.
|
|
110
|
+
|
|
111
|
+
On `.kbd`, `.code`, and `.pre` it is **not supported**. All three rest on `--intent-subtle`, and that ground draws the plate whatever the fill says — so `.ghost` took the fill away and changed nothing visible. Worse, the ground alone is a near-page tint: a ghost chip measured the same `#e5e5e5` for neutral and primary on the light page, and `#f5f5f5` at 1.04:1 against it for secondary. A named intent rests at `.soft` instead, which puts a real `12%` of the intent over the ground and separates it from the others; the no-named-intent case reads no differently from `.ghost` either way, so it rests at the ground alone rather than adding an unmotivated wash of its own.
|
|
109
112
|
|
|
110
113
|
Use `.table-wrap` around `.data-table` when table width may exceed its container:
|
|
111
114
|
|
|
@@ -144,15 +147,19 @@ Use `.table-wrap` around `.data-table` when table width may exceed its container
|
|
|
144
147
|
|
|
145
148
|
Both read intent, [presentation](./composing.md#presentation), and [material tokens](./customizing.md#material-tokens). A plain `.card` is a neutral bordered container; only an explicit presentation tints it. Resting at elevation `1` is not a visible shadow by itself — nothing draws depth until an [aesthetic](./aesthetics.md) supplies shadow geometry or `.elevation-sm`/`.elevation-md` asks for it; see [Composing → Elevation](./composing.md#elevation).
|
|
146
149
|
|
|
150
|
+
`.card.soft` with no named intent is untinted at rest — a plain `--color-foreground` plate, no ink mixed in, marking a different container without drawing attention to it. The intent tint and a `--color-surface` ground only appear together, on `:hover`, and only on `.card.interactive`/`.card.hoverable`: a plain `.card.soft` with neither has no hover state to reveal into and stays at the quiet rest. A named intent (`.card.soft.success`, `.card.soft.destructive`, and so on) keeps its ordinary tint at rest instead, and deepens further on hover the same way any other filled surface does — only the no-intent case is untinted, since removing an intent's own color would silence it rather than quiet it. `.solid` and `.ghost` are unaffected either way.
|
|
151
|
+
|
|
152
|
+
`.panel` with no named intent behaves the same way, permanently rather than on hover: a plain `.panel` rests at the same untinted `--color-foreground` plate a neutral `.card.soft` does, because a panel has no hover state to reveal a tint into. `.panel.primary`, `.panel.destructive`, and every other named intent keep their ordinary tint. `.kbd`, `.code`, and `.pre` follow the same no-named-intent rule for their own fill, without moving off their `--intent-subtle` ground.
|
|
153
|
+
|
|
147
154
|
On the base look, `.card.interactive` scales down slightly on press (`--ui-active-transform`, `scale(0.97)`); an [aesthetic](./aesthetics.md) substitutes its own press gesture, and `prefers-reduced-motion` turns it off.
|
|
148
155
|
|
|
149
156
|
`.interactive` is the pair `.hoverable` (hover response only, no pointer cursor) and `.pressable` (press response and pointer cursor) applied together. Take one half for a card that answers a single gesture: a card that warms on hover but holds its own action in a nested button takes `.hoverable`, so pressing that button does not dip the whole card.
|
|
150
157
|
|
|
151
158
|
```html
|
|
152
159
|
<article class="card">Neutral card</article>
|
|
153
|
-
<article class="card success
|
|
160
|
+
<article class="card success solid">Filled success card</article>
|
|
154
161
|
<article class="card primary ghost edged">Intent border, no fill</article>
|
|
155
|
-
<a class="card interactive" href="/package">
|
|
162
|
+
<a class="card success soft interactive" href="/package">Success-tinted at rest; deepens on hover</a>
|
|
156
163
|
<article class="card hoverable">Warms on hover; the action is a nested button</article>
|
|
157
164
|
<aside class="panel">Flush panel</aside>
|
|
158
165
|
```
|
package/docs/usage/feedback.md
CHANGED
|
@@ -9,7 +9,7 @@ order: 7
|
|
|
9
9
|
| Class | Purpose |
|
|
10
10
|
| ---------------- | ---------------------------------------------------------------------------- |
|
|
11
11
|
| `.alert` | Inline feedback surface. |
|
|
12
|
-
| `.icon`
|
|
12
|
+
| `.alert-icon` | Sizing and alignment for an icon element dropped in as a child of `.alert`. |
|
|
13
13
|
| `.badge` | Compact status pill. |
|
|
14
14
|
| `.loader-mask` | Low-level activity indicator composition utility. Applies the spinner mask. |
|
|
15
15
|
| `.loader` | Standalone inline loader artwork. |
|
|
@@ -37,11 +37,11 @@ These variants retain their embedded SVG animations normally. Under `prefers-red
|
|
|
37
37
|
|
|
38
38
|
Loader size modifiers:
|
|
39
39
|
|
|
40
|
-
| Class | Size
|
|
41
|
-
| -------- |
|
|
42
|
-
| _(none)_ | Default (`
|
|
43
|
-
| `.sm` | Small (`1.
|
|
44
|
-
| `.lg` | Large (`2.
|
|
40
|
+
| Class | Size |
|
|
41
|
+
| -------- | -------------------- |
|
|
42
|
+
| _(none)_ | Default (`1.75rem`). |
|
|
43
|
+
| `.sm` | Small (`1.25rem`). |
|
|
44
|
+
| `.lg` | Large (`2.25rem`). |
|
|
45
45
|
|
|
46
46
|
Alerts, badges, progress bars, skeletons, and loaders accept `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, `.danger`, `.error`, and `.info`. Without an intent, they use the text palette, except `.loader`, which keeps `currentColor` so it matches whatever content surrounds it.
|
|
47
47
|
|
|
@@ -51,16 +51,23 @@ Skeletons, loaders, progress bars, and dividers are indicators. They read intent
|
|
|
51
51
|
<span class="loader success" aria-hidden="true"></span> <span class="skeleton info"></span>
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
The package ships no icon of its own: `.alert` is already `flex`, so an icon dropped in as a child is spaced from the message by its `gap-3` with nothing to trigger. `.alert-icon` only sizes and aligns whatever icon element you provide — an inline `<svg>`, an `<img>`, or a class from an icon set such as `@codenhub/icons` — the same contract [`.input-group`](./forms.md#icons) documents.
|
|
55
55
|
|
|
56
|
-
Alerts and badges read the shared [presentation](./composing.md#presentation) classes. Without one they use a tinted surface, intent-colored text, and a mixed intent border.
|
|
56
|
+
Alerts and badges read the shared [presentation](./composing.md#presentation) classes. Without one they use a tinted surface, intent-colored text, and a mixed intent border -- except a neutral `.alert` (no named intent), which rests untinted instead, the same no-named-intent carve-out `.card.soft` and `.panel` use: a plain `--color-foreground` plate rather than 12% of near-black ink over the page. A named intent (`.alert.success`, `.alert.destructive`, and so on) keeps its ordinary tint. `.badge` is unaffected either way -- it has no border to fall back on at rest, so untinting it would make a neutral badge disappear rather than read quieter.
|
|
57
57
|
|
|
58
58
|
## Example
|
|
59
59
|
|
|
60
60
|
```html
|
|
61
61
|
<div class="alert success" role="status">Saved successfully.</div>
|
|
62
62
|
<div class="alert primary solid" role="status">Deployment started.</div>
|
|
63
|
-
<div class="alert warning soft
|
|
63
|
+
<div class="alert warning soft" role="status">
|
|
64
|
+
<svg class="alert-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
|
|
65
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" />
|
|
66
|
+
<path d="M12 9v4" />
|
|
67
|
+
<path d="M12 17h.01" />
|
|
68
|
+
</svg>
|
|
69
|
+
Review required.
|
|
70
|
+
</div>
|
|
64
71
|
<div class="alert destructive ghost edged" role="alert">Deployment failed.</div>
|
|
65
72
|
<span class="badge warning">Queued</span>
|
|
66
73
|
<span class="badge success solid">Live</span>
|
package/docs/usage/forms.md
CHANGED
|
@@ -6,29 +6,29 @@ order: 6
|
|
|
6
6
|
|
|
7
7
|
# Forms
|
|
8
8
|
|
|
9
|
-
| Class or Selector | Purpose
|
|
10
|
-
| --------------------------------------------------------------------- |
|
|
11
|
-
| `.field` | Vertical field wrapper.
|
|
12
|
-
| `.label` | Form label text.
|
|
13
|
-
| `.hint` | Secondary helper text.
|
|
14
|
-
| `.hint.error` | Helper text with destructive intent.
|
|
15
|
-
| `.surface` | Shared public container composition utility.
|
|
16
|
-
| `.text-control` | Shared public text-control composition utility.
|
|
17
|
-
| `.ipt` | Input control styling.
|
|
18
|
-
| `.input-group` | Wrapper that owns the field box so a control can carry
|
|
19
|
-
| `.textarea` | Textarea control styling.
|
|
20
|
-
| `.select` | Select control styling.
|
|
21
|
-
| `input[type="checkbox"].checkbox` | Custom checkbox control styling.
|
|
22
|
-
| `input[type="radio"].radio` | Custom radio control styling.
|
|
23
|
-
| `input[type="checkbox"].switch` | Custom switch control styling.
|
|
24
|
-
| `[aria-invalid="true"]` on controls | Destructive border and focus color.
|
|
25
|
-
| `[disabled]`, `[aria-disabled="true"]`, `[data-disabled]` on controls | Disabled styling.
|
|
9
|
+
| Class or Selector | Purpose |
|
|
10
|
+
| --------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
11
|
+
| `.field` | Vertical field wrapper. |
|
|
12
|
+
| `.label` | Form label text. |
|
|
13
|
+
| `.hint` | Secondary helper text. |
|
|
14
|
+
| `.hint.error` | Helper text with destructive intent. |
|
|
15
|
+
| `.surface` | Shared public container composition utility. |
|
|
16
|
+
| `.text-control` | Shared public text-control composition utility. |
|
|
17
|
+
| `.ipt` | Input control styling. |
|
|
18
|
+
| `.input-group` | Wrapper that owns the field box so a control can carry an icon or affix. |
|
|
19
|
+
| `.textarea` | Textarea control styling. |
|
|
20
|
+
| `.select` | Select control styling. |
|
|
21
|
+
| `input[type="checkbox"].checkbox` | Custom checkbox control styling. |
|
|
22
|
+
| `input[type="radio"].radio` | Custom radio control styling. |
|
|
23
|
+
| `input[type="checkbox"].switch` | Custom switch control styling. |
|
|
24
|
+
| `[aria-invalid="true"]` on controls | Destructive border and focus color. |
|
|
25
|
+
| `[disabled]`, `[aria-disabled="true"]`, `[data-disabled]` on controls | Disabled styling. |
|
|
26
26
|
|
|
27
27
|
## Icons
|
|
28
28
|
|
|
29
29
|
No icon is shipped for text inputs — that's what this section covers. It used to paint one per input type as a `background-image` — a `data:` URI, which cannot read `currentColor` or a custom property, so every glyph shipped a light and a dark copy and a theme selector chose between them. That put icon artwork, and the package's only theme-by-selector branch, inside a CSS-only design system whose glyphs did not fit every aesthetic. Icons for `.input-group` are the consumer's to choose now.
|
|
30
30
|
|
|
31
|
-
This is separate from the toggle marks below
|
|
31
|
+
This is separate from the toggle marks below, which stay small, fixed, built-in glyphs. `.alert`'s icon followed the same path since — see [Feedback → Icon](./feedback.md#example) — the package no longer paints one there either.
|
|
32
32
|
|
|
33
33
|
`.input-group` is the wrapper for a control that carries one. It owns the field box — border, radius, fill, focus ring, invalid and disabled state — and the control inside it goes flush, so the boundary is drawn once. Any icon element works, placed before the control for a leading icon or after it for a trailing one: an inline `<svg>`, an `<img>`, or a class from an icon set such as `@codenhub/icons`.
|
|
34
34
|
|
|
@@ -56,6 +56,17 @@ The group reads intent and both [presentation](./composing.md#presentation) axes
|
|
|
56
56
|
|
|
57
57
|
Non-icon input types keep the browser's native `date` and `datetime-local` pickers. WebKit's native `search` decorations are still suppressed on `.text-control` to keep them from overlapping the value.
|
|
58
58
|
|
|
59
|
+
The slot works the same way for a text affix — a URL host, a currency symbol, a unit — not just an icon:
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<div class="input-group">
|
|
63
|
+
<span>example.com/</span>
|
|
64
|
+
<input class="ipt" type="text" />
|
|
65
|
+
</div>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The gap between the control and its adornment is `--input-group-gap`, `0.5rem` by default: the right amount of breathing room for a distinct icon glyph, and too much for text meant to read as glued to the value — `example.com/` followed by a gap reads as a stray space breaking the path apart. Set `--input-group-gap: 0` on the group for a flush affix; icon compositions keep the default unchanged.
|
|
69
|
+
|
|
59
70
|
## Toggles
|
|
60
71
|
|
|
61
72
|
`.checkbox`, `.radio`, and `.switch` accept the same intent classes as buttons to set the checked color:
|
|
@@ -70,16 +81,15 @@ Non-icon input types keep the browser's native `date` and `datetime-local` picke
|
|
|
70
81
|
| `.destructive`, `.danger`, `.error` | Destructive color. |
|
|
71
82
|
| `.info` | Info color. |
|
|
72
83
|
|
|
73
|
-
All three toggles rest at `.
|
|
74
|
-
|
|
75
|
-
Presentation decides the fill in both states. Being checked lifts the cap rather than pinning a fill, so the class still chooses:
|
|
84
|
+
All three toggles rest at `.soft`. Presentation decides the _unchecked_ plate; checked is pinned to one look regardless of which class is on the element, so a checkbox, a radio, and a switch each have a single "on" identity rather than one per presentation:
|
|
76
85
|
|
|
77
|
-
| Toggle
|
|
78
|
-
|
|
|
79
|
-
| `.
|
|
80
|
-
| `.soft
|
|
86
|
+
| Toggle | unchecked | checked |
|
|
87
|
+
| ---------------- | --------- | ---------------------------------------- |
|
|
88
|
+
| `.ghost` | 0% | 100%, mark in the contrast tone (pinned) |
|
|
89
|
+
| `.soft`, default | 12% | 100%, mark in the contrast tone (pinned) |
|
|
90
|
+
| `.solid` | 40% | 100%, mark in the contrast tone (pinned) |
|
|
81
91
|
|
|
82
|
-
A checked checkbox and a checked switch cut their mark out of that plate. A checked radio thickens its ring to twice the resting line and takes the intent whole on it,
|
|
92
|
+
A checked checkbox and a checked switch cut their mark out of that pinned plate. A checked radio thickens its ring to twice the resting line and takes the intent whole on it, and the dot follows the same pinned plate, so `.radio.soft` and `.radio.solid` render the same filled circle once checked — presentation only changes what the radio looks like before it's picked.
|
|
83
93
|
|
|
84
94
|
## Text controls
|
|
85
95
|
|
package/docs/usage/tooltips.md
CHANGED
|
@@ -1,39 +1,65 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Tooltips
|
|
3
|
-
description: Tooltip
|
|
3
|
+
description: Tooltip composition classes and positioning attributes.
|
|
4
4
|
order: 8
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Tooltips
|
|
8
8
|
|
|
9
|
-
| Class or Attribute
|
|
10
|
-
|
|
|
11
|
-
| `.tooltip`
|
|
12
|
-
| `.tooltip
|
|
13
|
-
|
|
|
14
|
-
| `[data-tooltip-position="
|
|
15
|
-
| `[data-tooltip-position="
|
|
16
|
-
| `[data-tooltip-position="
|
|
17
|
-
|
|
|
18
|
-
| `
|
|
19
|
-
|
|
|
9
|
+
| Class or Attribute | Purpose |
|
|
10
|
+
| -------------------------------------- | ------------------------------------------------------------------------ |
|
|
11
|
+
| `.tooltip` | Wrapper around a trigger and a bubble. Paints nothing itself. |
|
|
12
|
+
| `.tooltip-bubble` | The message. A real element, styled like any other surface. |
|
|
13
|
+
| `.tooltip-icon` | Circular icon-style trigger, for a message with nothing else to hang on. |
|
|
14
|
+
| `[data-tooltip-position="top"]` | Positions the bubble above the trigger, on `.tooltip`. |
|
|
15
|
+
| `[data-tooltip-position="bottom"]` | Positions the bubble below the trigger, on `.tooltip`. |
|
|
16
|
+
| `[data-tooltip-position="left"]` | Positions the bubble left of the trigger, on `.tooltip`. |
|
|
17
|
+
| `[data-tooltip-position="right"]` | Positions the bubble right of the trigger, on `.tooltip`. |
|
|
18
|
+
| No `data-tooltip-position` | Defaults to top placement. |
|
|
19
|
+
| `[data-state="open"]` | Shows the bubble without hover, on `.tooltip`. |
|
|
20
|
+
| `.tooltip-bubble.raised` / `.floating` | Adds one or two units of depth. The bubble is flat by default. |
|
|
20
21
|
|
|
21
|
-
A tooltip
|
|
22
|
+
A tooltip is composition, not a single class: `.tooltip` wraps a trigger element and a `.tooltip-bubble`, and shows the bubble on hover or focus within the wrapper. This replaced a `::after` pseudo-element that carried the message as `content: attr(data-tooltip)` — CSS generated content is not reliably exposed to assistive tech, and cannot be the target of an `aria-describedby`, since that needs a real element with a real `id`. A real bubble can be. Wire the association yourself: give the bubble an `id`, give the trigger `aria-describedby` pointing at it, and put `role="tooltip"` on the bubble.
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
A tooltip bubble's fill, ground color, and floor behavior are covered in [Composing → Presentation](./composing.md#presentation), and its material follows whichever [aesthetic](./aesthetics.md) is in scope. Intent, presentation, aesthetic, and elevation classes go on `.tooltip-bubble` — the element that actually paints — not on `.tooltip`, the same rule every component in this package follows: put the class on the element that shows it.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
The bubble rests flat. It draws no shadow of its own on a plain page, and zeroes an aesthetic's part-based depth (such as `.neobrutalism`'s slab) the same way `.flat` does elsewhere. Add [`.raised` or `.floating`](./composing.md#elevation) to lift it, on the bubble itself — `.tooltip-bubble.floating` is the pre-0.1.0 look. An aesthetic whose shadow is a complete value, like `.glass`, still reaches the bubble as it reaches any surface.
|
|
27
|
+
|
|
28
|
+
Intent works on a tooltip bubble the same way it works on a filled component: `.tooltip-bubble.primary` fills the bubble with the primary color, black text on a light page and white on a dark one; `.tooltip-bubble.destructive` is a red bubble with the same logic. With no intent, the bubble uses `--color-tooltip`, a plate chosen per theme rather than derived from an intent; see [Composing → Presentation](./composing.md#presentation) for why.
|
|
26
29
|
|
|
27
30
|
## Example
|
|
28
31
|
|
|
29
32
|
```html
|
|
30
|
-
<
|
|
31
|
-
<button
|
|
32
|
-
<
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
<span class="tooltip">
|
|
34
|
+
<button aria-describedby="status-bubble">Status</button>
|
|
35
|
+
<span class="tooltip-bubble" role="tooltip" id="status-bubble">Saved 2 minutes ago</span>
|
|
36
|
+
</span>
|
|
37
|
+
|
|
38
|
+
<span class="tooltip" data-tooltip-position="bottom">
|
|
39
|
+
<button aria-describedby="docs-bubble">Docs</button>
|
|
40
|
+
<span class="tooltip-bubble" role="tooltip" id="docs-bubble">Opens in a new tab</span>
|
|
41
|
+
</span>
|
|
42
|
+
|
|
43
|
+
<span class="tooltip">
|
|
44
|
+
<button class="btn primary" aria-describedby="deploy-bubble">Deploy</button>
|
|
45
|
+
<span class="tooltip-bubble raised primary" role="tooltip" id="deploy-bubble">Primary intent, lifted a step</span>
|
|
46
|
+
</span>
|
|
47
|
+
|
|
48
|
+
<span class="tooltip" data-state="open">
|
|
49
|
+
<span aria-describedby="pinned-bubble">Pinned</span>
|
|
50
|
+
<span class="tooltip-bubble" role="tooltip" id="pinned-bubble">Always visible, no hover needed</span>
|
|
51
|
+
</span>
|
|
52
|
+
|
|
53
|
+
<span class="tooltip" data-tooltip-position="right">
|
|
54
|
+
<span class="tooltip-icon" tabindex="0" aria-label="More details" aria-describedby="icon-bubble">?</span>
|
|
55
|
+
<span class="tooltip-bubble" role="tooltip" id="icon-bubble">More details</span>
|
|
56
|
+
</span>
|
|
35
57
|
```
|
|
36
58
|
|
|
37
|
-
The first two show plain
|
|
59
|
+
The first two show plain triggers with default (top) and explicit bottom placement. The third combines an intent with `.raised` on the bubble to show they compose freely — the intent decides the bubble's fill, `.raised` decides whether it casts depth. The fourth uses `data-state="open"` on the wrapper to keep a tooltip visible without a hover or focus interaction, useful for a tooltip that should be demonstrated or tested without simulating pointer input. The fifth uses `.tooltip-icon` as the trigger, for a message with no other element to hang it on.
|
|
60
|
+
|
|
61
|
+
`.tooltip` composes with any trigger: wrap an existing `.btn` or `.badge` in it and both keep their own look, gaining a bubble beside them. `.tooltip-icon` is only the circular chip for the case where there is nothing else to be the trigger.
|
|
62
|
+
|
|
63
|
+
Showing and hiding the bubble is CSS-only — `:hover` and `:focus-within` on `.tooltip` — but that is presentational. It is not a complete accessible tooltip implementation by itself: provide the `id`/`aria-describedby`/`role="tooltip"` association outside the CSS; see [Accessibility](../accessibility.md).
|
|
38
64
|
|
|
39
|
-
|
|
65
|
+
Next: [Content and layout](./content-and-layout.md) covers layout helpers, content chips and tables, surfaces, and typography utilities.
|