@crewlethq/tokens 0.5.8 → 0.6.1
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 +92 -68
- package/dist/css/themes.css +170 -170
- package/dist/css/tokens.css +7 -7
- package/dist/themes.d.ts +109 -109
- package/dist/themes.js +109 -109
- package/package.json +1 -1
- package/test/palette.d.mts +12 -0
- package/test/palette.mjs +88 -37
- package/test/palette.test.mjs +81 -41
package/test/palette.mjs
CHANGED
|
@@ -74,7 +74,7 @@ export const OPAQUE_SURFACES = [
|
|
|
74
74
|
* - THE SHEET OVER THE FRAME is the whole layering device: a content sheet
|
|
75
75
|
* floating inside the application ground. At dE 3, the floor this file holds
|
|
76
76
|
* every "can a reader notice it" difference to, the sheet reads as a
|
|
77
|
-
* separate plane; the approved dark sheet, #
|
|
77
|
+
* separate plane; the approved dark sheet, #0c0e15, measured 2.96 and was
|
|
78
78
|
* nudged to clear it.
|
|
79
79
|
* - A CARD OVER THE SHEET is deliberately near-flat, dE 1.5, because a card is
|
|
80
80
|
* found by its HAIRLINE rather than by its fill: a page of cards each lifted
|
|
@@ -105,16 +105,28 @@ export const RUNG_STEPS = [
|
|
|
105
105
|
export const CARD_HAIRLINE = ['--color-border-default', '--color-surface-subtle', '--color-surface-background'];
|
|
106
106
|
export const HAIRLINE_DE = 3;
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* A chip drawn on the raised rung inside the strong hairline, as [fill,
|
|
110
|
+
* edge]: the neutral pill, and a key cap. Its fill IS raised, so on a raised
|
|
111
|
+
* ground (a lead block, a raised card, the rail's current row) the fill alone
|
|
112
|
+
* draws nothing, and what finds the chip is its edge. So the chip's boundary,
|
|
113
|
+
* the fill or the edge, whichever stands further off its ground, is held to
|
|
114
|
+
* HAIRLINE_DE on every ground it can land on: each opaque rung, and each
|
|
115
|
+
* overlay a hovered, pressed or inset row composites onto one. A component
|
|
116
|
+
* suite holds the chip to drawing this pair; this is what keeps a palette
|
|
117
|
+
* from taking the edge away.
|
|
118
|
+
*/
|
|
119
|
+
export const RAISED_CHIP = ['--color-surface-elevated', '--color-border-strong'];
|
|
120
|
+
|
|
108
121
|
/**
|
|
109
122
|
* THE OVERLAY STEPS HAVE TO BE SEEN, on every rung.
|
|
110
123
|
*
|
|
111
|
-
* A translucent overlay is one alpha on four grounds, and
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
* 0.60 off the frame. This is the floor that stops it. A hovered row separates
|
|
124
|
+
* A translucent overlay is one alpha on four grounds, and a stronger overlay
|
|
125
|
+
* costs the tertiary text step contrast on the rungs it lightens or darkens
|
|
126
|
+
* most. Left to that trade alone, the cheapest answer for the text is an
|
|
127
|
+
* overlay nobody sees, and a light frame keeps asking for it: an overlay that
|
|
128
|
+
* clears the sheet and the card can still sit under dE 3 on the frame. This
|
|
129
|
+
* is the floor that stops it. A hovered row separates
|
|
118
130
|
* from its rung by dE 3, and a pressed row from a hovered one by dE 3 more,
|
|
119
131
|
* because dE 3 is the floor this file holds every "can a reader notice it"
|
|
120
132
|
* difference to. The marketing root is exempt, as it is from the rungs.
|
|
@@ -143,6 +155,18 @@ export const TEXT_STEPS = [
|
|
|
143
155
|
['--color-text-tertiary', 4.5],
|
|
144
156
|
];
|
|
145
157
|
|
|
158
|
+
/**
|
|
159
|
+
* A DIMMED word against the word being read, as [read, dimmed, contrast]: the
|
|
160
|
+
* primary step and the tertiary one. A screen dims what is not its subject by
|
|
161
|
+
* dropping it from the first step to the third (a calendar's days from the
|
|
162
|
+
* neighbouring month, a resolved row under an open one), and both are facts,
|
|
163
|
+
* so each clears its own floor above. What this holds is that the two are a
|
|
164
|
+
* STEP apart rather than a rounding: 2:1 between the inks themselves. A ramp
|
|
165
|
+
* squeezed from both ends, a dimmer primary over a tertiary lifted for its
|
|
166
|
+
* floor on a pressed raised row, can keep every floor and lose the step.
|
|
167
|
+
*/
|
|
168
|
+
export const DIMMED_TEXT = ['--color-text-primary', '--color-text-tertiary', 2];
|
|
169
|
+
|
|
146
170
|
/** A hue used as TEXT on a surface. */
|
|
147
171
|
export const INK_STEPS = [
|
|
148
172
|
'--color-brand-accent-ink',
|
|
@@ -169,11 +193,11 @@ export const STATUS = [
|
|
|
169
193
|
];
|
|
170
194
|
|
|
171
195
|
/**
|
|
172
|
-
* The chart series, in the order a figure assigns them: blue, orange,
|
|
173
|
-
*
|
|
196
|
+
* The chart series, in the order a figure assigns them: blue, orange, green
|
|
197
|
+
* and yellow, the four the approved palette draws.
|
|
174
198
|
*
|
|
175
|
-
* FOUR, because four is what both floors below can hold at once. The
|
|
176
|
-
* four clear them with room (
|
|
199
|
+
* FOUR, because four is what both floors below can hold at once. The shipped
|
|
200
|
+
* four clear them with room (their tightest neighbours sit dE 20.6 apart under
|
|
177
201
|
* normal vision), and a fifth would have to sit between two of them in a hue
|
|
178
202
|
* budget the reserved red, the accent and a dichromat's collapse of red onto
|
|
179
203
|
* green have already spent.
|
|
@@ -219,13 +243,13 @@ export const LABEL_ON_FILL = [
|
|
|
219
243
|
* the fill is the whole of the feedback, so every step clears two things. It
|
|
220
244
|
* is SEEN: ACTION_DE, the floor this file holds every "can a reader notice
|
|
221
245
|
* it" difference to. And it moves AWAY from its label, which is ACTION_LABEL
|
|
222
|
-
* on every fill: a hover or a press only ever gains contrast.
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
* only its direction
|
|
246
|
+
* on every fill: a hover or a press only ever gains contrast. A hover drawn as
|
|
247
|
+
* brightness(1.08) is the step TOWARD a white label: on either accent it
|
|
248
|
+
* takes white under the text floor (4.25:1 in dark, 4.19:1 in light) at the
|
|
249
|
+
* moment a reader is about to press, which the label rule above catches. This
|
|
250
|
+
* rule is what catches a step toward the label that still clears it: the
|
|
251
|
+
* accent dulled at its own lightness reads as a step and keeps its label over
|
|
252
|
+
* 4.5:1, and only its direction is wrong.
|
|
229
253
|
*
|
|
230
254
|
* The DESTRUCTIVE action is the other filled action, and it is held the same
|
|
231
255
|
* way: a toast's destructive action is the danger fill under the same white
|
|
@@ -284,12 +308,12 @@ export const RAIL_GROUND = '--color-surface-frame';
|
|
|
284
308
|
* border drawn round it INSIDE the row, and the primary ink.
|
|
285
309
|
*
|
|
286
310
|
* It is found the way a card is found. Its fill is allowed to be near-flat on
|
|
287
|
-
* the frame, RAIL_CURRENT_LIFT, because in light raised is only dE 1.
|
|
311
|
+
* the frame, RAIL_CURRENT_LIFT, because in light raised is only dE 1.93 off
|
|
288
312
|
* the frame (the design draws it there); what carries the row is the
|
|
289
313
|
* hairline, held to HAIRLINE_DE against the fill it is drawn on. The hairline
|
|
290
|
-
* is also what tells the current row from a HOVERED one, which draws none:
|
|
291
|
-
*
|
|
292
|
-
*
|
|
314
|
+
* is also what tells the current row from a HOVERED one, which draws none: a
|
|
315
|
+
* hover overlay strong enough to be seen on the frame can lift it close to
|
|
316
|
+
* raised, and nothing else keeps the two apart.
|
|
293
317
|
*
|
|
294
318
|
* It used to be the accent's own soft tint with the label in the accent ink.
|
|
295
319
|
* The accent is the primary action's fill now, so a violet row in the rail
|
|
@@ -443,14 +467,13 @@ export const VEIL_BAND = [1.5, 3];
|
|
|
443
467
|
* somewhere the ink steps were never measured against, and it does it in the
|
|
444
468
|
* one state where a reader cannot tell a rendering fault from a design.
|
|
445
469
|
*
|
|
446
|
-
* 0.65 is the
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
* nobody had faded at all.
|
|
470
|
+
* 0.65 is the least alpha that brings every root into the band: the marketing
|
|
471
|
+
* root, near-white on black, needs it before its brightest composite comes
|
|
472
|
+
* under the 3:1 ceiling, and the approved palette draws its veil at it in both
|
|
473
|
+
* themes. At 0.65 dark measures 2.56:1 to 2.76:1, light 2.18:1 to 2.29:1 and
|
|
474
|
+
* the marketing root 2.75:1 to 2.93:1. A light veil drawn as a dark wash
|
|
475
|
+
* instead leaves the light page's text readable through it: a page nobody has
|
|
476
|
+
* faded at all.
|
|
454
477
|
*/
|
|
455
478
|
export const VEIL_GROUND = '--color-surface-frame';
|
|
456
479
|
export const VEIL_ALPHA = 0.65;
|
|
@@ -550,12 +573,11 @@ const ACCENT_DICHROMAT = 8;
|
|
|
550
573
|
// because it is the one hue that means the same thing everywhere in a product,
|
|
551
574
|
// and the accent's dichromat floor. Red, orange and green fall onto one axis
|
|
552
575
|
// for a dichromat, so this is the floor the chart's orange and aqua spend the
|
|
553
|
-
// most on: the approved
|
|
554
|
-
//
|
|
555
|
-
//
|
|
556
|
-
//
|
|
557
|
-
//
|
|
558
|
-
// costs the red.
|
|
576
|
+
// most on: the approved green sat dE 6.79 from the approved red under
|
|
577
|
+
// deuteranopia in dark and 2.30 in light, and the approved orange 11.39 from
|
|
578
|
+
// it under normal vision in dark. The fit moves the red darker, because it had
|
|
579
|
+
// to darken for its white label anyway, and turns the green toward aqua, which
|
|
580
|
+
// takes it off the axis the red falls on.
|
|
559
581
|
const DANGER_NORMAL = 14;
|
|
560
582
|
const DANGER_DICHROMAT = 8;
|
|
561
583
|
|
|
@@ -671,6 +693,12 @@ function checkState(state, values, profile, push) {
|
|
|
671
693
|
const low = worst(colour(name), all);
|
|
672
694
|
say('text step clears its floor', low.ratio >= floor, name, low.ratio, `${low.ratio.toFixed(2)}:1 >= ${floor} (worst on ${low.name})`);
|
|
673
695
|
}
|
|
696
|
+
{
|
|
697
|
+
// A dimmed word against the word being read. See DIMMED_TEXT.
|
|
698
|
+
const [read, dimmed, floor] = DIMMED_TEXT;
|
|
699
|
+
const ratio = contrast(colour(read), colour(dimmed));
|
|
700
|
+
say('a dimmed word is a step from the word being read', ratio >= floor, `${read} vs ${dimmed}`, ratio, `${ratio.toFixed(2)}:1 >= ${floor}`);
|
|
701
|
+
}
|
|
674
702
|
|
|
675
703
|
{
|
|
676
704
|
// It exists for a hairline glyph and a disabled affordance. The assertion
|
|
@@ -1042,6 +1070,29 @@ function checkState(state, values, profile, push) {
|
|
|
1042
1070
|
);
|
|
1043
1071
|
}
|
|
1044
1072
|
}
|
|
1073
|
+
{
|
|
1074
|
+
// A chip on every ground it can land on. See RAISED_CHIP.
|
|
1075
|
+
const [fill, edge] = RAISED_CHIP;
|
|
1076
|
+
const grounds = [
|
|
1077
|
+
...opaque,
|
|
1078
|
+
...OVERLAYS.flatMap((overlay) => opaque.map(([name, rgb]) => [`${overlay} on ${name}`, flatten(values.get(overlay), rgb)])),
|
|
1079
|
+
];
|
|
1080
|
+
const low = grounds.reduce(
|
|
1081
|
+
(least, [name, ground]) => {
|
|
1082
|
+
const filled = flatten(values.get(fill), ground);
|
|
1083
|
+
const drawn = Math.max(deltaE(filled, ground), deltaE(flatten(values.get(edge), filled), ground));
|
|
1084
|
+
return drawn < least.drawn ? { drawn, name } : least;
|
|
1085
|
+
},
|
|
1086
|
+
{ drawn: Infinity, name: '' },
|
|
1087
|
+
);
|
|
1088
|
+
say(
|
|
1089
|
+
'the strong hairline finds a raised chip on every ground',
|
|
1090
|
+
low.drawn >= HAIRLINE_DE,
|
|
1091
|
+
`${edge} round ${fill}`,
|
|
1092
|
+
low.drawn,
|
|
1093
|
+
`dE ${low.drawn.toFixed(2)} >= ${HAIRLINE_DE} (worst on ${low.name})`,
|
|
1094
|
+
);
|
|
1095
|
+
}
|
|
1045
1096
|
}
|
|
1046
1097
|
|
|
1047
1098
|
const describe = (measured) => measured.map((value, i) => `${VISIONS[i].slice(0, 1)}${value.toFixed(1)}`).join('/');
|
package/test/palette.test.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
DATA_ADJACENT_DE,
|
|
23
23
|
DATA_ADJACENT_NORMAL_DE,
|
|
24
24
|
describeFailure,
|
|
25
|
+
DIMMED_TEXT,
|
|
25
26
|
fromOklab,
|
|
26
27
|
hex,
|
|
27
28
|
oklabToLinear,
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
paletteStates,
|
|
31
32
|
parseHex,
|
|
32
33
|
RAIL_CURRENT_ROW,
|
|
34
|
+
RAISED_CHIP,
|
|
33
35
|
runPalette,
|
|
34
36
|
RUNG_STEPS,
|
|
35
37
|
tightest,
|
|
@@ -155,6 +157,17 @@ describe('the palette', () => {
|
|
|
155
157
|
assert.ok(onBase.includes('text step clears its floor'));
|
|
156
158
|
});
|
|
157
159
|
|
|
160
|
+
test('a dimmed word is measured in every state, and one a rounding from the word being read is caught', () => {
|
|
161
|
+
const DIMMED_RULE = 'a dimmed word is a step from the word being read';
|
|
162
|
+
assert.deepEqual(DIMMED_TEXT, ['--color-text-primary', '--color-text-tertiary', 2]);
|
|
163
|
+
for (const state of STATES) {
|
|
164
|
+
assert.equal(checks.filter((check) => check.state === state && check.rule === DIMMED_RULE).length, 1, state);
|
|
165
|
+
}
|
|
166
|
+
// The tertiary step lifted onto the secondary one: each clears its own
|
|
167
|
+
// floor, and the step between the first and the third is gone.
|
|
168
|
+
assert.deepEqual(failuresAfter('dark', '--color-text-tertiary', typed.dark.color.text.secondary), [DIMMED_RULE]);
|
|
169
|
+
});
|
|
170
|
+
|
|
158
171
|
test('the theme layer is dark first, and wins over the token layer', () => {
|
|
159
172
|
// themes.css is imported second on purpose. If that ever stopped being
|
|
160
173
|
// true the dark state would silently be the marketing palette; and if the
|
|
@@ -257,6 +270,18 @@ describe('the four rungs', () => {
|
|
|
257
270
|
assert.deepEqual(darkFailures(line, dark.surface.subtle), ['the hairline that finds a card is visible on both sides of it']);
|
|
258
271
|
});
|
|
259
272
|
|
|
273
|
+
test('a raised chip is measured in every theme state, and one whose edge is its own fill is caught', () => {
|
|
274
|
+
const CHIP_RULE = 'the strong hairline finds a raised chip on every ground';
|
|
275
|
+
const [fill, edge] = RAISED_CHIP;
|
|
276
|
+
assert.deepEqual([fill, edge], ['--color-surface-elevated', '--color-border-strong']);
|
|
277
|
+
for (const state of THEME_STATES) {
|
|
278
|
+
assert.equal(checks.filter((check) => check.state === state && check.rule === CHIP_RULE).length, 1, state);
|
|
279
|
+
}
|
|
280
|
+
// The edge drawn in the chip's own fill: on a raised ground the chip is
|
|
281
|
+
// loose words, and nothing else the palette measures notices.
|
|
282
|
+
assert.deepEqual(darkFailures(edge, dark.surface.elevated), [CHIP_RULE]);
|
|
283
|
+
});
|
|
284
|
+
|
|
260
285
|
test('raised at the card\'s own value is caught', () => {
|
|
261
286
|
assert.deepEqual(darkFailures('--color-surface-elevated', dark.surface.subtle), ['raised separates from the card']);
|
|
262
287
|
});
|
|
@@ -279,8 +304,8 @@ describe('the accent and the primary action', () => {
|
|
|
279
304
|
const [HOVER_RULE, PRESS_RULE] = ACTION_STEPS.map(([rule]) => rule);
|
|
280
305
|
|
|
281
306
|
/**
|
|
282
|
-
* What `filter: brightness(1.08)` does to a colour,
|
|
283
|
-
*
|
|
307
|
+
* What `filter: brightness(1.08)` does to a colour, the usual way to light a
|
|
308
|
+
* button under the pointer: each sRGB channel scaled and clipped.
|
|
284
309
|
*/
|
|
285
310
|
const brightened = (value) => {
|
|
286
311
|
const { r, g, b } = parseHex(value);
|
|
@@ -303,18 +328,33 @@ describe('the accent and the primary action', () => {
|
|
|
303
328
|
}
|
|
304
329
|
});
|
|
305
330
|
|
|
306
|
-
test(
|
|
307
|
-
//
|
|
308
|
-
// the label rule sees
|
|
309
|
-
//
|
|
310
|
-
assert.equal(brightened(typed.dark.color.brand.accent), '#
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
331
|
+
test('a hover that brightens the fill is caught in both palettes', () => {
|
|
332
|
+
// It takes the white label under the text floor (4.25:1 in dark, 4.19:1
|
|
333
|
+
// in light), which the label rule sees, and the step rule sees that it
|
|
334
|
+
// moved toward the label rather than away from it.
|
|
335
|
+
assert.equal(brightened(typed.dark.color.brand.accent), '#7b62f8');
|
|
336
|
+
for (const palette of ['dark', 'light']) {
|
|
337
|
+
assert.deepEqual(
|
|
338
|
+
failuresAfter(palette, '--color-brand-accent-hover', brightened(typed[palette].color.brand.accent)),
|
|
339
|
+
[LABEL_RULE, HOVER_RULE],
|
|
340
|
+
palette,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
test('a visible step toward the label is caught while the label still clears', () => {
|
|
346
|
+
// The accent dulled to 0.8 of its chroma at its own lightness: a step a
|
|
347
|
+
// reader sees (dE 3.94 in dark), under which the white label still clears
|
|
348
|
+
// the floor (4.72:1), and which moves toward the label all the same. Only
|
|
349
|
+
// the step rule's direction stands between it and a hover that fades.
|
|
350
|
+
const dulled = (value) => {
|
|
351
|
+
const lab = toOklab(parseHex(value));
|
|
352
|
+
return hex(fromOklab({ L: lab.L, a: lab.a * 0.8, b: lab.b * 0.8 }));
|
|
353
|
+
};
|
|
354
|
+
assert.equal(dulled(typed.dark.color.brand.accent), '#7164d1');
|
|
355
|
+
for (const palette of ['dark', 'light']) {
|
|
356
|
+
assert.deepEqual(failuresAfter(palette, '--color-brand-accent-hover', dulled(typed[palette].color.brand.accent)), [HOVER_RULE], palette);
|
|
357
|
+
}
|
|
318
358
|
});
|
|
319
359
|
|
|
320
360
|
test('a step nobody can see is caught, even one in the right direction', () => {
|
|
@@ -357,10 +397,12 @@ describe('the accent and the primary action', () => {
|
|
|
357
397
|
assert.deepEqual(failuresAfter('dark', line, typed.dark.color.surface.elevated), [
|
|
358
398
|
"the hairline round the rail's current row is visible on it",
|
|
359
399
|
]);
|
|
360
|
-
// Raised two steps off the
|
|
361
|
-
// to still holds, and the row is no longer there.
|
|
362
|
-
|
|
363
|
-
|
|
400
|
+
// Raised two steps off the dark frame: every other rule raised is held
|
|
401
|
+
// to still holds, and the row is no longer there. In light the hairline
|
|
402
|
+
// sits dE 1.23 from the frame, so a row lowered onto the frame loses its
|
|
403
|
+
// line as well, and only dark shows the lift on its own.
|
|
404
|
+
const { r, g, b } = parseHex(typed.dark.color.surface.frame);
|
|
405
|
+
assert.deepEqual(failuresAfter('dark', fill, hex({ r: r + 2, g: g + 2, b: b + 2 })), [
|
|
364
406
|
"the rail's current row lifts off the rail",
|
|
365
407
|
]);
|
|
366
408
|
});
|
|
@@ -410,39 +452,37 @@ describe('the state and chart hues', () => {
|
|
|
410
452
|
});
|
|
411
453
|
|
|
412
454
|
test("the design's stopped red is caught by its label, by deuteranopia and by the chart hues", () => {
|
|
413
|
-
// The approved #
|
|
414
|
-
//
|
|
415
|
-
//
|
|
416
|
-
// under
|
|
417
|
-
// (
|
|
418
|
-
const failing = checksAfter('dark', '--color-feedback-danger', '#
|
|
455
|
+
// The approved #f0506e carries a destructive action's white label at
|
|
456
|
+
// 3.46:1, and a deuteranopic reader finds it dE 5.9 from done. It also
|
|
457
|
+
// sits under the floors the reserved red keeps from the orange (11.4
|
|
458
|
+
// under normal vision, 6.8 under deuteranopia) and from the green
|
|
459
|
+
// (deuteranopia 4.9).
|
|
460
|
+
const failing = checksAfter('dark', '--color-feedback-danger', '#f0506e').map(summary);
|
|
419
461
|
assert.deepEqual(failing, [
|
|
420
|
-
`${LABEL_RULE}: --color-text-on-accent on --color-feedback-danger:
|
|
421
|
-
`${STATUS_RULE}: --color-feedback-success vs --color-feedback-danger: dE
|
|
422
|
-
`${DANGER_RULE}: --color-data-2: dE
|
|
423
|
-
`${DANGER_RULE}: --color-data-3: dE
|
|
424
|
-
`${DANGER_RULE}: --color-data-4: dE n13.6/p8.9/d7.0 >= 14 normal, 8 dichromat`,
|
|
462
|
+
`${LABEL_RULE}: --color-text-on-accent on --color-feedback-danger: 3.46:1 (worst on --color-feedback-danger on --color-surface-frame)`,
|
|
463
|
+
`${STATUS_RULE}: --color-feedback-success vs --color-feedback-danger: dE n34.5/p18.6/d5.9 >= 10`,
|
|
464
|
+
`${DANGER_RULE}: --color-data-2: dE n11.4/p9.9/d6.8 >= 14 normal, 8 dichromat`,
|
|
465
|
+
`${DANGER_RULE}: --color-data-3: dE n32.5/p12.7/d4.9 >= 14 normal, 8 dichromat`,
|
|
425
466
|
]);
|
|
426
467
|
});
|
|
427
468
|
|
|
428
469
|
test("the design's light yellow is caught as a mark nobody can see on the frame", () => {
|
|
429
|
-
// #
|
|
430
|
-
//
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
`${MARK_RULE}: --color-data-4: 1.85:1 (worst on --color-surface-frame)`,
|
|
470
|
+
// #edb302 on the light frame is 1.61:1, and that is the only rule it
|
|
471
|
+
// breaks: a yellow dark enough to be seen on a light page is an ochre.
|
|
472
|
+
assert.deepEqual(checksAfter('light', '--color-data-4', '#edb302').map(summary), [
|
|
473
|
+
`${MARK_RULE}: --color-data-4: 1.61:1 (worst on --color-surface-frame)`,
|
|
434
474
|
]);
|
|
435
475
|
});
|
|
436
476
|
|
|
437
477
|
test('a neighbour that clears every dichromat floor is still caught under normal vision', () => {
|
|
438
|
-
//
|
|
439
|
-
// protanopia and deuteranopia, which the dichromat floor alone
|
|
440
|
-
// and
|
|
441
|
-
// sees colour. Nothing else it touches fails, so the
|
|
442
|
-
// is the only thing standing between it and a chart.
|
|
443
|
-
const failing = checksAfter('dark', '--color-data-4', '#
|
|
478
|
+
// A teal fourth series beside the aqua green third: dE 13.0 apart under
|
|
479
|
+
// protanopia and 12.3 under deuteranopia, which the dichromat floor alone
|
|
480
|
+
// passes, and 13.0 under normal vision, two shades of one hue to every
|
|
481
|
+
// reader who sees colour. Nothing else it touches fails, so the
|
|
482
|
+
// normal-vision floor is the only thing standing between it and a chart.
|
|
483
|
+
const failing = checksAfter('dark', '--color-data-4', '#008c87');
|
|
444
484
|
assert.deepEqual(failing.map(summary), [
|
|
445
|
-
`${ADJACENT_RULE}: --color-data-3 vs --color-data-4: dE
|
|
485
|
+
`${ADJACENT_RULE}: --color-data-3 vs --color-data-4: dE n13.0/p13.0/d12.3 >= ${DATA_ADJACENT_NORMAL_DE} normal, ${DATA_ADJACENT_DE} every vision`,
|
|
446
486
|
]);
|
|
447
487
|
assert.ok(failing[0].value >= DATA_ADJACENT_DE, 'the mutation has to clear the dichromat floor, or it proves nothing about the normal one');
|
|
448
488
|
});
|