@ropav/styles 0.3.0 → 0.5.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 +160 -19
- package/dist/components/accordion.css +12 -5
- package/dist/components/alert-dialog.css +1 -1
- package/dist/components/alert.css +9 -1
- package/dist/components/autocomplete/autocomplete.styles.d.ts +33 -0
- package/dist/components/autocomplete/autocomplete.styles.d.ts.map +1 -1
- package/dist/components/autocomplete/autocomplete.styles.js +12 -0
- package/dist/components/autocomplete.css +39 -3
- package/dist/components/avatar.css +9 -0
- package/dist/components/badge.css +7 -0
- package/dist/components/button-group.css +6 -6
- package/dist/components/button.css +34 -11
- package/dist/components/calendar-year-picker.css +2 -1
- package/dist/components/calendar.css +8 -0
- package/dist/components/card.css +22 -1
- package/dist/components/chip.css +21 -0
- package/dist/components/close-button.css +8 -0
- package/dist/components/color-input-group/color-input-group.styles.d.ts +27 -0
- package/dist/components/color-input-group/color-input-group.styles.d.ts.map +1 -1
- package/dist/components/color-input-group/color-input-group.styles.js +6 -0
- package/dist/components/color-input-group.css +30 -1
- package/dist/components/color-swatch-picker.css +11 -0
- package/dist/components/combo-box/combo-box.styles.d.ts +27 -0
- package/dist/components/combo-box/combo-box.styles.d.ts.map +1 -1
- package/dist/components/combo-box/combo-box.styles.js +17 -7
- package/dist/components/combo-box.css +21 -1
- package/dist/components/date-input-group/date-input-group.styles.d.ts +27 -0
- package/dist/components/date-input-group/date-input-group.styles.d.ts.map +1 -1
- package/dist/components/date-input-group/date-input-group.styles.js +6 -0
- package/dist/components/date-input-group.css +30 -1
- package/dist/components/dropdown/dropdown.styles.d.ts.map +1 -1
- package/dist/components/dropdown/dropdown.styles.js +1 -1
- package/dist/components/dropdown.css +17 -12
- package/dist/components/index.css +4 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/input/input.styles.d.ts +15 -0
- package/dist/components/input/input.styles.d.ts.map +1 -1
- package/dist/components/input/input.styles.js +6 -0
- package/dist/components/input-group/input-group.styles.d.ts +27 -0
- package/dist/components/input-group/input-group.styles.d.ts.map +1 -1
- package/dist/components/input-group/input-group.styles.js +6 -0
- package/dist/components/input-group.css +32 -1
- package/dist/components/input.css +23 -1
- package/dist/components/list-box/list-box.styles.d.ts +15 -0
- package/dist/components/list-box/list-box.styles.d.ts.map +1 -1
- package/dist/components/list-box/list-box.styles.js +15 -5
- package/dist/components/list-box-item.css +4 -2
- package/dist/components/list-box.css +19 -0
- package/dist/components/menu/menu.styles.d.ts +19 -1
- package/dist/components/menu/menu.styles.d.ts.map +1 -1
- package/dist/components/menu/menu.styles.js +9 -1
- package/dist/components/menu.css +25 -0
- package/dist/components/meter.css +12 -0
- package/dist/components/modal.css +1 -1
- package/dist/components/number-field/number-field.styles.d.ts +27 -0
- package/dist/components/number-field/number-field.styles.d.ts.map +1 -1
- package/dist/components/number-field/number-field.styles.js +6 -0
- package/dist/components/number-field.css +68 -1
- package/dist/components/pagination.css +10 -6
- package/dist/components/popover.css +15 -1
- package/dist/components/progress-bar.css +12 -0
- package/dist/components/progress-circle.css +12 -0
- package/dist/components/radio.css +7 -0
- package/dist/components/range-calendar.css +28 -0
- package/dist/components/search-field/search-field.styles.d.ts +27 -0
- package/dist/components/search-field/search-field.styles.d.ts.map +1 -1
- package/dist/components/search-field/search-field.styles.js +6 -0
- package/dist/components/search-field.css +33 -1
- package/dist/components/segmented-control/index.d.ts +2 -0
- package/dist/components/segmented-control/index.d.ts.map +1 -0
- package/dist/components/segmented-control/index.js +2 -0
- package/dist/components/segmented-control/segmented-control.styles.d.ts +73 -0
- package/dist/components/segmented-control/segmented-control.styles.d.ts.map +1 -0
- package/dist/components/segmented-control/segmented-control.styles.js +27 -0
- package/dist/components/segmented-control.css +193 -0
- package/dist/components/select/select.styles.d.ts +33 -0
- package/dist/components/select/select.styles.d.ts.map +1 -1
- package/dist/components/select/select.styles.js +12 -0
- package/dist/components/select.css +40 -3
- package/dist/components/separator.css +18 -1
- package/dist/components/sidebar/index.d.ts +2 -0
- package/dist/components/sidebar/index.d.ts.map +1 -0
- package/dist/components/sidebar/index.js +2 -0
- package/dist/components/sidebar/sidebar.styles.d.ts +190 -0
- package/dist/components/sidebar/sidebar.styles.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar.styles.js +52 -0
- package/dist/components/sidebar.css +510 -0
- package/dist/components/skeleton.css +9 -0
- package/dist/components/slider.css +61 -0
- package/dist/components/splitter/index.d.ts +2 -0
- package/dist/components/splitter/index.d.ts.map +1 -0
- package/dist/components/splitter/index.js +2 -0
- package/dist/components/splitter/splitter.styles.d.ts +61 -0
- package/dist/components/splitter/splitter.styles.d.ts.map +1 -0
- package/dist/components/splitter/splitter.styles.js +26 -0
- package/dist/components/splitter.css +241 -0
- package/dist/components/surface.css +24 -0
- package/dist/components/switch.css +30 -0
- package/dist/components/table.css +11 -3
- package/dist/components/tabs.css +30 -2
- package/dist/components/tag.css +10 -0
- package/dist/components/textarea/textarea.styles.d.ts +15 -0
- package/dist/components/textarea/textarea.styles.d.ts.map +1 -1
- package/dist/components/textarea/textarea.styles.js +6 -0
- package/dist/components/textarea.css +23 -1
- package/dist/components/toast.css +1 -1
- package/dist/components/toggle-button-group.css +7 -7
- package/dist/components/toggle-button.css +17 -11
- package/dist/components/toolbar.css +8 -1
- package/dist/components/tooltip.css +15 -2
- package/dist/components/typography.css +21 -0
- package/dist/components/virtualizer/index.d.ts +2 -0
- package/dist/components/virtualizer/index.d.ts.map +1 -0
- package/dist/components/virtualizer/index.js +2 -0
- package/dist/components/virtualizer/virtualizer.styles.d.ts +44 -0
- package/dist/components/virtualizer/virtualizer.styles.d.ts.map +1 -0
- package/dist/components/virtualizer/virtualizer.styles.js +15 -0
- package/dist/components/virtualizer.css +64 -0
- package/dist/index.css +7 -2
- package/dist/index.js +5 -1
- package/dist/ropav.min.css +2 -2
- package/dist/themes/airbnb.css +231 -0
- package/dist/themes/all.css +17 -0
- package/dist/themes/coinbase.css +231 -0
- package/dist/themes/{default/variables.css → default.css} +28 -9
- package/dist/themes/discord.css +231 -0
- package/dist/themes/hero.css +262 -0
- package/dist/themes/lavender.css +231 -0
- package/dist/themes/mint.css +231 -0
- package/dist/themes/netflix.css +231 -0
- package/dist/themes/rabbit.css +231 -0
- package/dist/themes/shared/theme.css +19 -2
- package/dist/themes/sky.css +231 -0
- package/dist/themes/spotify.css +231 -0
- package/dist/themes/uber.css +231 -0
- package/dist/utilities/index.css +97 -0
- package/dist/variants/index.css +5 -15
- package/package.json +2 -3
- package/src/components/autocomplete/autocomplete.styles.ts +12 -0
- package/src/components/color-input-group/color-input-group.styles.ts +10 -0
- package/src/components/combo-box/combo-box.styles.ts +12 -0
- package/src/components/date-input-group/date-input-group.styles.ts +10 -0
- package/src/components/dropdown/dropdown.styles.ts +3 -1
- package/src/components/index.ts +4 -0
- package/src/components/input/input.styles.ts +6 -0
- package/src/components/input-group/input-group.styles.ts +10 -0
- package/src/components/list-box/list-box.styles.ts +6 -0
- package/src/components/menu/menu.styles.ts +10 -0
- package/src/components/number-field/number-field.styles.ts +10 -0
- package/src/components/search-field/search-field.styles.ts +10 -0
- package/src/components/segmented-control/index.ts +1 -0
- package/src/components/segmented-control/segmented-control.styles.ts +37 -0
- package/src/components/select/select.styles.ts +12 -0
- package/src/components/sidebar/index.ts +1 -0
- package/src/components/sidebar/sidebar.styles.ts +94 -0
- package/src/components/splitter/index.ts +1 -0
- package/src/components/splitter/splitter.styles.ts +44 -0
- package/src/components/textarea/textarea.styles.ts +6 -0
- package/src/components/virtualizer/index.ts +1 -0
- package/src/components/virtualizer/virtualizer.styles.ts +15 -0
- package/dist/themes/default/components/index.css +0 -6
- package/dist/themes/default/index.css +0 -8
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ That single line pulls in, in layer order (`theme, base, components, utilities`)
|
|
|
35
35
|
- Tailwind CSS v4 and `tw-animate-css`
|
|
36
36
|
- base styles and the scrollbar system
|
|
37
37
|
- the component layer — 85 files, one per component
|
|
38
|
-
- the default theme:
|
|
38
|
+
- the default theme: tokens for light and dark
|
|
39
39
|
- utilities and custom variants
|
|
40
40
|
|
|
41
41
|
### Importing only what you need
|
|
@@ -45,11 +45,12 @@ That single line pulls in, in layer order (`theme, base, components, utilities`)
|
|
|
45
45
|
|
|
46
46
|
@import "@ropav/styles/components/button.css" layer(components);
|
|
47
47
|
@import "@ropav/styles/components/chip.css" layer(components);
|
|
48
|
-
@import "@ropav/styles/themes/
|
|
48
|
+
@import "@ropav/styles/themes/shared/theme.css";
|
|
49
|
+
@import "@ropav/styles/themes/default";
|
|
49
50
|
```
|
|
50
51
|
|
|
51
|
-
> The granular subpaths — `./components/*.css`, `./base`, `./base/*.css`, `./themes/*`, `./
|
|
52
|
-
> `./variants` — exist **only in the published tarball**; `clean-package.config.json` writes them into
|
|
52
|
+
> The granular subpaths — `./components/*.css`, `./base`, `./base/*.css`, `./themes/*`, `./themes/*.css`,
|
|
53
|
+
> `./utilities`, `./variants` — exist **only in the published tarball**; `clean-package.config.json` writes them into
|
|
53
54
|
> `exports` at `prepack` time. Inside the workspace, import the files from `packages/styles/` by relative path
|
|
54
55
|
> instead.
|
|
55
56
|
|
|
@@ -74,14 +75,14 @@ packages/styles/
|
|
|
74
75
|
│ └── scrollbar.css # Scrollbar system
|
|
75
76
|
├── components/ # 85 CSS files, one per component
|
|
76
77
|
├── themes/
|
|
77
|
-
│ ├── default
|
|
78
|
-
│
|
|
79
|
-
│
|
|
80
|
-
│ │ └── components/ # Per-component theme overrides
|
|
78
|
+
│ ├── default.css # Default theme — hand-written, light and dark token sets
|
|
79
|
+
│ ├── sky.css … rabbit.css # Ten more themes — generated, do not edit
|
|
80
|
+
│ ├── all.css # Every bundled theme, for docs and playgrounds
|
|
81
81
|
│ └── shared/
|
|
82
82
|
│ └── theme.css # @theme block — derived values, radius scale, easing curves
|
|
83
83
|
├── utilities/index.css # Tailwind v4 @utility definitions
|
|
84
84
|
├── variants/index.css # Tailwind v4 @custom-variant definitions
|
|
85
|
+
├── scripts/themes/ # Build-time theme generator — not published
|
|
85
86
|
└── src/ # TypeScript: tv() variants + shared utility class strings
|
|
86
87
|
```
|
|
87
88
|
|
|
@@ -113,31 +114,171 @@ component that publishes it as an attribute.
|
|
|
113
114
|
|
|
114
115
|
## Theming
|
|
115
116
|
|
|
116
|
-
|
|
117
|
+
Two independent axes. `data-theme` picks the palette, a `light`/`dark` class picks the appearance:
|
|
117
118
|
|
|
118
119
|
```html
|
|
119
|
-
<html data-theme="dark"></html>
|
|
120
|
+
<html data-theme="netflix" class="dark"></html>
|
|
120
121
|
```
|
|
121
122
|
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
Either can be left out. With no `data-theme` you get the default theme; with no class you get light.
|
|
124
|
+
The default theme also answers to `[data-theme="light"]` and `[data-theme="dark"]`, which is what it
|
|
125
|
+
did before the other themes existed.
|
|
126
|
+
|
|
127
|
+
### Bundled themes
|
|
128
|
+
|
|
129
|
+
The default one, plus a theme per brand ported from HeroUI's gallery — `hero` among them, being
|
|
130
|
+
HeroUI's own palette. The default is already in `@ropav/styles`; the others are opt-in, one file
|
|
131
|
+
each:
|
|
132
|
+
|
|
133
|
+
```css
|
|
134
|
+
@import "@ropav/styles";
|
|
135
|
+
@import "@ropav/styles/themes/netflix";
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
| `data-theme` | | `data-theme` | | `data-theme` |
|
|
139
|
+
| --- | --- | --- | --- | --- |
|
|
140
|
+
| `default` | | `mint` | | `coinbase` |
|
|
141
|
+
| `hero` | | `netflix` | | `airbnb` |
|
|
142
|
+
| `sky` | | `uber` | | `discord` |
|
|
143
|
+
| `lavender` | | `spotify` | | `rabbit` |
|
|
144
|
+
|
|
145
|
+
Each carries both a light and a dark palette, so a theme is a brand rather than an appearance. There is
|
|
146
|
+
no `netflix-dark` — it is `data-theme="netflix"` plus `class="dark"`.
|
|
147
|
+
|
|
148
|
+
`themes/all.css` pulls in all of them at once. That is for docs and playgrounds; an app should import
|
|
149
|
+
only the themes it actually offers, since each is around 10 kB before compression.
|
|
150
|
+
|
|
151
|
+
Every theme but `default` and `hero` is **generated** — edit `scripts/themes/presets.ts` and run
|
|
152
|
+
`pnpm generate:themes`, never the CSS. A preset is four numbers (accent lightness, chroma and hue, plus
|
|
153
|
+
the chroma of the neutral ramp), a radius pair, and any exact brand colours that should beat the
|
|
154
|
+
calculated ones.
|
|
155
|
+
|
|
156
|
+
Those two stay hand-written, each file's header saying what the generator cannot reproduce about it.
|
|
157
|
+
Their presets carry the label and the presentation order; the CSS is the source of truth for their
|
|
158
|
+
tokens.
|
|
159
|
+
|
|
160
|
+
### Retheming
|
|
161
|
+
|
|
162
|
+
Every token is a CSS custom property, so overriding them in your own stylesheet is enough — no rebuild
|
|
163
|
+
of this package, and no need to go through a theme file at all:
|
|
124
164
|
|
|
125
165
|
```css
|
|
126
166
|
:root {
|
|
127
167
|
--accent: oklch(0.62 0.19 253.83);
|
|
128
168
|
--radius: 0.5rem;
|
|
129
|
-
--field-radius: calc(var(--radius) * 1.5);
|
|
130
169
|
}
|
|
131
170
|
```
|
|
132
171
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
172
|
+
Author CSS outside a cascade layer outranks everything here, so these win wherever you put them.
|
|
173
|
+
|
|
174
|
+
To add a theme rather than change the default one, write the same token block under your own attribute.
|
|
175
|
+
It has to redeclare the *derived* tokens too, not just the authored ones: a custom property substitutes
|
|
176
|
+
`var()` where it is declared, so an `--accent-hover` inherited from `:root` would still be mixed from
|
|
177
|
+
the root's `--accent`. Copy a generated theme and edit it, or generate one.
|
|
178
|
+
|
|
179
|
+
```css
|
|
180
|
+
@layer theme {
|
|
181
|
+
[data-theme="ocean"] {
|
|
182
|
+
color-scheme: light;
|
|
183
|
+
--accent: oklch(0.62 0.14 220);
|
|
184
|
+
--accent-hover: color-mix(in oklab, var(--accent) 90%, var(--accent-foreground) 10%);
|
|
185
|
+
/* … */
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
A theme only needs to carry colours. Everything keyed on neither the palette nor the appearance —
|
|
191
|
+
`--spacing`, `--cursor-*`, the primitives, the shadows, `--backdrop` — stays on `:root` and `.dark` in
|
|
192
|
+
`themes/default.css`, both of which keep matching an element that carries a `data-theme`.
|
|
193
|
+
|
|
194
|
+
### Tokens
|
|
137
195
|
|
|
138
|
-
|
|
196
|
+
Base colors (`--background`, `--surface`, `--overlay`, `--muted`), interactive and status colors
|
|
197
|
+
(`--accent`, `--success`, `--warning`, `--danger`, each with a `-foreground` and a derived `-hover` and
|
|
198
|
+
`-soft`), form fields (`--field-background`, `--field-border`, `--field-radius`, …), layout knobs
|
|
199
|
+
(`--spacing`, `--border-width`, `--radius`, `--ring-offset-width`, `--cursor-interactive`), the
|
|
200
|
+
scrollbar set, and shadows.
|
|
201
|
+
|
|
202
|
+
**`themes/default.css` is the source of truth — read it rather than a list in a README**, which goes
|
|
139
203
|
stale the moment a token moves. `themes/shared/theme.css` holds what is derived from those tokens: the
|
|
140
|
-
`--radius-xs` … `--radius-4xl` scale
|
|
204
|
+
`--radius-xs` … `--radius-4xl` scale and the easing curves.
|
|
205
|
+
|
|
206
|
+
### Reduced motion
|
|
207
|
+
|
|
208
|
+
`data-reduce-motion="true"` on any ancestor forces animations off, `"false"` forces them on regardless
|
|
209
|
+
of the OS setting, and with neither the `prefers-reduced-motion` media query decides. Defined as the
|
|
210
|
+
`motion-reduce` / `motion-safe` variants in `variants/index.css`.
|
|
211
|
+
|
|
212
|
+
### Forced colors
|
|
213
|
+
|
|
214
|
+
Forced Colors Mode - Windows High Contrast - replaces author colours with the user's own palette and
|
|
215
|
+
strips `box-shadow` outright. That second part is what makes it more than a colour question here:
|
|
216
|
+
every ring in this library *is* a `box-shadow`, because that is what `ring-*` compiles to, and it sits
|
|
217
|
+
on top of `outline-none`. Left alone, a focused control would have no indicator at all.
|
|
218
|
+
|
|
219
|
+
Nothing to opt into. The three focus utilities - `focus-ring`, `focus-field-ring`,
|
|
220
|
+
`invalid-field-ring` - draw an outline back in `Highlight` under `forced-colors: active`, so any
|
|
221
|
+
component that goes through `status-focused`, `status-focused-field` or `status-invalid-field` is
|
|
222
|
+
covered without a line of its own. `status-disabled` picks up `GrayText` the same way.
|
|
223
|
+
|
|
224
|
+
The other half is state carried only by `background-color`, which the override flattens into its
|
|
225
|
+
surroundings. Where selection is *just* a background - a tag, a calendar day, a table row - apply
|
|
226
|
+
`forced-selected`, **as an `@apply` statement of its own**:
|
|
227
|
+
|
|
228
|
+
```css
|
|
229
|
+
.thing[data-selected="true"] {
|
|
230
|
+
@apply bg-accent text-accent-foreground;
|
|
231
|
+
@apply forced-selected;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Folded into the line above it, Tailwind sorts the list and hoists the nested media query over the
|
|
236
|
+
plain declarations, and the `background-color` it exists to override wins instead. Where selection
|
|
237
|
+
also moves a thumb or shows a glyph, the component writes its own `forced-colors` block, because
|
|
238
|
+
those parts need colours of their own - see `switch.css`, `radio.css`, `tabs.css`, `range-calendar.css`,
|
|
239
|
+
`slider.css` and `skeleton.css`.
|
|
240
|
+
|
|
241
|
+
Use the system colour keywords, not tokens: `Highlight` / `HighlightText` for a selected control,
|
|
242
|
+
`CanvasText` on `Canvas` for ordinary content, `ButtonBorder` for a control's edge, `GrayText` for
|
|
243
|
+
disabled. They are the only colours exempt from the override.
|
|
244
|
+
|
|
245
|
+
Watch for `transparent` used as a spacer. Forced colors preserves a transparent *background*, but a
|
|
246
|
+
transparent `border-color` is turned **opaque** - so a border held open purely to reserve layout space
|
|
247
|
+
(`slider.css` does this at both ends of the track) stops being invisible and renders as a solid block.
|
|
248
|
+
Restate those as `Canvas` inside the media query.
|
|
249
|
+
|
|
250
|
+
One trap, and `getComputedStyle` cannot see it. Chromium paints a `Canvas`-coloured **backplate**
|
|
251
|
+
behind the text of any element that has text, so that text over an image stays legible. It lands on
|
|
252
|
+
top of that element's own background, so a `Highlight` fill carrying `HighlightText` renders as a
|
|
253
|
+
solid plate with the label invisible inside it - the colours are all correct and the component is
|
|
254
|
+
unreadable. `forced-color-adjust: none` is what suppresses the backplate. `forced-selected` already
|
|
255
|
+
carries it; anything hand-rolling the same pairing needs it too, including the case where the fill
|
|
256
|
+
sits on a different element than the text (`tabs.css`, `range-calendar.css`). Reach for it only
|
|
257
|
+
alongside explicit system colours - on its own it just hands the author's palette back, which is the
|
|
258
|
+
opposite of the point.
|
|
259
|
+
|
|
260
|
+
Structure has to survive the mode as well as state. A component that is only a tinted fill and a
|
|
261
|
+
shadow - a card, an alert, a text field, a chip - renders as loose text once both are taken, which
|
|
262
|
+
reads as no component at all. So every container carries an inset `CanvasText` outline under the
|
|
263
|
+
mode and every control a `ButtonBorder` one, on the variants that actually paint; a transparent
|
|
264
|
+
surface is left alone, since framing it would invent a box that was never there. A separator is the
|
|
265
|
+
exception that proves it: the whole thing *is* its background, so it takes a colour rather than an
|
|
266
|
+
edge.
|
|
267
|
+
|
|
268
|
+
Two things guard it. `forced-colors.browser.test.ts` in the `ropav` package asserts the stylesheet
|
|
269
|
+
directly, and the Storybook package runs **every story** through an audit that renders it twice - the
|
|
270
|
+
mode off, then on over CDP - and fails on anything that painted something and stops painting it. The
|
|
271
|
+
second one exists because the first cannot see this class of bug on its own: the colour override runs
|
|
272
|
+
after the cascade and the backplate is painted later still, so a component reports every declared
|
|
273
|
+
colour correctly while rendering as a blank block. Three bugs shipped that way before the audit
|
|
274
|
+
existed.
|
|
275
|
+
|
|
276
|
+
To look at it by hand, use Chromium's rendering panel - DevTools, `Cmd+Shift+P`, "Show Rendering",
|
|
277
|
+
then *Emulate CSS media feature forced-colors* - and note that **macOS has no Forced Colors Mode at
|
|
278
|
+
all**: "Increase contrast" maps to `prefers-contrast: more`, so switching it on tests nothing. There
|
|
279
|
+
is deliberately no toolbar control in Storybook. `data-reduce-motion` is an attribute a decorator can
|
|
280
|
+
set, but this is a browser-level media feature an iframe cannot turn on for itself, and faking it with
|
|
281
|
+
a stylesheet of system colours would miss the `box-shadow` removal - the part that actually breaks.
|
|
141
282
|
|
|
142
283
|
## Build
|
|
143
284
|
|
|
@@ -116,7 +116,14 @@
|
|
|
116
116
|
/* Surface variant */
|
|
117
117
|
.accordion--surface {
|
|
118
118
|
@apply bg-surface;
|
|
119
|
-
border-radius: min(32px, var(--radius
|
|
119
|
+
border-radius: min(32px, var(--component-radius));
|
|
120
|
+
|
|
121
|
+
/* Forced Colors Mode flattens the fill onto the page and strips the shadow, so the container
|
|
122
|
+
* stops having any shape and its contents sit loose on the page. */
|
|
123
|
+
@media (forced-colors: active) {
|
|
124
|
+
outline: 1px solid CanvasText;
|
|
125
|
+
outline-offset: -1px;
|
|
126
|
+
}
|
|
120
127
|
|
|
121
128
|
.accordion__trigger {
|
|
122
129
|
@media (hover: hover) {
|
|
@@ -140,13 +147,13 @@
|
|
|
140
147
|
|
|
141
148
|
/* Special rounding for first and last items in surface variant */
|
|
142
149
|
&:first-child [data-slot="accordion-trigger"] {
|
|
143
|
-
border-start-start-radius: min(32px, var(--radius
|
|
144
|
-
border-start-end-radius: min(32px, var(--radius
|
|
150
|
+
border-start-start-radius: min(32px, var(--component-radius));
|
|
151
|
+
border-start-end-radius: min(32px, var(--component-radius));
|
|
145
152
|
}
|
|
146
153
|
|
|
147
154
|
&:last-child:not(:has([data-slot="accordion-trigger"][aria-expanded="true"]))
|
|
148
155
|
[data-slot="accordion-trigger"] {
|
|
149
|
-
border-end-start-radius: min(32px, var(--radius
|
|
150
|
-
border-end-end-radius: min(32px, var(--radius
|
|
156
|
+
border-end-start-radius: min(32px, var(--component-radius));
|
|
157
|
+
border-end-end-radius: min(32px, var(--component-radius));
|
|
151
158
|
}
|
|
152
159
|
}
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
@apply flex min-h-0 w-full flex-col;
|
|
146
146
|
@apply max-h-full;
|
|
147
147
|
@apply bg-overlay shadow-overlay outline-none;
|
|
148
|
-
border-radius: min(32px, var(--radius
|
|
148
|
+
border-radius: min(32px, var(--component-radius));
|
|
149
149
|
@apply p-6;
|
|
150
150
|
@apply overflow-clip;
|
|
151
151
|
@apply pointer-events-auto;
|
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
/* Base alert styles */
|
|
4
4
|
.alert {
|
|
5
5
|
@apply flex w-full flex-row items-start justify-start gap-4 bg-surface px-4 py-3 shadow-surface;
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
/* Forced Colors Mode flattens the fill onto the page and strips the shadow, so the container
|
|
8
|
+
* stops having any shape - its contents just sit loose on the page. An outline rather than a
|
|
9
|
+
* border so nothing shifts, and it follows the radius the component sets. */
|
|
10
|
+
@media (forced-colors: active) {
|
|
11
|
+
outline: 1px solid CanvasText;
|
|
12
|
+
outline-offset: -1px;
|
|
13
|
+
}
|
|
14
|
+
border-radius: min(32px, var(--component-radius));
|
|
7
15
|
}
|
|
8
16
|
|
|
9
17
|
/* Alert elements */
|
|
@@ -7,6 +7,17 @@ export declare const autocompleteVariants: import("tailwind-variants").TVReturnT
|
|
|
7
7
|
trigger: string;
|
|
8
8
|
};
|
|
9
9
|
};
|
|
10
|
+
size: {
|
|
11
|
+
lg: {
|
|
12
|
+
base: string;
|
|
13
|
+
popover: string;
|
|
14
|
+
};
|
|
15
|
+
md: {};
|
|
16
|
+
sm: {
|
|
17
|
+
base: string;
|
|
18
|
+
popover: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
10
21
|
variant: {
|
|
11
22
|
primary: {
|
|
12
23
|
base: string;
|
|
@@ -31,6 +42,17 @@ export declare const autocompleteVariants: import("tailwind-variants").TVReturnT
|
|
|
31
42
|
trigger: string;
|
|
32
43
|
};
|
|
33
44
|
};
|
|
45
|
+
size: {
|
|
46
|
+
lg: {
|
|
47
|
+
base: string;
|
|
48
|
+
popover: string;
|
|
49
|
+
};
|
|
50
|
+
md: {};
|
|
51
|
+
sm: {
|
|
52
|
+
base: string;
|
|
53
|
+
popover: string;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
34
56
|
variant: {
|
|
35
57
|
primary: {
|
|
36
58
|
base: string;
|
|
@@ -55,6 +77,17 @@ export declare const autocompleteVariants: import("tailwind-variants").TVReturnT
|
|
|
55
77
|
trigger: string;
|
|
56
78
|
};
|
|
57
79
|
};
|
|
80
|
+
size: {
|
|
81
|
+
lg: {
|
|
82
|
+
base: string;
|
|
83
|
+
popover: string;
|
|
84
|
+
};
|
|
85
|
+
md: {};
|
|
86
|
+
sm: {
|
|
87
|
+
base: string;
|
|
88
|
+
popover: string;
|
|
89
|
+
};
|
|
90
|
+
};
|
|
58
91
|
variant: {
|
|
59
92
|
primary: {
|
|
60
93
|
base: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autocomplete.styles.d.ts","sourceRoot":"","sources":["../../../src/components/autocomplete/autocomplete.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,eAAO,MAAM,oBAAoB;;
|
|
1
|
+
{"version":3,"file":"autocomplete.styles.d.ts","sourceRoot":"","sources":["../../../src/components/autocomplete/autocomplete.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,eAAO,MAAM,oBAAoB;;QAiB3B,KAAK;QACL,IAAI;YACF,IAAI;YACJ,OAAO;;;;QAIT,EAAE;YACA,IAAI;YACJ,OAAO;;QAET,EAAE;QACF,EAAE;YACA,IAAI;YACJ,OAAO;;;;QAIT,OAAO;YACL,IAAI;;QAEN,SAAS;YACP,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAIV,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,YAAY,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { tv } from "tailwind-variants";
|
|
|
3
3
|
const autocompleteVariants = tv({
|
|
4
4
|
defaultVariants: {
|
|
5
5
|
fullWidth: false,
|
|
6
|
+
size: "md",
|
|
6
7
|
variant: "primary"
|
|
7
8
|
},
|
|
8
9
|
slots: {
|
|
@@ -22,6 +23,17 @@ const autocompleteVariants = tv({
|
|
|
22
23
|
trigger: "autocomplete__trigger--full-width"
|
|
23
24
|
}
|
|
24
25
|
},
|
|
26
|
+
size: {
|
|
27
|
+
lg: {
|
|
28
|
+
base: "autocomplete--lg",
|
|
29
|
+
popover: "autocomplete__popover--lg"
|
|
30
|
+
},
|
|
31
|
+
md: {},
|
|
32
|
+
sm: {
|
|
33
|
+
base: "autocomplete--sm",
|
|
34
|
+
popover: "autocomplete__popover--sm"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
25
37
|
variant: {
|
|
26
38
|
primary: { base: "autocomplete--primary" },
|
|
27
39
|
secondary: { base: "autocomplete--secondary" }
|
|
@@ -4,7 +4,15 @@
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
.autocomplete__trigger {
|
|
7
|
-
@apply relative isolate inline-flex min-h-9 rounded-field border bg-field px-3
|
|
7
|
+
@apply relative isolate inline-flex min-h-9 rounded-field border bg-field px-3 field-line-md text-field-foreground shadow-field outline-none select-none no-highlight;
|
|
8
|
+
|
|
9
|
+
/* Forced Colors Mode flattens the fill onto the page and strips the shadow, leaving a control
|
|
10
|
+
* with nothing to say it is one. `ButtonBorder` is the keyword the platform uses for a
|
|
11
|
+
* control's edge. */
|
|
12
|
+
@media (forced-colors: active) {
|
|
13
|
+
outline: 1px solid ButtonBorder;
|
|
14
|
+
outline-offset: -1px;
|
|
15
|
+
}
|
|
8
16
|
|
|
9
17
|
/**
|
|
10
18
|
* Transitions
|
|
@@ -101,7 +109,7 @@
|
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
.autocomplete__value {
|
|
104
|
-
@apply flex-1 text-start
|
|
112
|
+
@apply flex-1 text-start wrap-break-word text-current;
|
|
105
113
|
|
|
106
114
|
&[data-placeholder="true"] {
|
|
107
115
|
@apply text-field-placeholder;
|
|
@@ -131,7 +139,7 @@
|
|
|
131
139
|
/* Similar to popover content styles */
|
|
132
140
|
.autocomplete__popover {
|
|
133
141
|
@apply flex w-(--trigger-width) max-w-(--trigger-width) origin-(--trigger-anchor-point) scroll-py-1 flex-col overflow-hidden overscroll-contain bg-overlay p-0 pt-2 text-sm outline-none;
|
|
134
|
-
border-radius: min(32px, var(--radius
|
|
142
|
+
border-radius: min(32px, var(--component-radius));
|
|
135
143
|
box-shadow: var(--shadow-overlay);
|
|
136
144
|
|
|
137
145
|
&:focus,
|
|
@@ -281,3 +289,31 @@
|
|
|
281
289
|
transform: scale(0.93);
|
|
282
290
|
}
|
|
283
291
|
}
|
|
292
|
+
|
|
293
|
+
/* ==========================================================================
|
|
294
|
+
Size variants
|
|
295
|
+
========================================================================== */
|
|
296
|
+
|
|
297
|
+
/* The trigger's own metrics, and the option rows in a popover that is portalled out of this tree -
|
|
298
|
+
* which is why the popover carries its own size class rather than being reached from the base. */
|
|
299
|
+
.autocomplete--sm .autocomplete__trigger {
|
|
300
|
+
@apply min-h-8 field-line-sm;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.autocomplete--lg .autocomplete__trigger {
|
|
304
|
+
@apply min-h-10 field-line-lg;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.autocomplete__popover--sm {
|
|
308
|
+
[data-slot="list-box-item"] {
|
|
309
|
+
@apply min-h-8 py-1;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.autocomplete__popover--lg {
|
|
314
|
+
@apply text-base;
|
|
315
|
+
|
|
316
|
+
[data-slot="list-box-item"] {
|
|
317
|
+
@apply min-h-10 py-2;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
/* Base avatar styles */
|
|
2
2
|
.avatar {
|
|
3
3
|
@apply relative flex size-10 shrink-0 items-center justify-center overflow-hidden rounded-3xl bg-default;
|
|
4
|
+
|
|
5
|
+
/* Forced Colors Mode flattens the fill onto the page, so a fallback avatar is initials sitting
|
|
6
|
+
* loose on the page with no shape around them. The edge goes here rather than on the fallback:
|
|
7
|
+
* this is the element carrying the radius, and the `overflow-hidden` above would clip a
|
|
8
|
+
* square outline drawn inside it down to four arcs. */
|
|
9
|
+
@media (forced-colors: active) {
|
|
10
|
+
outline: 1px solid CanvasText;
|
|
11
|
+
outline-offset: -1px;
|
|
12
|
+
}
|
|
4
13
|
}
|
|
5
14
|
|
|
6
15
|
/* Avatar fallback element */
|
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
color: var(--badge-fg);
|
|
19
19
|
border: 1px solid var(--badge-border);
|
|
20
20
|
background-clip: padding-box;
|
|
21
|
+
|
|
22
|
+
/* That border is the page colour, there to cut the badge out of whatever it overlaps, and
|
|
23
|
+
* forced colors turns it into a visible ring - which is the only reason a badge still reads
|
|
24
|
+
* as one. Stated here so it stays true if `--badge-border` is ever repointed. */
|
|
25
|
+
@media (forced-colors: active) {
|
|
26
|
+
border-color: CanvasText;
|
|
27
|
+
}
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
.badge__label {
|
|
@@ -26,32 +26,32 @@
|
|
|
26
26
|
|
|
27
27
|
/* Apply border radius to first button (start edge) */
|
|
28
28
|
.button-group--horizontal .button:first-child {
|
|
29
|
-
@apply rounded-s-
|
|
29
|
+
@apply rounded-s-component;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/* Apply border radius to last button (end edge) */
|
|
33
33
|
.button-group--horizontal .button:last-child {
|
|
34
|
-
@apply rounded-e-
|
|
34
|
+
@apply rounded-e-component;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/* If only one button, apply both rounded edges */
|
|
38
38
|
.button-group--horizontal .button:first-child:last-child {
|
|
39
|
-
@apply rounded-
|
|
39
|
+
@apply rounded-component;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/* Apply border radius to first button (top edge) in vertical */
|
|
43
43
|
.button-group--vertical .button:first-child {
|
|
44
|
-
@apply rounded-t-
|
|
44
|
+
@apply rounded-t-component;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/* Apply border radius to last button (bottom edge) in vertical */
|
|
48
48
|
.button-group--vertical .button:last-child {
|
|
49
|
-
@apply rounded-b-
|
|
49
|
+
@apply rounded-b-component;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/* If only one button in vertical, apply all rounded edges */
|
|
53
53
|
.button-group--vertical .button:first-child:last-child {
|
|
54
|
-
@apply rounded-
|
|
54
|
+
@apply rounded-component;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/* Remove scale transform on active/pressed state for buttons in group */
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/* Base button styles */
|
|
4
4
|
.button {
|
|
5
|
-
@apply relative isolate inline-flex h-
|
|
5
|
+
@apply relative isolate inline-flex h-9 w-fit origin-center items-center justify-center gap-2 rounded-component px-4 text-sm font-medium whitespace-nowrap outline-none select-none no-highlight;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Transitions
|
|
@@ -26,6 +26,15 @@
|
|
|
26
26
|
background-color: var(--button-bg);
|
|
27
27
|
color: var(--button-fg);
|
|
28
28
|
|
|
29
|
+
/* Forced Colors Mode flattens the fill onto the page and strips the shadow, leaving a control
|
|
30
|
+
* that reads as bare text. `ButtonBorder` is the keyword the platform uses for a control's
|
|
31
|
+
* edge; an outline rather than a border so nothing shifts, and the focus ring replaces it
|
|
32
|
+
* while focused, which is the right order of importance. */
|
|
33
|
+
@media (forced-colors: active) {
|
|
34
|
+
outline: 1px solid ButtonBorder;
|
|
35
|
+
outline-offset: -1px;
|
|
36
|
+
}
|
|
37
|
+
|
|
29
38
|
/* Focus state */
|
|
30
39
|
&:focus-visible:not(:focus),
|
|
31
40
|
&[data-focus-visible="true"] {
|
|
@@ -60,17 +69,13 @@
|
|
|
60
69
|
|
|
61
70
|
/* SVG icon styling - exclude spinner and link-icon svgs */
|
|
62
71
|
& svg:not([data-slot="spinner"] svg, [data-slot="link-icon"] svg) {
|
|
63
|
-
@apply pointer-events-none -mx-0.5 my-
|
|
72
|
+
@apply pointer-events-none -mx-0.5 my-1 size-4 shrink-0 self-center;
|
|
64
73
|
}
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
/* Size variants */
|
|
68
77
|
.button--sm {
|
|
69
|
-
@apply h-
|
|
70
|
-
|
|
71
|
-
& svg:not([data-slot="spinner"] svg, [data-slot="link-icon"] svg) {
|
|
72
|
-
@apply size-4;
|
|
73
|
-
}
|
|
78
|
+
@apply h-8 px-3;
|
|
74
79
|
|
|
75
80
|
&:active,
|
|
76
81
|
&[data-pressed="true"] {
|
|
@@ -83,7 +88,7 @@
|
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
.button--lg {
|
|
86
|
-
@apply h-
|
|
91
|
+
@apply h-10 text-base;
|
|
87
92
|
|
|
88
93
|
&:active,
|
|
89
94
|
&[data-pressed="true"] {
|
|
@@ -97,6 +102,16 @@
|
|
|
97
102
|
--button-bg-hover: var(--accent-hover);
|
|
98
103
|
--button-bg-pressed: var(--accent-hover);
|
|
99
104
|
--button-fg: var(--accent-foreground);
|
|
105
|
+
|
|
106
|
+
/* Solid against outlined is the one distinction that survives - forced colors has no keyword
|
|
107
|
+
* for "this is the important one", so the emphasis has to come from the fill. `Highlight` is
|
|
108
|
+
* spoken for by selection, which a button is not in. `forced-color-adjust` keeps the backplate
|
|
109
|
+
* off the label. */
|
|
110
|
+
@media (forced-colors: active) {
|
|
111
|
+
forced-color-adjust: none;
|
|
112
|
+
background-color: CanvasText;
|
|
113
|
+
color: Canvas;
|
|
114
|
+
}
|
|
100
115
|
}
|
|
101
116
|
|
|
102
117
|
.button--secondary {
|
|
@@ -130,6 +145,14 @@
|
|
|
130
145
|
--button-bg-hover: var(--danger-hover);
|
|
131
146
|
--button-bg-pressed: var(--danger-hover);
|
|
132
147
|
--button-fg: var(--danger-foreground);
|
|
148
|
+
|
|
149
|
+
/* Solid like the primary one. The danger colour itself cannot survive - there is no keyword
|
|
150
|
+
* for it - so the label is what says this is the destructive action. */
|
|
151
|
+
@media (forced-colors: active) {
|
|
152
|
+
forced-color-adjust: none;
|
|
153
|
+
background-color: CanvasText;
|
|
154
|
+
color: Canvas;
|
|
155
|
+
}
|
|
133
156
|
}
|
|
134
157
|
|
|
135
158
|
.button--danger-soft {
|
|
@@ -141,15 +164,15 @@
|
|
|
141
164
|
|
|
142
165
|
/* Icon-only modifier */
|
|
143
166
|
.button--icon-only {
|
|
144
|
-
@apply w-
|
|
167
|
+
@apply w-9 p-0;
|
|
145
168
|
}
|
|
146
169
|
|
|
147
170
|
.button--icon-only.button--sm {
|
|
148
|
-
@apply w-
|
|
171
|
+
@apply w-8;
|
|
149
172
|
}
|
|
150
173
|
|
|
151
174
|
.button--icon-only.button--lg {
|
|
152
|
-
@apply w-
|
|
175
|
+
@apply w-10;
|
|
153
176
|
}
|
|
154
177
|
|
|
155
178
|
/* Full width modifier */
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
* Year Cell
|
|
117
117
|
* -------------------------------------------------------------------------- */
|
|
118
118
|
.calendar-year-picker__year-cell {
|
|
119
|
-
@apply relative inline-flex h-8 items-center justify-center rounded-
|
|
119
|
+
@apply relative inline-flex h-8 items-center justify-center rounded-component px-2.5 text-sm font-medium outline-none select-none no-highlight;
|
|
120
120
|
touch-action: manipulation;
|
|
121
121
|
|
|
122
122
|
/**
|
|
@@ -144,6 +144,7 @@
|
|
|
144
144
|
&[data-selected="true"],
|
|
145
145
|
&[aria-selected="true"] {
|
|
146
146
|
@apply bg-accent text-accent-foreground;
|
|
147
|
+
@apply forced-selected;
|
|
147
148
|
|
|
148
149
|
@media (hover: hover) and (pointer: fine) {
|
|
149
150
|
&:is(:hover, [data-hovered="true"]) {
|
|
@@ -207,6 +207,13 @@
|
|
|
207
207
|
&[data-today="true"] {
|
|
208
208
|
@apply bg-accent-soft text-accent-soft-foreground;
|
|
209
209
|
|
|
210
|
+
/* A tinted background is all that marks today, and forced colors flattens it onto the page.
|
|
211
|
+
* An edge rather than a fill, so today still reads as itself once it is also selected. */
|
|
212
|
+
@media (forced-colors: active) {
|
|
213
|
+
outline: 1px solid CanvasText;
|
|
214
|
+
outline-offset: -1px;
|
|
215
|
+
}
|
|
216
|
+
|
|
210
217
|
@media (hover: hover) {
|
|
211
218
|
&:hover:not([data-selected="true"]),
|
|
212
219
|
&[data-hovered="true"]:not([data-selected="true"]) {
|
|
@@ -218,6 +225,7 @@
|
|
|
218
225
|
/* Selected state */
|
|
219
226
|
&[data-selected="true"] {
|
|
220
227
|
@apply bg-accent text-accent-foreground;
|
|
228
|
+
@apply forced-selected;
|
|
221
229
|
}
|
|
222
230
|
|
|
223
231
|
/* Pressed state */
|