@kolkrabbi/kol-styleguide 0.18.0 → 0.18.2
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/package.json +5 -5
- package/src/ColorLab.jsx +33 -27
- package/src/lab/LabWindow.jsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kolkrabbi/kol-styleguide",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Brand guide components and the brand tool",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"react-dom": "^18.3.0 || ^19.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
+
"@kolkrabbi/kol-print": "^0.1.1",
|
|
26
|
+
"@kolkrabbi/kol-theme": "^0.200.2",
|
|
25
27
|
"@kolkrabbi/kol-framework": "^0.65.0",
|
|
26
|
-
"@kolkrabbi/kol-
|
|
27
|
-
"@kolkrabbi/kol-
|
|
28
|
-
"@kolkrabbi/kol-component": "^0.317.0",
|
|
29
|
-
"@kolkrabbi/kol-print": "^0.1.1"
|
|
28
|
+
"@kolkrabbi/kol-component": "^0.317.2",
|
|
29
|
+
"@kolkrabbi/kol-icons": "^0.53.2"
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"src",
|
package/src/ColorLab.jsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useRef, useState } from 'react'
|
|
2
|
-
import { Button, ColorPickerPopover, Dropdown, Icon, IconFrame, PaletteHarmonyWheel,
|
|
2
|
+
import { Button, ColorPickerPopover, Dropdown, Icon, IconFrame, PaletteHarmonyWheel, Slider, Tooltip, hexToHsl, hslToHex } from '@kolkrabbi/kol-component'
|
|
3
3
|
import { COLOR_RELATIONS, CVD_TYPES, DEFAULT_COLOR_LAB, colorLab, colorLabCss, contrastGrade, contrastRatio, hexToOklch, inkOn, midColor, oklchToHex, paletteFromPixels, rollColorLab, simulateCvd, tintLadder } from './colorLab.js'
|
|
4
4
|
import LabWindow, { CopyAction, LabHistory, useLabValue } from './lab/LabWindow.jsx'
|
|
5
5
|
|
|
@@ -260,9 +260,11 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
260
260
|
const harmony = (
|
|
261
261
|
/* HARMONIES (review 3): the DS's glyphs, each named on hover, the mode named in the label — on the Wheel tab only
|
|
262
262
|
* (review 6 — *"you know there is a tab for wheel. why do you put it on every page?"*) */
|
|
263
|
-
|
|
264
|
-
/* review
|
|
265
|
-
|
|
263
|
+
<>
|
|
264
|
+
{/* THE EYEBROW IS THE RAIL'S LABEL (review 8 — *"IT WAS PERFECT!!! I was saying why is it only used here"*): the
|
|
265
|
+
* settings rail's section label, now on every label in the rail */}
|
|
266
|
+
<p className="kol-eyebrow text-fg-80">Harmony: {harmonyLabel(c.relation)}</p>
|
|
267
|
+
{/* review 5 — bigger glyphs across the rail's width, no chip, OPAQUE ink (oq, never fg), full when chosen */}
|
|
266
268
|
<div className="grid w-full grid-cols-9">
|
|
267
269
|
{HARMONY_TILES.map((id) => (
|
|
268
270
|
<Tooltip key={id} label={harmonyLabel(id)}>
|
|
@@ -274,7 +276,7 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
274
276
|
</Tooltip>
|
|
275
277
|
))}
|
|
276
278
|
</div>
|
|
277
|
-
|
|
279
|
+
</>
|
|
278
280
|
)
|
|
279
281
|
const sources = [
|
|
280
282
|
{ id: 'base', label: 'Base', icon: 'eyedrop', content: (
|
|
@@ -298,11 +300,11 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
298
300
|
{image
|
|
299
301
|
? <img src={image} alt="" className="absolute inset-0 h-full w-full object-cover" />
|
|
300
302
|
: (
|
|
301
|
-
|
|
302
|
-
<Button size="md" iconLeft="upload" onClick={(e) => { e.stopPropagation(); fileInput.current?.click() }}>Upload your image</Button>
|
|
303
|
+
<span className="relative flex flex-col items-center gap-2">
|
|
304
|
+
<Button size="md" tone="inverted" iconLeft="upload" onClick={(e) => { e.stopPropagation(); fileInput.current?.click() }}>Upload your image</Button>
|
|
303
305
|
<span className="kol-sans-body-02 text-emphasis">Or drag and drop here</span>
|
|
304
|
-
<span className="kol-sans-body-03 text-meta">File must be JPEG, JPG, PNG or WebP and up to 40MB</span>
|
|
305
|
-
|
|
306
|
+
<span className="whitespace-nowrap kol-sans-body-03 text-meta">File must be JPEG, JPG, PNG or WebP and up to 40MB</span>
|
|
307
|
+
</span>
|
|
306
308
|
)}
|
|
307
309
|
<input ref={fileInput} type="file" accept="image/jpeg,image/png,image/webp" className="hidden" onChange={(e) => { fromFile(e.target.files?.[0]); e.target.value = '' }} />
|
|
308
310
|
</div>
|
|
@@ -312,7 +314,7 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
312
314
|
<div className="flex flex-col gap-3">
|
|
313
315
|
<div className="flex items-baseline justify-between gap-3">
|
|
314
316
|
<span className="kol-sans-body-02 text-emphasis">Don’t have an image? Try one of ours:</span>
|
|
315
|
-
{library && <a href={library.href} target="_blank" rel="noreferrer" className="group inline-flex shrink-0 items-center gap-1 kol-
|
|
317
|
+
{library && <a href={library.href} target="_blank" rel="noreferrer" className="group inline-flex shrink-0 items-center gap-1 kol-sans-body-02 text-meta hover:text-emphasis">{library.label}<Icon name="external-link" size={12} className="text-oq-48 group-hover:text-oq-96" /></a>}
|
|
316
318
|
</div>
|
|
317
319
|
<div className="grid grid-cols-4 gap-2">
|
|
318
320
|
{samples.slice(0, 4).map((x) => <SampleTile key={x.src} src={x.src} label={x.label ?? x.src} onPick={() => takeImage(x.src)} />)}
|
|
@@ -408,7 +410,7 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
408
410
|
/* the pair, Adobe's: Foreground and Background side by side, swap between them, each colour's lightness under it */
|
|
409
411
|
const pairCol = (label, i, key) => (
|
|
410
412
|
<div className="flex min-w-0 flex-col gap-2">
|
|
411
|
-
<span className="kol-
|
|
413
|
+
<span className="kol-eyebrow text-fg-80">{label}</span>
|
|
412
414
|
<div className="flex items-center gap-2">
|
|
413
415
|
<span className="size-4 shrink-0 rounded-full" style={{ background: c.colors[i] }} />
|
|
414
416
|
<Dropdown size="sm" value={String(i)} onChange={(v) => setPair({ fg: fgI, bg: bgI, [key]: Number(v) })} options={colourOptions} className="min-w-0 flex-1" ariaLabel={`${label} colour`} />
|
|
@@ -419,28 +421,28 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
419
421
|
const pairHead = (
|
|
420
422
|
<div className="flex flex-col gap-4">
|
|
421
423
|
<div className="flex items-center justify-between gap-3">
|
|
422
|
-
<span className="kol-
|
|
424
|
+
<span className="kol-eyebrow text-fg-80">Contrast ratio</span>
|
|
423
425
|
<span className={`inline-flex items-center gap-1 rounded px-2 py-0.5 kol-mono-12 ${ratio >= 4.5 ? 'bg-oq-08 text-emphasis' : 'bg-oq-04 text-meta'}`}><Icon name={ratio >= 4.5 ? 'check' : 'alert-triangle'} size={12} className={ratio >= 4.5 ? 'text-oq-96' : 'text-oq-48'} />{ratioText(ratio)} : 1</span>
|
|
424
426
|
</div>
|
|
425
427
|
<div className="grid grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] items-start gap-2">
|
|
426
|
-
{pairCol('Foreground
|
|
428
|
+
{pairCol('Foreground', fgI, 'fg')}
|
|
427
429
|
<Button variant="nav" size="sm" iconOnly="swap" aria-label="Swap foreground and background" className="mt-6" onClick={() => setPair({ fg: bgI, bg: fgI })} />
|
|
428
|
-
{pairCol('Background
|
|
430
|
+
{pairCol('Background', bgI, 'bg')}
|
|
429
431
|
</div>
|
|
430
432
|
</div>
|
|
431
433
|
)
|
|
432
434
|
const summaryTable = (
|
|
433
435
|
<div className="flex flex-col">
|
|
434
|
-
<div className="grid grid-cols-[minmax(0,1fr)_64px_64px] border-b border-oq-16 pb-2 kol-
|
|
436
|
+
<div className="grid grid-cols-[minmax(0,1fr)_64px_64px] border-b border-oq-16 pb-2 kol-eyebrow text-fg-80"><span>Category</span><span>AA</span><span>AAA</span></div>
|
|
435
437
|
{SUMMARY.map((r) => (
|
|
436
|
-
<div key={r.id} className="grid grid-cols-[minmax(0,1fr)_64px_64px] items-center border-b border-oq-08 py-3 kol-sans-body-
|
|
438
|
+
<div key={r.id} className="grid grid-cols-[minmax(0,1fr)_64px_64px] items-center border-b border-oq-08 py-3 kol-sans-body-02 text-emphasis"><span>{r.label}</span><Verdict ok={r.aa} /><Verdict ok={r.aaa} na={r.aaa === null} /></div>
|
|
437
439
|
))}
|
|
438
440
|
</div>
|
|
439
441
|
)
|
|
440
442
|
/* KOL's text levels: the foreground at every ink stop over the background, each measured */
|
|
441
443
|
const ladder = (
|
|
442
444
|
<div className="flex flex-col gap-2">
|
|
443
|
-
<span className="kol-
|
|
445
|
+
<span className="kol-eyebrow text-fg-80">Text levels</span>
|
|
444
446
|
<div className="flex w-full flex-col rounded p-3" style={{ background: bg }}>
|
|
445
447
|
{c.text.map((x) => {
|
|
446
448
|
const r = contrastRatio(over(fg, bg, x.stop / 100), bg)
|
|
@@ -461,8 +463,8 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
461
463
|
<>
|
|
462
464
|
{pairHead}
|
|
463
465
|
<div className="flex flex-col">
|
|
464
|
-
<span className="border-b border-oq-16 pb-2 kol-
|
|
465
|
-
{suggestions.length === 0 && <span className="py-3 kol-sans-body-
|
|
466
|
+
<span className="border-b border-oq-16 pb-2 kol-eyebrow text-fg-80">Foreground colors that pass AA</span>
|
|
467
|
+
{suggestions.length === 0 && <span className="py-3 kol-sans-body-02 text-meta">None at this hue. Move the background’s lightness.</span>}
|
|
466
468
|
{suggestions.map((x) => (
|
|
467
469
|
<button key={x.hex} type="button" onClick={() => editAt(fgI, x.hex)} className="grid cursor-pointer grid-cols-[16px_minmax(0,1fr)_auto] items-center gap-3 border-b border-oq-08 py-2 text-left kol-mono-12 text-emphasis hover:bg-oq-04">
|
|
468
470
|
<span className="size-4 rounded-full" style={{ background: x.hex }} /><span>{x.hex}</span><span className="text-meta">{ratioText(x.r)} : 1 {contrastGrade(x.r)}</span>
|
|
@@ -475,23 +477,27 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
475
477
|
<>
|
|
476
478
|
{pairHead}
|
|
477
479
|
<div className="flex flex-col gap-2">
|
|
478
|
-
<span className="kol-
|
|
480
|
+
<span className="kol-eyebrow text-fg-80">Target ratio</span>
|
|
479
481
|
<Slider className="w-full" min={1} max={21} step={0.5} value={target ?? Math.round(ratio * 2) / 2} onChange={(t) => { setTarget(t); editAt(fgI, solveFor(t)) }} readout="input" displayWidth={4} readoutPreset="rail" aria-label="Target contrast ratio" />
|
|
480
|
-
<span className="kol-sans-body-
|
|
482
|
+
<span className="kol-sans-body-02 text-meta">The foreground’s lightness moves until the pair reaches it.</span>
|
|
481
483
|
</div>
|
|
482
484
|
</>
|
|
483
485
|
) },
|
|
484
486
|
]
|
|
485
|
-
|
|
487
|
+
/* THE PREVIEW IN THE PALETTE'S OWN FORMS (review 8 — *"how is this using ANYTHING but the colors?? … show some
|
|
488
|
+
* forms that use the pallette"*): the page in bg and fg, the other colours as forms beside the text; the DS Button */
|
|
489
|
+
const FORMS = ['left-[8%] top-[10%] w-[52%] aspect-square rounded-full', 'right-[8%] bottom-[8%] w-[38%] aspect-square rounded-[12%]', 'left-[6%] bottom-[12%] h-[14%] w-[48%] rounded-full', 'right-[10%] top-[8%] h-[9%] w-[32%] rounded']
|
|
490
|
+
const forms = c.colors.filter((_, i) => i !== fgI && i !== bgI)
|
|
486
491
|
const contrastStage = (
|
|
487
|
-
/* ADOBE'S PREVIEW: the image beside the pair as a page would use it — a headline, body text and a button */
|
|
488
492
|
<div className="flex h-full min-h-[240px] flex-col gap-3">
|
|
489
|
-
<div className=
|
|
490
|
-
|
|
493
|
+
<div className="grid min-h-0 flex-1 grid-cols-2 grid-rows-[minmax(0,1fr)] overflow-hidden rounded" style={{ background: bg, color: fg }}>
|
|
494
|
+
<div className="relative min-h-0 overflow-hidden">
|
|
495
|
+
{(forms.length ? forms : [fg]).slice(0, 4).map((hex, i) => <span key={`${hex}${i}`} className={`absolute ${FORMS[i]}`} style={{ background: hex }} />)}
|
|
496
|
+
</div>
|
|
491
497
|
<div className="flex min-h-0 flex-col justify-center gap-6 p-10">
|
|
492
498
|
<span className="kol-sans-heading-01 leading-none">The quick brown fox</span>
|
|
493
499
|
<span className="max-w-[48ch] kol-sans-body-02">Body text in the foreground on the background, the size most of a page is read at. If this line is hard to read, so is the page.</span>
|
|
494
|
-
<
|
|
500
|
+
<Button size="md" className="self-start" style={{ '--kol-tone-bg': fg, '--kol-tone-hover-bg': fg, '--kol-tone-fg': bg, '--kol-tone-hover-fg': bg, '--kol-tone-image': 'none', '--kol-tone-hover-image': 'none' }}>Button</Button>
|
|
495
501
|
</div>
|
|
496
502
|
</div>
|
|
497
503
|
{paletteFoot}
|
|
@@ -508,7 +514,7 @@ export default function ColorLab({ value: valueProp, onChange, samples = [], lib
|
|
|
508
514
|
const visionRail = [{ id: 'conflicts', label: 'Conflicts', content: (
|
|
509
515
|
<>
|
|
510
516
|
<div className="flex items-center justify-between gap-3 rounded bg-oq-04 p-3">
|
|
511
|
-
<span className="kol-
|
|
517
|
+
<span className="kol-eyebrow text-fg-80">Potential color blind conflicts</span>
|
|
512
518
|
<span className={`inline-flex shrink-0 items-center gap-1 rounded px-2 py-0.5 kol-mono-12 ${conflicts ? 'bg-oq-08 text-emphasis' : 'text-meta'}`}>{conflicts && <Icon name="alert-triangle" size={12} className="text-oq-96" />}{conflicts ? 'Conflicts found' : 'None'}</span>
|
|
513
519
|
</div>
|
|
514
520
|
<PaletteDots colors={c.colors} />
|
package/src/lab/LabWindow.jsx
CHANGED
|
@@ -65,7 +65,7 @@ export default function LabWindow({ title, actions, tabs = [], tab: tabProp, onT
|
|
|
65
65
|
<div {...grabProps} className="kol-rail-grab kol-rail-grab--left hidden md:block" />
|
|
66
66
|
{/* THE TABSROW AT THE TOP OF EVERY WINDOW (review 6 — *"why dont we make it a rule at top of each window?"*):
|
|
67
67
|
* one section or many, the rail opens on its tabs */}
|
|
68
|
-
{tabs.length > 0 && <TabsRow tabs={tabs.map(({ id, label, icon }) => ({ id, label, icon }))} value={open?.id} onChange={setTab} ariaLabel={`${title} sections`} />}
|
|
68
|
+
{tabs.length > 0 && <TabsRow size="md" tabs={tabs.map(({ id, label, icon }) => ({ id, label, icon }))} value={open?.id} onChange={setTab} ariaLabel={`${title} sections`} />}
|
|
69
69
|
<div className="flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto">{open?.content}</div>
|
|
70
70
|
{foot && <div className="flex flex-wrap items-center gap-1">{foot}</div>}
|
|
71
71
|
</aside>
|