@tristan2828/ui-foundation 3.26.0 → 3.27.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/conventions/docs/design-language.md +33 -24
- package/package.json +1 -1
- package/styles/theme.css +42 -46
|
@@ -125,30 +125,38 @@ that lets people pick a colour stores the slot's name (an enum of
|
|
|
125
125
|
`category-1` … `category-12` in its contract, with a CHECK on the column)
|
|
126
126
|
and maps each to its whole class the same way.
|
|
127
127
|
|
|
128
|
-
|
|
|
129
|
-
|
|
130
|
-
| 1
|
|
131
|
-
|
|
|
128
|
+
| Slot | Colour | Slot | Colour |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| 1 | blue (near info) | 7 | teal |
|
|
131
|
+
| 2 | orange | 8 | red |
|
|
132
|
+
| 3 | green | 9 | gold |
|
|
133
|
+
| 4 | purple | 10 | navy |
|
|
134
|
+
| 5 | pink | 11 | lime |
|
|
135
|
+
| 6 | brown | 12 | magenta |
|
|
136
|
+
|
|
137
|
+
Every slot is a colour with its own name: no two blues, no two teals. So
|
|
138
|
+
in a picker, label each with its name ("Orange"), not its number.
|
|
132
139
|
|
|
133
140
|
Five things about them:
|
|
134
141
|
|
|
135
|
-
- **
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
142
|
+
- **Chosen to be told apart, not spaced by hue.** They use the whole hue
|
|
143
|
+
circle and vary lightness and chroma as well, so a light lime sits next
|
|
144
|
+
to a deep navy rather than two mid-tone hues 25° apart. Every pair is at
|
|
145
|
+
least 17.9 apart in CIEDE2000 ΔE (the perceived difference; 10 and up
|
|
146
|
+
reads as a different colour), in both themes. A unit test holds every
|
|
147
|
+
pair to 15.
|
|
148
|
+
- **A category is not a tone.** Red, orange, brown and green are slots
|
|
149
|
+
because a category is a tinted glyph beside its name, never a status
|
|
150
|
+
badge, and doesn't read as good or bad there. Where it still could, keep
|
|
151
|
+
them apart: a column that shows tone badges doesn't tint its categories
|
|
152
|
+
in the same column, and a table that shows an info badge keeps its
|
|
153
|
+
categories off slot 1, the one near info's blue.
|
|
154
|
+
- **They are ordered for small sets.** An app using the first few gets the
|
|
155
|
+
most separable few, for everyone: the first six also stay apart (ΔE 10
|
|
156
|
+
or more, tested) for readers with deuteranopia or protanopia, the common
|
|
157
|
+
red-green deficiencies. Past six, some pairs merge for those readers
|
|
158
|
+
(gold and lime are nearly one colour), so the glyph and the name carry
|
|
159
|
+
the meaning and the colour only reinforces it.
|
|
152
160
|
- **Tint the glyph, never fill behind text.** The label stays
|
|
153
161
|
`text-foreground`, so readability never depends on the hue. A slot used
|
|
154
162
|
as a background needs its own contrast check, which nothing here does
|
|
@@ -157,12 +165,13 @@ Five things about them:
|
|
|
157
165
|
non-text minimum in both themes, on the page and on a card (recorded in
|
|
158
166
|
`theme.css`). axe checks text contrast, not icon contrast, so the
|
|
159
167
|
package's Storybook glyph check draws an icon in each slot on both
|
|
160
|
-
surfaces (`patterns/CategoricalColour
|
|
161
|
-
|
|
168
|
+
surfaces (`patterns/CategoricalColour`) and fails a change that takes
|
|
169
|
+
one below 3:1. Its `SideBySide` story shows both themes at once, under
|
|
170
|
+
normal vision and simulated deuteranopia and protanopia.
|
|
162
171
|
|
|
163
172
|
If you find yourself wanting a thirteenth, that is a sign the column should
|
|
164
173
|
be showing a shape or a label rather than more colours: there is no more
|
|
165
|
-
room
|
|
174
|
+
room that stays readable.
|
|
166
175
|
|
|
167
176
|
## Typography
|
|
168
177
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tristan2828/ui-foundation",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.27.0",
|
|
4
4
|
"description": "Shared UI foundation for contract-first, database-backed React apps: shadcn primitives, DataTable/EntityForm composites, auth, the gateway error seam, design tokens, lint rules and the AI playbook.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/styles/theme.css
CHANGED
|
@@ -66,54 +66,50 @@
|
|
|
66
66
|
* to a slot in its own columns file, so a new enum value costs a line
|
|
67
67
|
* there rather than three tokens here.
|
|
68
68
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
69
|
+
* Chosen to be told apart (#108), not spaced by hue: twelve colours a
|
|
70
|
+
* person names differently, from the whole hue circle, with lightness and
|
|
71
|
+
* chroma varied per slot as well as hue. Red, orange, brown and green are
|
|
72
|
+
* in: a category is a tinted glyph beside its name, never a status badge,
|
|
73
|
+
* so it doesn't read as a tone (design-language.md says where that still
|
|
74
|
+
* matters). Slot 1 (blue) sits near info's hue; a table using info keeps
|
|
75
|
+
* its categories off it.
|
|
76
76
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
--category-3-400: oklch(0.78 0.12 95);
|
|
89
|
-
--category-4-700: oklch(0.5 0.15 190);
|
|
90
|
-
--category-4-400: oklch(0.78 0.12 190);
|
|
91
|
-
--category-5-700: oklch(0.5 0.15 330);
|
|
92
|
-
--category-5-400: oklch(0.78 0.12 330);
|
|
93
|
-
--category-6-700: oklch(0.5 0.15 265);
|
|
94
|
-
--category-6-400: oklch(0.78 0.12 265);
|
|
95
|
-
--category-7-700: oklch(0.5 0.15 120);
|
|
96
|
-
--category-7-400: oklch(0.78 0.12 120);
|
|
97
|
-
--category-8-700: oklch(0.5 0.15 215);
|
|
98
|
-
--category-8-400: oklch(0.78 0.12 215);
|
|
99
|
-
/*
|
|
100
|
-
* Slots 9-12 are a second channel, not new hues: the hues left between
|
|
101
|
-
* the tones' are already spent ~25 degrees apart, so these are deeper
|
|
102
|
-
* shades of the four that sit furthest from info (teal, plum, olive,
|
|
103
|
-
* violet), darker than their slot in both themes. Each is at least as
|
|
104
|
-
* far from its nearest slot (OKLab distance) as slots 1-8 are from each
|
|
105
|
-
* other; tests/category-slots.test.ts holds every pair to that. A deep
|
|
106
|
-
* shade of the blues or the yellow-green fell to half that distance, so
|
|
107
|
-
* twelve is where it stops. Chroma is the most each holds in sRGB.
|
|
77
|
+
* Every pair is at least 17.9 apart in CIEDE2000 ΔE in both themes (the
|
|
78
|
+
* hue-spaced slots before them got to 8.8); tests/category-slots.test.ts
|
|
79
|
+
* holds every pair to 15. They are ordered so the first few stay apart
|
|
80
|
+
* under deuteranopia and protanopia too (the first six are 12 apart);
|
|
81
|
+
* past that, the glyph has to carry the meaning for those readers.
|
|
82
|
+
*
|
|
83
|
+
* Ratios are against the page, measured (WCAG 2.x, sRGB): all clear the
|
|
84
|
+
* 3:1 non-text minimum in both themes (3.75:1 at the least, orange and
|
|
85
|
+
* teal on white). axe does NOT check icon contrast; the Storybook glyph
|
|
86
|
+
* check re-measures every slot on the page and on a card
|
|
87
|
+
* (patterns/CategoricalColour).
|
|
108
88
|
*/
|
|
109
|
-
--category-
|
|
110
|
-
--category-
|
|
111
|
-
--category-
|
|
112
|
-
--category-
|
|
113
|
-
--category-
|
|
114
|
-
--category-
|
|
115
|
-
--category-
|
|
116
|
-
--category-
|
|
89
|
+
--category-1-700: oklch(0.44 0.11 245); /* blue */
|
|
90
|
+
--category-1-400: oklch(0.626 0.156 245);
|
|
91
|
+
--category-2-700: oklch(0.627 0.161 52); /* orange */
|
|
92
|
+
--category-2-400: oklch(0.722 0.16 52);
|
|
93
|
+
--category-3-700: oklch(0.492 0.105 152); /* green */
|
|
94
|
+
--category-3-400: oklch(0.763 0.17 152);
|
|
95
|
+
--category-4-700: oklch(0.55 0.254 305); /* purple */
|
|
96
|
+
--category-4-400: oklch(0.772 0.116 305);
|
|
97
|
+
--category-5-700: oklch(0.615 0.144 7); /* pink */
|
|
98
|
+
--category-5-400: oklch(0.812 0.102 7);
|
|
99
|
+
--category-6-700: oklch(0.445 0.1 56); /* brown */
|
|
100
|
+
--category-6-400: oklch(0.602 0.054 56);
|
|
101
|
+
--category-7-700: oklch(0.599 0.104 183); /* teal */
|
|
102
|
+
--category-7-400: oklch(0.849 0.139 183);
|
|
103
|
+
--category-8-700: oklch(0.503 0.176 27); /* red */
|
|
104
|
+
--category-8-400: oklch(0.646 0.152 27);
|
|
105
|
+
--category-9-700: oklch(0.573 0.115 84); /* gold */
|
|
106
|
+
--category-9-400: oklch(0.87 0.136 84);
|
|
107
|
+
--category-10-700: oklch(0.362 0.203 279); /* navy */
|
|
108
|
+
--category-10-400: oklch(0.601 0.164 279);
|
|
109
|
+
--category-11-700: oklch(0.593 0.121 119); /* lime */
|
|
110
|
+
--category-11-400: oklch(0.823 0.163 119);
|
|
111
|
+
--category-12-700: oklch(0.423 0.181 337); /* magenta */
|
|
112
|
+
--category-12-400: oklch(0.648 0.232 337);
|
|
117
113
|
--blue-500: oklch(0.488 0.243 264.376);
|
|
118
114
|
|
|
119
115
|
--radius-base: 0.625rem;
|