@carissa-io/theme-default 0.2.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/DESIGN.md +67 -10
- package/README.md +57 -2
- package/dist/index.css +366 -176
- package/package.json +7 -2
- package/scss/_modes.scss +90 -0
- package/scss/_tokens.scss +21 -0
- package/scss/index.scss +242 -162
package/DESIGN.md
CHANGED
|
@@ -26,19 +26,76 @@ The same palette is available as Sass tokens (`$black`, `$muted`, `$surface`, `$
|
|
|
26
26
|
[scss/_tokens.scss](scss/_tokens.scss), the machine-readable palette: apps read them (for example to configure Bootstrap)
|
|
27
27
|
instead of copying the hex values, so a change of value here reaches them with the next release.
|
|
28
28
|
|
|
29
|
-
##
|
|
30
|
-
|
|
29
|
+
## Dark mode
|
|
30
|
+
Both modes ship in the same package; dark is **opt-in per app** with `data-mode` on `<html>` (`dark`, `light`, or `auto` to follow
|
|
31
|
+
`prefers-color-scheme`; no attribute is light). The palette is a set of custom properties by role, defined in
|
|
32
|
+
[scss/_modes.scss](scss/_modes.scss); the Sass tokens remain the static light values.
|
|
33
|
+
|
|
34
|
+
| Role (`--c-...`) | Light | Dark |
|
|
35
|
+
| :--- | :--- | :--- |
|
|
36
|
+
| `background` | `#ffffff` | `#0a0a0a` |
|
|
37
|
+
| `text` | `#171717` | `#f5f5f5` |
|
|
38
|
+
| `muted` | `#737373` | `#a3a3a3` |
|
|
39
|
+
| `surface` | `#f5f5f5` | `#171717` |
|
|
40
|
+
| `surface-active` | `#e5e5e5` | `#262626` |
|
|
41
|
+
| `primary` | `#000000` | `#ffffff` |
|
|
42
|
+
| `on-primary` | `#ffffff` | `#000000` |
|
|
43
|
+
| `primary-hover` | `#262626` | `#e5e5e5` |
|
|
44
|
+
| `primary-active` | `#404040` | `#d4d4d4` |
|
|
45
|
+
| `disabled-text` | `#a3a3a3` | `#737373` |
|
|
46
|
+
| `disabled-border` | `#d4d4d4` | `#404040` |
|
|
47
|
+
| `error` | `#dc3545` | `#f87171` |
|
|
48
|
+
| `focus` | `#000000` | `#ffffff` |
|
|
49
|
+
|
|
50
|
+
Decisions: dark inverts the contrast of the light theme, it does not invent a new look (near-black ground, the primary action becomes white,
|
|
51
|
+
square corners and the 1px focus ring stay). The ground is `#0a0a0a`, not pure black, so surfaces (`#171717`) can be told apart. Primary and focus
|
|
52
|
+
are pure white as black is in light. The error red is lighter (`#f87171`) because `#dc3545` is too dim on a dark ground.
|
|
53
|
+
|
|
54
|
+
Contrast (WCAG 2.x): text 4.5:1, borders and the focus ring 3:1.
|
|
55
|
+
|
|
56
|
+
| Pair | Light | Dark |
|
|
31
57
|
| :--- | :--- | :--- |
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
34
|
-
| `
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
58
|
+
| `text` on `background` | 17.93 | 18.16 |
|
|
59
|
+
| `muted` on `background` (labels, placeholders, field borders) | 4.74 | 7.85 |
|
|
60
|
+
| `muted` on `surface` | 4.35 | 7.11 |
|
|
61
|
+
| `on-primary` on `primary` | 21.00 | 21.00 |
|
|
62
|
+
| `error` on `background` | 4.53 | 7.16 |
|
|
63
|
+
| `focus` on `background` | 21.00 | 19.80 |
|
|
64
|
+
| `disabled-text` on `surface` (disabled, exempt) | 2.31 | 3.78 |
|
|
65
|
+
|
|
66
|
+
`muted` on `surface` in light (4.35) is a known gap that already existed (muted text on the hover surface); the disabled states are exempt from
|
|
67
|
+
WCAG but are listed in the backlog for a contrast review. Known gap in dark: the 0-width listbox option separator keeps the component default
|
|
68
|
+
(`#dee2e6`); it draws nothing today.
|
|
69
|
+
|
|
70
|
+
## Typography
|
|
71
|
+
Configured through [components-typography](components/components-typography): `Heading` (the element comes from `level`, the look from `size`)
|
|
72
|
+
and `Text`. Neutral grotesque, no margins (spacing belongs to the layout), color from `$text`; only muted text uses `$muted`.
|
|
73
|
+
|
|
74
|
+
| Style | Size / line height | Weight | Tracking | Purpose |
|
|
75
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
76
|
+
| `display` | 3.5rem / 1.05 | Black (900) | -0.04em | Hero statements |
|
|
77
|
+
| `h1` | 2.5rem / 1.1 | Black (900) | -0.03em | Primary page header |
|
|
78
|
+
| `h2` | 1.75rem / 1.2 | Black (900) | -0.02em | Section header |
|
|
79
|
+
| `h3` | 1.25rem / 1.3 | Bold (700) | normal | Sub-section |
|
|
80
|
+
| `h4` | 1.125rem / 1.3 | Bold (700) | normal | Group title |
|
|
81
|
+
| `h5` | 1rem / 1.4 | Bold (700) | normal | Minor title |
|
|
82
|
+
| `h6` | 0.875rem / 1.4 | Bold (700) | normal | Smallest title |
|
|
83
|
+
| `lead` | 1.25rem / 1.5 | Regular (400) | normal | Introductory paragraph |
|
|
84
|
+
| `body` | 1rem / 1.5 | Regular (400) | normal | Main content |
|
|
85
|
+
| `small` | 0.875rem / 1.5 | Regular (400) | normal | Secondary content |
|
|
86
|
+
| `caption` | 0.75rem / 1.4 | Regular (400), muted by use | normal | Notes under media or fields |
|
|
87
|
+
| `overline` | 0.6875rem / 1.4 | Bold (700), uppercase | 0.1em | Metadata / tags: the field-label style |
|
|
88
|
+
| `mono` | 0.875rem / 1.5 | Regular (400) | normal | System data, in `$font-family-mono` |
|
|
89
|
+
|
|
90
|
+
The sizes, weights and the two shared line heights of this table are Sass tokens in [scss/_tokens.scss](scss/_tokens.scss)
|
|
91
|
+
(`$font-size-display` to `$font-size-overline`, `$font-weight-regular|bold|black`, `$line-height-tight|normal`), so the whole hierarchy moves
|
|
92
|
+
from one place. The components' own text uses them where it plays the same role (field and option text is `$font-size-body`, the selected
|
|
93
|
+
option `$font-weight-bold`). One-off values stay literal: the line heights 1.05, 1.1, 1.2 and 1.4, the heading tracking, the 0.8125rem error text.
|
|
38
94
|
|
|
39
95
|
Font family: a neutral grotesque stack, `Helvetica Neue, Helvetica, Arial, Liberation Sans, sans-serif`, in keeping with
|
|
40
|
-
the International Typographic Style. No webfont is loaded, so a theme never depends on the network.
|
|
41
|
-
|
|
96
|
+
the International Typographic Style. No webfont is loaded, so a theme never depends on the network. System data uses the
|
|
97
|
+
`$font-family-mono` token, a system monospace stack (`ui-monospace, SFMono-Regular, Menlo, Consolas, Liberation Mono`).
|
|
98
|
+
Field text is 1rem (16px, which also avoids the zoom-on-focus of mobile browsers); labels are 11px.
|
|
42
99
|
|
|
43
100
|
## Buttons
|
|
44
101
|
Three variants from [components-button](components/components-button), all square, 44px tall, with the same uppercase,
|
package/README.md
CHANGED
|
@@ -26,6 +26,43 @@ peer dependencies).
|
|
|
26
26
|
4. **A starting point for a new theme:** copy `scss/index.scss` and `scss/_tokens.scss` and change the values. In the Carissa workspace,
|
|
27
27
|
`scripts/new-theme.sh <name> "<description>"` does this and sets up the repo.
|
|
28
28
|
|
|
29
|
+
## Color modes
|
|
30
|
+
The theme has a light and a dark palette in one package. The palette is a set of CSS custom properties (`--c-background`, `--c-text`,
|
|
31
|
+
`--c-muted`, `--c-surface`, `--c-surface-active`, `--c-primary`, `--c-on-primary`, `--c-primary-hover`, `--c-primary-active`,
|
|
32
|
+
`--c-disabled-text`, `--c-disabled-border`, `--c-error`, `--c-focus`) that every component reads. **Dark is opt-in per app**: without
|
|
33
|
+
the attribute below the app is light, exactly as before.
|
|
34
|
+
|
|
35
|
+
An app opts in with one line in the file where it imports the theme (`App/theme.js`), setting the mode on `<html>`:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
import '@carissa-io/theme-default/css'
|
|
39
|
+
|
|
40
|
+
document.documentElement.dataset.mode = 'auto' // 'auto' | 'dark' | 'light'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
| `data-mode` on `<html>` | Result |
|
|
44
|
+
| :--- | :--- |
|
|
45
|
+
| none | light |
|
|
46
|
+
| `light` | light |
|
|
47
|
+
| `dark` | dark |
|
|
48
|
+
| `auto` | light, and dark while the system asks for it (`prefers-color-scheme: dark`) |
|
|
49
|
+
|
|
50
|
+
`color-scheme` follows the mode, so native controls and scrollbars match. To avoid a flash of the wrong mode, set the attribute before the
|
|
51
|
+
first paint: put this in the `<head>` of the page, before the stylesheet, with the choice the app remembers (here in `localStorage`):
|
|
52
|
+
|
|
53
|
+
```html
|
|
54
|
+
<script>
|
|
55
|
+
try {
|
|
56
|
+
document.documentElement.dataset.mode = localStorage.getItem('mode') || 'auto'
|
|
57
|
+
} catch {
|
|
58
|
+
document.documentElement.dataset.mode = 'auto'
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The Sass tokens above stay the static **light** values (for Sass consumers); the dark values are in `scss/_modes.scss`. The page background and
|
|
64
|
+
text color are the app's: give `body` `background: var(--c-background); color: var(--c-text)`.
|
|
65
|
+
|
|
29
66
|
## Tokens
|
|
30
67
|
The palette and the values shared by every component are Sass variables in `scss/_tokens.scss`, the single source of
|
|
31
68
|
the theme's values (`scss/index.scss` reads them with `@use 'tokens' as *`). The file emits no CSS, so an app can read
|
|
@@ -50,6 +87,7 @@ change.
|
|
|
50
87
|
| `$disabled-border` | `#d4d4d4` | disabled borders |
|
|
51
88
|
| `$error` | `#dc3545` | error text and borders |
|
|
52
89
|
| `$font-family` | `'Helvetica Neue', Helvetica, Arial, 'Liberation Sans', sans-serif` | type stack |
|
|
90
|
+
| `$font-family-mono` | `ui-monospace, 'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', monospace` | monospace stack for system data and code |
|
|
53
91
|
| `$radius` | `0` | corner radius |
|
|
54
92
|
| `$min-height` | `2.75rem` | touch target |
|
|
55
93
|
| `$focus-color` | `$black` | focus color |
|
|
@@ -58,6 +96,23 @@ change.
|
|
|
58
96
|
| `$label-font-size` | `0.6875rem` | field label size |
|
|
59
97
|
| `$label-font-weight` | `700` | field label weight |
|
|
60
98
|
| `$label-letter-spacing` | `0.1em` | field label tracking |
|
|
99
|
+
| `$font-size-display` | `3.5rem` | `Heading` display |
|
|
100
|
+
| `$font-size-h1` | `2.5rem` | `Heading` 1 |
|
|
101
|
+
| `$font-size-h2` | `1.75rem` | `Heading` 2 |
|
|
102
|
+
| `$font-size-h3` | `1.25rem` | `Heading` 3 |
|
|
103
|
+
| `$font-size-h4` | `1.125rem` | `Heading` 4 |
|
|
104
|
+
| `$font-size-h5` | `1rem` | `Heading` 5 |
|
|
105
|
+
| `$font-size-h6` | `0.875rem` | `Heading` 6, `Text` mono |
|
|
106
|
+
| `$font-size-lead` | `1.25rem` | `Text` lead |
|
|
107
|
+
| `$font-size-body` | `1rem` | body text, and the text of every field and option (16px) |
|
|
108
|
+
| `$font-size-small` | `0.875rem` | `Text` small |
|
|
109
|
+
| `$font-size-caption` | `0.75rem` | `Text` caption |
|
|
110
|
+
| `$font-size-overline` | `$label-font-size` | `Text` overline |
|
|
111
|
+
| `$font-weight-regular` | `400` | body text |
|
|
112
|
+
| `$font-weight-bold` | `700` | titles from `h3`, selected option |
|
|
113
|
+
| `$font-weight-black` | `900` | `display`, `h1` and `h2` |
|
|
114
|
+
| `$line-height-tight` | `1.3` | `h3` and `h4` |
|
|
115
|
+
| `$line-height-normal` | `1.5` | running text |
|
|
61
116
|
| `$arrow-size` | `1rem` | dropdown arrow size |
|
|
62
117
|
| `$arrow-offset` | `0.75rem` | dropdown arrow inset |
|
|
63
118
|
| `$arrow-color` | `$muted` | dropdown arrow color |
|
|
@@ -84,11 +139,11 @@ it: check the names against the theme's `scss/_tokens.scss` before you switch.
|
|
|
84
139
|
|
|
85
140
|
## What it configures
|
|
86
141
|
`components-input`, `-button`, `-checkbox`, `-switch`, `-radio-group`, `-slider`, `-popover`, `-listbox`, `-select`,
|
|
87
|
-
`-combobox`, `-upload`, `-calendar`, `-date-picker` and `-
|
|
142
|
+
`-combobox`, `-upload`, `-calendar`, `-date-picker`, `-search` and `-typography`. `components-email`, `-password`, `-url` and `-textarea`
|
|
88
143
|
are styled through the input.
|
|
89
144
|
|
|
90
145
|
## Change a value
|
|
91
|
-
The palette and the values shared by every component (radius, minimum height, focus ring, transition, label style, dropdown
|
|
146
|
+
The palette and the values shared by every component (fonts, radius, minimum height, focus ring, transition, label style, dropdown
|
|
92
147
|
arrow) are the Sass variables of `scss/_tokens.scss` (the [tokens](#tokens)); each component has one `@use ... with (...)` block of overrides
|
|
93
148
|
below. Change the value, run `npm run build`, and update [DESIGN.md](DESIGN.md) if the decision changes.
|
|
94
149
|
|