@juwel-development/design-system 3.0.0 → 3.1.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 +31 -0
- package/dist/design-system.js +202 -126
- package/dist/index.css +1 -1
- package/dist/types/Arrangement/Cluster/Cluster.d.ts +50 -0
- package/dist/types/Arrangement/Stack/Stack.d.ts +46 -0
- package/dist/types/Display/Figure/Figure.d.ts +21 -4
- package/dist/types/Display/Rail/Rail.d.ts +6 -0
- package/dist/types/Display/Typography/H1/H1.d.ts +7 -1
- package/dist/types/Display/Typography/Note/Note.d.ts +35 -0
- package/dist/types/Interaction/Link/Link.d.ts +4 -4
- package/dist/types/Layout/Form/Form.d.ts +8 -4
- package/dist/types/Layout/Header/Header.d.ts +20 -1
- package/dist/types/Layout/Hero/Hero.d.ts +9 -7
- package/dist/types/Layout/Section/Section.d.ts +7 -0
- package/dist/types/Theme/Palette.d.ts +55 -6
- package/dist/types/index.d.ts +3 -0
- package/package.json +1 -1
- package/src/Arrangement/Cluster/Cluster.tsx +80 -0
- package/src/Arrangement/Stack/Stack.tsx +75 -0
- package/src/Display/Figure/Figure.tsx +48 -7
- package/src/Display/Rail/Rail.tsx +6 -0
- package/src/Display/Typography/H1/H1.tsx +17 -7
- package/src/Display/Typography/Note/Note.tsx +56 -0
- package/src/Interaction/Button/Button.tsx +4 -1
- package/src/Interaction/Input/Input.tsx +17 -6
- package/src/Interaction/Link/Link.tsx +9 -5
- package/src/Interaction/TextArea/TextArea.tsx +17 -6
- package/src/Layout/Form/Form.tsx +24 -8
- package/src/Layout/Header/Header.tsx +37 -4
- package/src/Layout/Hero/Hero.tsx +10 -6
- package/src/Layout/PageHead/PageHead.tsx +2 -0
- package/src/Layout/Section/Section.tsx +11 -0
- package/src/Theme/Palette.ts +63 -14
- package/src/Theme/renderTokens.ts +18 -1
- package/src/index.ts +3 -0
- package/src/tokens.css +20 -9
- package/src/tokens.dark.css +16 -5
- package/src/tokens.light.css +16 -5
|
@@ -2,7 +2,7 @@ import type { VariantProps } from 'class-variance-authority';
|
|
|
2
2
|
import { cva } from 'class-variance-authority';
|
|
3
3
|
import type { FunctionComponent, ReactNode } from 'react';
|
|
4
4
|
|
|
5
|
-
//
|
|
5
|
+
// The recipe on the <header>. It sets the label type role - the "small grotesk, letter-spaced, muted"
|
|
6
6
|
// the issue described, whose "never grows past 1rem" was a role wearing a number, so no size literal
|
|
7
7
|
// appears here (#14). The shell's air is one value in every direction: --space-region above, below and
|
|
8
8
|
// (on the nav) between, --gutter across, so the bar aligns with every inset Section. The current-page
|
|
@@ -15,7 +15,7 @@ import type { FunctionComponent, ReactNode } from 'react';
|
|
|
15
15
|
const header = cva(
|
|
16
16
|
[
|
|
17
17
|
'flex items-baseline justify-between',
|
|
18
|
-
'font-secondary text-label tracking-label text-muted',
|
|
18
|
+
'font-secondary text-label leading-label tracking-label text-muted',
|
|
19
19
|
'py-[var(--space-region)] px-[var(--gutter)]',
|
|
20
20
|
'[&_[aria-current=page]]:text-foreground',
|
|
21
21
|
].join(' '),
|
|
@@ -30,6 +30,20 @@ const header = cva(
|
|
|
30
30
|
},
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
+
// Not a second recipe - the standing slot has nothing to vary, and the standard allows a component
|
|
34
|
+
// one cva() (design-system-components.md §4), which is the bar's own above. A named constant beside
|
|
35
|
+
// the nav's inline class string, so the comment has something to sit on.
|
|
36
|
+
//
|
|
37
|
+
// The height floor is the nav's own line box, written from the two tokens the recipe above sets the
|
|
38
|
+
// header from, so the declared floor and the rendered line cannot drift (#81). `shrink-0` because an
|
|
39
|
+
// explicit min-width replaces a flex item's automatic minimum - without it the bar squeezes the slot
|
|
40
|
+
// below its content and wraps the place name the floor exists to keep on one line.
|
|
41
|
+
const standingSlot = [
|
|
42
|
+
'inline-flex shrink-0 items-center',
|
|
43
|
+
'min-h-[calc(var(--text-label)*var(--leading-label))]',
|
|
44
|
+
'min-w-[var(--standing-min-width)]',
|
|
45
|
+
].join(' ');
|
|
46
|
+
|
|
33
47
|
export interface IHeaderProps extends VariantProps<typeof header> {
|
|
34
48
|
/** The standing link: a place name, a mark, or a home link. The consumer supplies the whole anchor -
|
|
35
49
|
* Header renders no link of its own. A place name uses `<Link treatment="quiet" href="/">…</Link>`; a
|
|
@@ -49,7 +63,14 @@ export interface IHeaderProps extends VariantProps<typeof header> {
|
|
|
49
63
|
*
|
|
50
64
|
* @Guarantees — enforced on every render
|
|
51
65
|
* - The header is set at the label role and carries no size of its own: `font-secondary text-label
|
|
52
|
-
* tracking-label text-muted`, so it never grows past that role whatever the page font size.
|
|
66
|
+
* leading-label tracking-label text-muted`, so it never grows past that role whatever the page font size.
|
|
67
|
+
* - The nav's line box is the library's own rather than the consuming document's: the header leads
|
|
68
|
+
* itself at the label role, so the height it declares for its slot is the height it renders.
|
|
69
|
+
* - The standing slot is floored, never fixed: its minimum height is that same line box - the label
|
|
70
|
+
* role's size times its leading - its minimum width is `--standing-min-width`, and its contents are
|
|
71
|
+
* centred. Standing content inside both floors leaves the bar the same height from route to route,
|
|
72
|
+
* so a place name on one page and a mark on another do not move the shell; content past either floor
|
|
73
|
+
* grows the slot, on one line, and is never clamped or wrapped.
|
|
53
74
|
* - A nav item marked `aria-current="page"` renders at `foreground` whatever supplied it - the treatment
|
|
54
75
|
* keys on the attribute, not on `Link`, so it holds against a bare anchor or any component.
|
|
55
76
|
* - The shell's air is one value above, below and between: `--space-region` vertically and between nav
|
|
@@ -57,6 +78,18 @@ export interface IHeaderProps extends VariantProps<typeof header> {
|
|
|
57
78
|
* - It is never sticky and needs no JavaScript: there is no `sticky` variant and nothing to hydrate.
|
|
58
79
|
* - Omitting `navName` emits no `aria-label` at all, not an empty one.
|
|
59
80
|
*
|
|
81
|
+
* @CallerMustEnsure — the component cannot see these and does not check them
|
|
82
|
+
* - A mark that should *fill* the standing slot is given a **definite width** by whoever placed it -
|
|
83
|
+
* `width: var(--standing-min-width)` on the element wrapping it, so the mark and the floor move
|
|
84
|
+
* together when a theme re-points the token. Measured against a `viewBox`-only SVG, the common
|
|
85
|
+
* shape: it has no intrinsic width to fill from, and `width: 100%` cannot resolve against the slot's
|
|
86
|
+
* indefinite basis - so a mark told to fill that way renders at its intrinsic width instead (300px in
|
|
87
|
+
* a slot floored at 120px, against 120px on the place-name route) and the floor stops governing,
|
|
88
|
+
* which is the jump between routes the floor exists to remove. A definite width holds at any bar
|
|
89
|
+
* width; `flex: 1 1 0; min-width: 0` only collapses the mark when the bar is already out of room, so
|
|
90
|
+
* it is not the rule to reach for. The library cannot apply either rule for you: the same width on a
|
|
91
|
+
* place name would clamp the name and wrap it.
|
|
92
|
+
*
|
|
60
93
|
* @UXGuidelines
|
|
61
94
|
* - Name the nav with `navName` once the page has more than one navigation landmark - a footer nav will
|
|
62
95
|
* be the second, and two unnamed navs are indistinguishable to a screen-reader user.
|
|
@@ -73,7 +106,7 @@ export const Header: FunctionComponent<IHeaderProps> = ({
|
|
|
73
106
|
testId,
|
|
74
107
|
}) => (
|
|
75
108
|
<header className={header({ edge })} data-testid={testId}>
|
|
76
|
-
<div>{standing}</div>
|
|
109
|
+
<div className={standingSlot}>{standing}</div>
|
|
77
110
|
<nav
|
|
78
111
|
aria-label={navName}
|
|
79
112
|
className={'flex flex-wrap items-baseline gap-[var(--space-region)]'}
|
package/src/Layout/Hero/Hero.tsx
CHANGED
|
@@ -2,6 +2,8 @@ import type { VariantProps } from 'class-variance-authority';
|
|
|
2
2
|
import { cva } from 'class-variance-authority';
|
|
3
3
|
import type { FunctionComponent, ReactNode } from 'react';
|
|
4
4
|
|
|
5
|
+
// Not pinned against Stack (#75): the fold height is this component's own, so the base legitimately
|
|
6
|
+
// differs and an equality spec would only forbid a difference that is the point of the component.
|
|
5
7
|
// One recipe on a plain <div>. It holds the fold - a minimum height taller than its content, so leftover
|
|
6
8
|
// space is guaranteed and how the slot sits in it is a decision, not a default (#17). With no className
|
|
7
9
|
// escape hatch, whatever place picks is final, so it is a variant: center is the conventional hero and the
|
|
@@ -52,12 +54,14 @@ export interface IHeroProps extends VariantProps<typeof hero> {
|
|
|
52
54
|
* bleed, the band, the gutter and the region. `Hero` imports no component and adds none of these.
|
|
53
55
|
*
|
|
54
56
|
* @UXGuidelines
|
|
55
|
-
* -
|
|
56
|
-
*
|
|
57
|
-
* 24ch a one-sentence lead set five lines and
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
57
|
+
* - The lead is capped at `--measure-display`, and `H1` is what carries the cap - place one in the slot
|
|
58
|
+
* and the bound comes with it (#87). The slot itself stays uncapped, because capping it would cap the
|
|
59
|
+
* mark too. Measured on the lockup that prompted this: at 24ch a one-sentence lead set five lines and
|
|
60
|
+
* became a second block competing with the mark; at 36ch, where the token sits, it sets three and reads
|
|
61
|
+
* as the mark's caption. This is the one place where copy length is a layout parameter, and the token
|
|
62
|
+
* is one value for the whole product - so a hero whose lead runs longer than that measurement assumed
|
|
63
|
+
* is a reason to re-measure `--measure-display` against the real sentence, which moves every `H1` with
|
|
64
|
+
* it, and never a reason to cap that one hero by hand.
|
|
61
65
|
* - A hero built on a wide lockup is a desktop bet by construction. A 15-character lockup can only be as
|
|
62
66
|
* wide as the phone, so at 390px the scale contrast between mark and lead is capped by the viewport
|
|
63
67
|
* rather than chosen - roughly 2:1, against roughly 6:1 at 1440.
|
|
@@ -10,6 +10,8 @@ import type { FunctionComponent, ReactNode } from 'react';
|
|
|
10
10
|
// literal appears. That tracking is the title role's, not this component's (#57): H2 binds to the same
|
|
11
11
|
// role and carries the same correction, so the role reads one way wherever it is rendered. The stack gap is --space-stack, the sibling gap Prose uses. Colours are semantic
|
|
12
12
|
// tokens re-pointed by `.dark`, so no `dark:` class.
|
|
13
|
+
// Not pinned against Stack (#75): the band and the gutter are the head's own page job, so the base
|
|
14
|
+
// legitimately differs and there is no equality to hold - a Stack carries neither.
|
|
13
15
|
const pageHead = cva(
|
|
14
16
|
'flex flex-col gap-[var(--space-stack)] py-[var(--space-band)] px-[var(--gutter)]',
|
|
15
17
|
);
|
|
@@ -16,6 +16,10 @@ import type { FunctionComponent, ReactNode } from 'react';
|
|
|
16
16
|
// `.dark`, so no `dark:` class.
|
|
17
17
|
const section = cva(
|
|
18
18
|
[
|
|
19
|
+
// Anchor, not placement: a consumer hangs its own decoration off the join, and cannot get an anchor
|
|
20
|
+
// by wrapping the section without costing two joins. No offset and no z-index, so the layout is
|
|
21
|
+
// unchanged and no stacking context forms - decoration at z-index:-1 must still escape to an outer one.
|
|
22
|
+
'relative',
|
|
19
23
|
'py-[var(--space-band)]',
|
|
20
24
|
'[[data-section]+&]:border-t [[data-section]+&]:border-solid [[data-section]+&]:border-rule',
|
|
21
25
|
].join(' '),
|
|
@@ -51,10 +55,17 @@ export interface ISectionProps extends VariantProps<typeof section> {
|
|
|
51
55
|
* - A `bleed="full"` section drops the gutter and runs edge to edge; the vertical band is kept on both
|
|
52
56
|
* bleed variants, and the join spans the full width of either.
|
|
53
57
|
* - An unnamed section is not a landmark: it emits no `aria-label` and is inert to assistive technology.
|
|
58
|
+
* - The section is a positioning context, under either bleed, so a consumer may place absolutely-positioned
|
|
59
|
+
* decoration against its edges - including the join above it, the one edge only a section knows. It sets
|
|
60
|
+
* no offset and no `z-index`, so it is not a stacking context and decoration at a negative `z-index`
|
|
61
|
+
* still resolves against an outer one.
|
|
54
62
|
*
|
|
55
63
|
* @CallerMustEnsure
|
|
56
64
|
* - Where `name` is given it matches the section's visible heading. The component labels the region with
|
|
57
65
|
* that string because it cannot reach the heading's id to reference it with `aria-labelledby` instead.
|
|
66
|
+
* - A descendant meant to position against an ancestor *outside* the section is given its own positioned
|
|
67
|
+
* wrapper, since the section is now the nearer positioned ancestor and takes the anchor. The
|
|
68
|
+
* re-anchoring is silent - no error and no warning, only a descendant that lands somewhere else.
|
|
58
69
|
*
|
|
59
70
|
* @UXGuidelines
|
|
60
71
|
* - On a page with no borrowed proof - no logos, no testimonials, no credits - a gap between blocks reads
|
package/src/Theme/Palette.ts
CHANGED
|
@@ -39,15 +39,36 @@ export type PaletteTokens = {
|
|
|
39
39
|
* keeps it near `surface` rather than a mid grey. */
|
|
40
40
|
backing: string;
|
|
41
41
|
|
|
42
|
-
/** The main call-to-action fill.
|
|
42
|
+
/** The main call-to-action fill. A filled control draws no border, so the fill is the only thing
|
|
43
|
+
* separating the control from the surface - what `controlBorder` is for an unfilled one.
|
|
44
|
+
* Constraint (WCAG 2.2 SC 1.4.11): at least 3:1 against `surface` in the same theme,
|
|
45
|
+
* `primaryHover` included, since a hovered control has to stay identifiable too. A second
|
|
46
|
+
* constraint governs this value and `primaryHover` from the other side, stated on
|
|
47
|
+
* `primaryForeground` - the ink they carry - rather than restated here. */
|
|
43
48
|
primary: string;
|
|
44
49
|
primaryHover: string;
|
|
45
|
-
/** Text and icons drawn on top of `primary`.
|
|
50
|
+
/** Text and icons drawn on top of `primary`. Constraint (WCAG 2.2 SC 1.4.3): at least 4.5:1
|
|
51
|
+
* against both `primary` and `primaryHover` in the same theme, hover included, since a hovered
|
|
52
|
+
* control has to stay readable too. Button text is normal-weight at the `body` role, so it takes
|
|
53
|
+
* the text threshold rather than the 3:1 large-text allowance. This is what makes the ink follow
|
|
54
|
+
* the theme where the fills' own roles do not: a fill light enough to clear 3:1 against a dark
|
|
55
|
+
* surface is too light to carry near-white text, so the ink sits at the *surface's* end of the
|
|
56
|
+
* neutral range in each theme. Not required against `disabled` or `disabledHover` - a disabled
|
|
57
|
+
* control is an inactive user interface component, which SC 1.4.3 exempts. */
|
|
46
58
|
primaryForeground: string;
|
|
47
59
|
|
|
48
|
-
/** The alternative action fill, for choices that sit beside a primary one.
|
|
60
|
+
/** The alternative action fill, for choices that sit beside a primary one. Filled like `primary`
|
|
61
|
+
* and so identified the same way. Constraint (WCAG 2.2 SC 1.4.11): at least 3:1 against
|
|
62
|
+
* `surface` in the same theme, `secondaryHover` included. A second constraint governs this value
|
|
63
|
+
* and `secondaryHover` from the other side, stated on `secondaryForeground`. */
|
|
49
64
|
secondary: string;
|
|
50
65
|
secondaryHover: string;
|
|
66
|
+
/** Text and icons drawn on top of `secondary`. Constraint (WCAG 2.2 SC 1.4.3): at least 4.5:1
|
|
67
|
+
* against both `secondary` and `secondaryHover` in the same theme, hover included, since a
|
|
68
|
+
* hovered control has to stay readable too. Not required against `disabled` or `disabledHover` -
|
|
69
|
+
* a disabled control is an inactive user interface component, which SC 1.4.3 exempts. Why the
|
|
70
|
+
* threshold is 4.5 and not 3, and why this makes the ink follow the theme: see
|
|
71
|
+
* `primaryForeground`, which carries the same rule for the other ramp. */
|
|
51
72
|
secondaryForeground: string;
|
|
52
73
|
|
|
53
74
|
/** The tone a control takes when it cannot be interacted with - its fill, or its border when
|
|
@@ -75,6 +96,25 @@ export type PaletteTokens = {
|
|
|
75
96
|
info: string;
|
|
76
97
|
};
|
|
77
98
|
|
|
99
|
+
/**
|
|
100
|
+
* The ink follows the theme, and that is what set the eight fill and ink values across both sets
|
|
101
|
+
* (issue #93). Solve the window a fill has to sit in - at least 3:1 against its surface (#78) and
|
|
102
|
+
* at least 4.5:1 against the ink drawn on it - and it comes out lopsided: a near-white ink is
|
|
103
|
+
* unbounded above in light and leaves a window just 1.26x wide in dark, and a near-black ink is the
|
|
104
|
+
* exact inverse. The reason is structural - in a dark theme a fill has to be light enough to
|
|
105
|
+
* separate from a near-black surface, and a light fill wants dark text - so pinning the ink
|
|
106
|
+
* near-white in both themes asks a dark fill to be both at once. That 1.26x has to hold two values,
|
|
107
|
+
* rest and hover, where what shipped before it stepped 1.35x and 1.23x here and 1.35x and 1.48x in
|
|
108
|
+
* dark. Letting the ink invert instead puts every value on a stock ramp step, with hover steps of
|
|
109
|
+
* 1.25x and 1.27x here and 1.56x and 1.48x in dark.
|
|
110
|
+
*
|
|
111
|
+
* Two routes were rejected, and they are what a reader arriving here is most likely to re-propose:
|
|
112
|
+
* - Keep one near-white ink in both themes and move the fills. It clears 4.5:1, but caps the dark
|
|
113
|
+
* hover at that same 1.26x - gutting the state #78 constrained hover in order to keep.
|
|
114
|
+
* - Give each ramp its own ink, the same in both themes. It clears 4.5:1 only against pure black:
|
|
115
|
+
* against `#0f172a`, the dark set's own `surface`, sky-600 lands at 4.36 and fails. It also buys
|
|
116
|
+
* a light theme with white text on one button and black on the one beside it.
|
|
117
|
+
*/
|
|
78
118
|
export const light: PaletteTokens = {
|
|
79
119
|
surface: '#ffffff',
|
|
80
120
|
foreground: '#0f172a',
|
|
@@ -84,12 +124,12 @@ export const light: PaletteTokens = {
|
|
|
84
124
|
rule: '#808fa3',
|
|
85
125
|
backing: '#f1f5f9',
|
|
86
126
|
|
|
87
|
-
primary: '#
|
|
88
|
-
primaryHover: '#
|
|
127
|
+
primary: '#7c3aed',
|
|
128
|
+
primaryHover: '#6d28d9',
|
|
89
129
|
primaryForeground: '#f8fafc',
|
|
90
130
|
|
|
91
|
-
secondary: '#
|
|
92
|
-
secondaryHover: '#
|
|
131
|
+
secondary: '#0369a1',
|
|
132
|
+
secondaryHover: '#075985',
|
|
93
133
|
secondaryForeground: '#f8fafc',
|
|
94
134
|
|
|
95
135
|
disabled: '#94a3b8',
|
|
@@ -106,10 +146,19 @@ export const light: PaletteTokens = {
|
|
|
106
146
|
};
|
|
107
147
|
|
|
108
148
|
/**
|
|
109
|
-
* Dark reverses the
|
|
110
|
-
*
|
|
149
|
+
* Dark reverses the direction the fills step: it sits higher up the ramp than light does and hovers
|
|
150
|
+
* *up* into lighter still, where light sits lower and hovers down. That is what the components' old
|
|
111
151
|
* `dark:bg-primary-600 dark:hover:bg-primary-500` pair encoded, moved here so it is stated once
|
|
112
|
-
* for the whole system instead of repeated per component.
|
|
152
|
+
* for the whole system instead of repeated per component. The two sets no longer share a step, since
|
|
153
|
+
* each theme's pair has to clear its own ink as well as its own surface (issue #93).
|
|
154
|
+
*
|
|
155
|
+
* The ink inverts with the ramp: slate-950 under these lighter fills, where light takes slate-50
|
|
156
|
+
* under its darker ones. The pair is the two ends of the one neutral ramp the rest of the palette is
|
|
157
|
+
* already built from - `#f8fafc` is slate-50, `surface` slate-900, `muted` slate-500 - rather than a
|
|
158
|
+
* new colour arriving for a single job. `#020617` is also the lightest slate step that still admits
|
|
159
|
+
* violet-500 and sky-600, which is what leaves this set's `secondary` pair unmoved: slate-900 draws
|
|
160
|
+
* 4.22 and 4.36 against them and fails. Why the ink follows the theme at all, and the two routes
|
|
161
|
+
* rejected in getting here: see the light set.
|
|
113
162
|
*/
|
|
114
163
|
export const dark: PaletteTokens = {
|
|
115
164
|
surface: '#0f172a',
|
|
@@ -120,13 +169,13 @@ export const dark: PaletteTokens = {
|
|
|
120
169
|
rule: '#5b6a80',
|
|
121
170
|
backing: '#1e293b',
|
|
122
171
|
|
|
123
|
-
primary: '#
|
|
124
|
-
primaryHover: '#
|
|
125
|
-
primaryForeground: '#
|
|
172
|
+
primary: '#8b5cf6',
|
|
173
|
+
primaryHover: '#a78bfa',
|
|
174
|
+
primaryForeground: '#020617',
|
|
126
175
|
|
|
127
176
|
secondary: '#0284c7',
|
|
128
177
|
secondaryHover: '#0ea5e9',
|
|
129
|
-
secondaryForeground: '#
|
|
178
|
+
secondaryForeground: '#020617',
|
|
130
179
|
|
|
131
180
|
disabled: '#475569',
|
|
132
181
|
disabledHover: '#334155',
|
|
@@ -61,6 +61,14 @@ const CONTROL_MIN_WIDTH = `:root {
|
|
|
61
61
|
--control-min-width: 10.5rem;
|
|
62
62
|
}`;
|
|
63
63
|
|
|
64
|
+
/* The shell's standing slot claims a width, and that is what this names: how much of the bar the
|
|
65
|
+
slot takes, never how wide any drawing is - a slot role, so Brandmark keeps setting no dimension of
|
|
66
|
+
its own (.out-of-scope/brandmark-size-vocabulary.md). Not a colour and no Tailwind namespace, so it
|
|
67
|
+
sits in :root beside the control minimum width. 7.5rem is the one attested value, measured in #81. */
|
|
68
|
+
const STANDING_MIN_WIDTH = `:root {
|
|
69
|
+
--standing-min-width: 7.5rem;
|
|
70
|
+
}`;
|
|
71
|
+
|
|
64
72
|
/* The library's underline is not a colour: like the focus-ring dimensions it lives in :root only,
|
|
65
73
|
never @theme inline. Not prose's alone - every Link treatment that draws a line draws it from these.
|
|
66
74
|
Constraint: --underline-thickness-hover > --underline-thickness (the thicken on hover is the only
|
|
@@ -102,11 +110,17 @@ const TYPOGRAPHY = `@theme {
|
|
|
102
110
|
subtitle was rejected in ADR 0004 - it welds the lede's size to H3's and its leading to a head's. */
|
|
103
111
|
--text-lede: 1.25rem; /* 20px */
|
|
104
112
|
--leading-lede: 1.4;
|
|
105
|
-
--text-body: 1.0625rem; /* 17px */
|
|
113
|
+
--text-body: 1.0625rem; /* 17px, floored at 16px: below it iOS Safari zooms the viewport when a control set at this role takes focus (#92) */
|
|
106
114
|
--leading-body: 1.6;
|
|
107
115
|
--text-small: 0.9375rem; /* 15px floor: below it tabular figures stop comparing column to column */
|
|
108
116
|
--text-label: 0.8125rem; /* 13px floor: below it the tracking reads as damage, not a device */
|
|
109
117
|
|
|
118
|
+
/* The label role's leading, declared standalone and deliberately not paired into text-label's
|
|
119
|
+
utility: pairing would move every existing label site's line box at once, silently. A component
|
|
120
|
+
whose own height is measured against its labels reads leading-label explicitly (Header #81). 1.5
|
|
121
|
+
is the line height SC 1.4.12 expects text to survive, so a user stylesheet applying it moves nothing. */
|
|
122
|
+
--leading-label: 1.5;
|
|
123
|
+
|
|
110
124
|
/* Two quantities on one property that must not collapse: --tracking-label is a fixed letter-spaced
|
|
111
125
|
style, --tracking-optical a correction that varies with size. The names say which is which, so the
|
|
112
126
|
distinction survives without the ADR in hand. Scope: the title role and above - H1, H2 and the page
|
|
@@ -225,6 +239,9 @@ ${RADIUS}
|
|
|
225
239
|
/* The control minimum width is not a colour either, and sits in :root beside radius. */
|
|
226
240
|
${CONTROL_MIN_WIDTH}
|
|
227
241
|
|
|
242
|
+
/* The standing slot's minimum width is not a colour either, and sits in :root beside the control one. */
|
|
243
|
+
${STANDING_MIN_WIDTH}
|
|
244
|
+
|
|
228
245
|
/* The library's underline dimensions are not colours either, and sit in :root beside radius. They are
|
|
229
246
|
not prose's alone: every Link treatment that draws a line draws it from these (docs/adr/0006). */
|
|
230
247
|
${UNDERLINE}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import './styles.css';
|
|
2
2
|
|
|
3
|
+
export { Cluster } from 'Arrangement/Cluster/Cluster';
|
|
4
|
+
export { Stack } from 'Arrangement/Stack/Stack';
|
|
3
5
|
export { Brandmark } from 'Display/Brandmark/Brandmark';
|
|
4
6
|
export { Checklist } from 'Display/Checklist/Checklist';
|
|
5
7
|
export { DefinitionList } from 'Display/DefinitionList/DefinitionList';
|
|
@@ -13,6 +15,7 @@ export { H3 } from 'Display/Typography/H3/H3';
|
|
|
13
15
|
export { H4 } from 'Display/Typography/H4/H4';
|
|
14
16
|
export { H5 } from 'Display/Typography/H5/H5';
|
|
15
17
|
export { H6 } from 'Display/Typography/H6/H6';
|
|
18
|
+
export { Note } from 'Display/Typography/Note/Note';
|
|
16
19
|
export { P } from 'Display/Typography/P/P';
|
|
17
20
|
export { Prose } from 'Display/Typography/Prose/Prose';
|
|
18
21
|
export { Button } from 'Interaction/Button/Button';
|
package/src/tokens.css
CHANGED
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
--color-control-border: #64748b;
|
|
18
18
|
--color-rule: #808fa3;
|
|
19
19
|
--color-backing: #f1f5f9;
|
|
20
|
-
--color-primary: #
|
|
21
|
-
--color-primary-hover: #
|
|
20
|
+
--color-primary: #7c3aed;
|
|
21
|
+
--color-primary-hover: #6d28d9;
|
|
22
22
|
--color-primary-foreground: #f8fafc;
|
|
23
|
-
--color-secondary: #
|
|
24
|
-
--color-secondary-hover: #
|
|
23
|
+
--color-secondary: #0369a1;
|
|
24
|
+
--color-secondary-hover: #075985;
|
|
25
25
|
--color-secondary-foreground: #f8fafc;
|
|
26
26
|
--color-disabled: #94a3b8;
|
|
27
27
|
--color-disabled-hover: #64748b;
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
--color-control-border: #94a3b8;
|
|
42
42
|
--color-rule: #5b6a80;
|
|
43
43
|
--color-backing: #1e293b;
|
|
44
|
-
--color-primary: #
|
|
45
|
-
--color-primary-hover: #
|
|
46
|
-
--color-primary-foreground: #
|
|
44
|
+
--color-primary: #8b5cf6;
|
|
45
|
+
--color-primary-hover: #a78bfa;
|
|
46
|
+
--color-primary-foreground: #020617;
|
|
47
47
|
--color-secondary: #0284c7;
|
|
48
48
|
--color-secondary-hover: #0ea5e9;
|
|
49
|
-
--color-secondary-foreground: #
|
|
49
|
+
--color-secondary-foreground: #020617;
|
|
50
50
|
--color-disabled: #475569;
|
|
51
51
|
--color-disabled-hover: #334155;
|
|
52
52
|
--color-focus-ring: var(--color-ring, #cbd5e1);
|
|
@@ -110,6 +110,11 @@
|
|
|
110
110
|
--control-min-width: 10.5rem;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/* The standing slot's minimum width is not a colour either, and sits in :root beside the control one. */
|
|
114
|
+
:root {
|
|
115
|
+
--standing-min-width: 7.5rem;
|
|
116
|
+
}
|
|
117
|
+
|
|
113
118
|
/* The library's underline dimensions are not colours either, and sit in :root beside radius. They are
|
|
114
119
|
not prose's alone: every Link treatment that draws a line draws it from these (docs/adr/0006). */
|
|
115
120
|
:root {
|
|
@@ -144,11 +149,17 @@
|
|
|
144
149
|
subtitle was rejected in ADR 0004 - it welds the lede's size to H3's and its leading to a head's. */
|
|
145
150
|
--text-lede: 1.25rem; /* 20px */
|
|
146
151
|
--leading-lede: 1.4;
|
|
147
|
-
--text-body: 1.0625rem; /* 17px */
|
|
152
|
+
--text-body: 1.0625rem; /* 17px, floored at 16px: below it iOS Safari zooms the viewport when a control set at this role takes focus (#92) */
|
|
148
153
|
--leading-body: 1.6;
|
|
149
154
|
--text-small: 0.9375rem; /* 15px floor: below it tabular figures stop comparing column to column */
|
|
150
155
|
--text-label: 0.8125rem; /* 13px floor: below it the tracking reads as damage, not a device */
|
|
151
156
|
|
|
157
|
+
/* The label role's leading, declared standalone and deliberately not paired into text-label's
|
|
158
|
+
utility: pairing would move every existing label site's line box at once, silently. A component
|
|
159
|
+
whose own height is measured against its labels reads leading-label explicitly (Header #81). 1.5
|
|
160
|
+
is the line height SC 1.4.12 expects text to survive, so a user stylesheet applying it moves nothing. */
|
|
161
|
+
--leading-label: 1.5;
|
|
162
|
+
|
|
152
163
|
/* Two quantities on one property that must not collapse: --tracking-label is a fixed letter-spaced
|
|
153
164
|
style, --tracking-optical a correction that varies with size. The names say which is which, so the
|
|
154
165
|
distinction survives without the ADR in hand. Scope: the title role and above - H1, H2 and the page
|
package/src/tokens.dark.css
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
--color-control-border: #94a3b8;
|
|
13
13
|
--color-rule: #5b6a80;
|
|
14
14
|
--color-backing: #1e293b;
|
|
15
|
-
--color-primary: #
|
|
16
|
-
--color-primary-hover: #
|
|
17
|
-
--color-primary-foreground: #
|
|
15
|
+
--color-primary: #8b5cf6;
|
|
16
|
+
--color-primary-hover: #a78bfa;
|
|
17
|
+
--color-primary-foreground: #020617;
|
|
18
18
|
--color-secondary: #0284c7;
|
|
19
19
|
--color-secondary-hover: #0ea5e9;
|
|
20
|
-
--color-secondary-foreground: #
|
|
20
|
+
--color-secondary-foreground: #020617;
|
|
21
21
|
--color-disabled: #475569;
|
|
22
22
|
--color-disabled-hover: #334155;
|
|
23
23
|
--color-focus-ring: var(--color-ring, #cbd5e1);
|
|
@@ -81,6 +81,11 @@
|
|
|
81
81
|
--control-min-width: 10.5rem;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/* The standing slot's minimum width is not a colour either, and sits in :root beside the control one. */
|
|
85
|
+
:root {
|
|
86
|
+
--standing-min-width: 7.5rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
84
89
|
/* The library's underline dimensions are not colours either, and sit in :root beside radius. They are
|
|
85
90
|
not prose's alone: every Link treatment that draws a line draws it from these (docs/adr/0006). */
|
|
86
91
|
:root {
|
|
@@ -115,11 +120,17 @@
|
|
|
115
120
|
subtitle was rejected in ADR 0004 - it welds the lede's size to H3's and its leading to a head's. */
|
|
116
121
|
--text-lede: 1.25rem; /* 20px */
|
|
117
122
|
--leading-lede: 1.4;
|
|
118
|
-
--text-body: 1.0625rem; /* 17px */
|
|
123
|
+
--text-body: 1.0625rem; /* 17px, floored at 16px: below it iOS Safari zooms the viewport when a control set at this role takes focus (#92) */
|
|
119
124
|
--leading-body: 1.6;
|
|
120
125
|
--text-small: 0.9375rem; /* 15px floor: below it tabular figures stop comparing column to column */
|
|
121
126
|
--text-label: 0.8125rem; /* 13px floor: below it the tracking reads as damage, not a device */
|
|
122
127
|
|
|
128
|
+
/* The label role's leading, declared standalone and deliberately not paired into text-label's
|
|
129
|
+
utility: pairing would move every existing label site's line box at once, silently. A component
|
|
130
|
+
whose own height is measured against its labels reads leading-label explicitly (Header #81). 1.5
|
|
131
|
+
is the line height SC 1.4.12 expects text to survive, so a user stylesheet applying it moves nothing. */
|
|
132
|
+
--leading-label: 1.5;
|
|
133
|
+
|
|
123
134
|
/* Two quantities on one property that must not collapse: --tracking-label is a fixed letter-spaced
|
|
124
135
|
style, --tracking-optical a correction that varies with size. The names say which is which, so the
|
|
125
136
|
distinction survives without the ADR in hand. Scope: the title role and above - H1, H2 and the page
|
package/src/tokens.light.css
CHANGED
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
--color-control-border: #64748b;
|
|
13
13
|
--color-rule: #808fa3;
|
|
14
14
|
--color-backing: #f1f5f9;
|
|
15
|
-
--color-primary: #
|
|
16
|
-
--color-primary-hover: #
|
|
15
|
+
--color-primary: #7c3aed;
|
|
16
|
+
--color-primary-hover: #6d28d9;
|
|
17
17
|
--color-primary-foreground: #f8fafc;
|
|
18
|
-
--color-secondary: #
|
|
19
|
-
--color-secondary-hover: #
|
|
18
|
+
--color-secondary: #0369a1;
|
|
19
|
+
--color-secondary-hover: #075985;
|
|
20
20
|
--color-secondary-foreground: #f8fafc;
|
|
21
21
|
--color-disabled: #94a3b8;
|
|
22
22
|
--color-disabled-hover: #64748b;
|
|
@@ -81,6 +81,11 @@
|
|
|
81
81
|
--control-min-width: 10.5rem;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/* The standing slot's minimum width is not a colour either, and sits in :root beside the control one. */
|
|
85
|
+
:root {
|
|
86
|
+
--standing-min-width: 7.5rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
84
89
|
/* The library's underline dimensions are not colours either, and sit in :root beside radius. They are
|
|
85
90
|
not prose's alone: every Link treatment that draws a line draws it from these (docs/adr/0006). */
|
|
86
91
|
:root {
|
|
@@ -115,11 +120,17 @@
|
|
|
115
120
|
subtitle was rejected in ADR 0004 - it welds the lede's size to H3's and its leading to a head's. */
|
|
116
121
|
--text-lede: 1.25rem; /* 20px */
|
|
117
122
|
--leading-lede: 1.4;
|
|
118
|
-
--text-body: 1.0625rem; /* 17px */
|
|
123
|
+
--text-body: 1.0625rem; /* 17px, floored at 16px: below it iOS Safari zooms the viewport when a control set at this role takes focus (#92) */
|
|
119
124
|
--leading-body: 1.6;
|
|
120
125
|
--text-small: 0.9375rem; /* 15px floor: below it tabular figures stop comparing column to column */
|
|
121
126
|
--text-label: 0.8125rem; /* 13px floor: below it the tracking reads as damage, not a device */
|
|
122
127
|
|
|
128
|
+
/* The label role's leading, declared standalone and deliberately not paired into text-label's
|
|
129
|
+
utility: pairing would move every existing label site's line box at once, silently. A component
|
|
130
|
+
whose own height is measured against its labels reads leading-label explicitly (Header #81). 1.5
|
|
131
|
+
is the line height SC 1.4.12 expects text to survive, so a user stylesheet applying it moves nothing. */
|
|
132
|
+
--leading-label: 1.5;
|
|
133
|
+
|
|
123
134
|
/* Two quantities on one property that must not collapse: --tracking-label is a fixed letter-spaced
|
|
124
135
|
style, --tracking-optical a correction that varies with size. The names say which is which, so the
|
|
125
136
|
distinction survives without the ADR in hand. Scope: the title role and above - H1, H2 and the page
|