@hattisar/design-tokens 0.3.6 → 0.3.7
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 +1 -1
- package/tokens.css +185 -44
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hattisar/design-tokens",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Shared design tokens (colors, type, radius, spacing, motion) and base primitives (reset, buttons, inputs, cards, modals, auth shell) for every Hattisar frontend.",
|
|
5
5
|
"main": "tokens.css",
|
|
6
6
|
"files": [
|
package/tokens.css
CHANGED
|
@@ -32,21 +32,40 @@
|
|
|
32
32
|
>=4.5:1) and for a real 3-step surface ladder — surface-tint used
|
|
33
33
|
to equal background-global exactly, which meant hover states had
|
|
34
34
|
no visible target to land on. */
|
|
35
|
-
--color-background-global: #
|
|
35
|
+
--color-background-global: #f4f4f5;
|
|
36
36
|
--color-background-card: #ffffff;
|
|
37
|
-
--color-surface-tint: #
|
|
37
|
+
--color-surface-tint: #e8e8ea;
|
|
38
38
|
--color-input: #ffffff;
|
|
39
|
-
--color-text-primary: #
|
|
39
|
+
--color-text-primary: #09090b;
|
|
40
40
|
/* ~6.4:1 on card */
|
|
41
|
-
--color-text-secondary: #
|
|
41
|
+
--color-text-secondary: #52525b;
|
|
42
42
|
/* ~4.6:1 on card — was #8f99a8 at 2.9:1, failing AA body text */
|
|
43
|
-
--color-text-muted: #
|
|
43
|
+
--color-text-muted: #6b6b74;
|
|
44
44
|
/* Derived from text-primary's own RGB (28,33,39) rather than a
|
|
45
45
|
separately maintained literal, so border and text can never drift
|
|
46
46
|
apart the way they used to (border was rgb(17,20,24), a different
|
|
47
47
|
dark from text-primary's rgb(28,33,39)). */
|
|
48
|
-
--color-border:
|
|
49
|
-
--color-border-strong:
|
|
48
|
+
--color-border: #e4e4e7;
|
|
49
|
+
--color-border-strong: #d4d4d8;
|
|
50
|
+
|
|
51
|
+
/* Anything that floats over the page: dropdowns, menus, popovers,
|
|
52
|
+
modals, tooltips.
|
|
53
|
+
Reported: "we might need to add little background shadow for all
|
|
54
|
+
dropdown, popup so it differentiate from background. hard to view
|
|
55
|
+
now."
|
|
56
|
+
They all had a shadow already. The problem was that they were
|
|
57
|
+
painted --color-background-card and opened *over* cards — white on
|
|
58
|
+
white, separated by a 9%-alpha hairline and a shadow tuned so
|
|
59
|
+
softly it read as nothing. A surface only looks raised against
|
|
60
|
+
something.
|
|
61
|
+
So a floating surface gets its own tier: in dark it is a real step
|
|
62
|
+
above the card, and in light — where a popover over a white card
|
|
63
|
+
has nowhere lighter to go — the separation comes from a stronger
|
|
64
|
+
edge and a shadow with actual weight instead. */
|
|
65
|
+
--color-surface-raised: #ffffff;
|
|
66
|
+
--color-border-raised: #d4d4d8;
|
|
67
|
+
--shadow-popover: 0 4px 6px -2px rgba(9, 9, 11, 0.08), 0 12px 28px -8px rgba(9, 9, 11, 0.18);
|
|
68
|
+
|
|
50
69
|
--color-hover: var(--color-surface-tint);
|
|
51
70
|
--color-focus-ring: rgba(233, 235, 239, 0.2);
|
|
52
71
|
--color-focus-ring-danger: rgba(255, 138, 156, 0.24);
|
|
@@ -54,7 +73,7 @@
|
|
|
54
73
|
than a saturated blue: this palette has no brand hue, and a blue
|
|
55
74
|
ring here would be the one place colour appeared without meaning
|
|
56
75
|
anything — the ten status tiers are what colour is for. */
|
|
57
|
-
--color-focus-ring: rgba(
|
|
76
|
+
--color-focus-ring: rgba(9, 9, 11, 0.14);
|
|
58
77
|
--color-focus-ring-danger: rgba(199, 10, 36, 0.2);
|
|
59
78
|
|
|
60
79
|
/* Named accents — the same 8 hues most of the status tiers below
|
|
@@ -191,10 +210,10 @@
|
|
|
191
210
|
popovers), lg for a modal. Tinted with the ink colour rather than
|
|
192
211
|
pure black so a shadow reads as the surface's own shade instead of
|
|
193
212
|
a grey smudge. */
|
|
194
|
-
--shadow-xs: 0 1px 2px rgba(
|
|
195
|
-
--shadow-sm: 0 1px 2px rgba(
|
|
196
|
-
--shadow-md: 0 2px 4px -1px rgba(
|
|
197
|
-
--shadow-lg: 0 4px 8px -2px rgba(
|
|
213
|
+
--shadow-xs: 0 1px 2px rgba(9, 9, 11, 0.04);
|
|
214
|
+
--shadow-sm: 0 1px 2px rgba(9, 9, 11, 0.05), 0 2px 8px -3px rgba(9, 9, 11, 0.08);
|
|
215
|
+
--shadow-md: 0 2px 4px -1px rgba(9, 9, 11, 0.04), 0 8px 20px -4px rgba(9, 9, 11, 0.12);
|
|
216
|
+
--shadow-lg: 0 4px 8px -2px rgba(9, 9, 11, 0.06), 0 20px 48px -12px rgba(9, 9, 11, 0.22);
|
|
198
217
|
|
|
199
218
|
/* One shared tier for every FloatingPanel-based dropdown/menu
|
|
200
219
|
(row actions, column picker, combobox, select, table-actions,
|
|
@@ -227,6 +246,16 @@
|
|
|
227
246
|
regions of a page rather than elements inside one. Without them
|
|
228
247
|
every large gap in the app was a hardcoded number, and they were
|
|
229
248
|
all slightly different. */
|
|
249
|
+
/* The narrowest a form field may be before it stops being readable.
|
|
250
|
+
The document forms laid fields out as `flex: 1; minWidth: 140`,
|
|
251
|
+
which on a wide screen fits six controls onto one row at about
|
|
252
|
+
130px each — narrow enough to clip "Customer's own reference"
|
|
253
|
+
mid-word. Every form field grid is built on this instead. */
|
|
254
|
+
--field-min-width: 260px;
|
|
255
|
+
/* For a control whose value is a word, not a sentence — a variant
|
|
256
|
+
name, a unit, a percentage — inside a line-item row. */
|
|
257
|
+
--field-min-width-narrow: 140px;
|
|
258
|
+
|
|
230
259
|
--space-16: 64px;
|
|
231
260
|
--space-20: 80px;
|
|
232
261
|
|
|
@@ -320,22 +349,27 @@
|
|
|
320
349
|
sits below the hover/tint tier. Modest steps between each (not a
|
|
321
350
|
dramatic jump) plus real borders is what keeps a dark theme
|
|
322
351
|
reading crisp instead of washed out — see --color-border below. */
|
|
323
|
-
--color-background-global: #
|
|
324
|
-
--color-background-card: #
|
|
325
|
-
--color-surface-tint: #
|
|
352
|
+
--color-background-global: #09090b;
|
|
353
|
+
--color-background-card: #18181b;
|
|
354
|
+
--color-surface-tint: #27272a;
|
|
326
355
|
--color-input: var(--color-background-card);
|
|
327
356
|
/* Not pure white — pure white text on a near-black surface causes
|
|
328
357
|
halation (a glow/vibrate effect on the eye over long sessions).
|
|
329
358
|
~92% white instead. */
|
|
330
|
-
--color-text-primary: #
|
|
359
|
+
--color-text-primary: #fafafa;
|
|
331
360
|
/* ~7:1 on card */
|
|
332
|
-
--color-text-secondary: #
|
|
361
|
+
--color-text-secondary: #d4d4d8;
|
|
333
362
|
/* ~4.7:1 on card — was #5f6b7c at 2.7:1, failing AA body text */
|
|
334
|
-
--color-text-muted: #
|
|
363
|
+
--color-text-muted: #a1a1aa;
|
|
335
364
|
/* Derived from text-primary's own RGB (233,233,236) — same
|
|
336
365
|
single-source-of-truth reasoning as :root's own --color-border. */
|
|
337
|
-
--color-border:
|
|
338
|
-
--color-border-strong:
|
|
366
|
+
--color-border: #27272a;
|
|
367
|
+
--color-border-strong: #3f3f46;
|
|
368
|
+
/* A genuine step above the card, which is what makes a dropdown read
|
|
369
|
+
as floating rather than pasted on. */
|
|
370
|
+
--color-surface-raised: #1f1f23;
|
|
371
|
+
--color-border-raised: #3f3f46;
|
|
372
|
+
--shadow-popover: 0 4px 6px -2px rgba(0, 0, 0, 0.5), 0 16px 40px -10px rgba(0, 0, 0, 0.75);
|
|
339
373
|
--color-hover: var(--color-surface-tint);
|
|
340
374
|
|
|
341
375
|
/* Brighter counterparts of :root's accent set — a dark badge fill
|
|
@@ -360,10 +394,10 @@
|
|
|
360
394
|
--color-brand: var(--color-text-primary);
|
|
361
395
|
--color-brand-hover: color-mix(in srgb, var(--color-brand) 90%, black);
|
|
362
396
|
--color-brand-active: color-mix(in srgb, var(--color-brand) 75%, black);
|
|
363
|
-
--color-brand-text: #
|
|
397
|
+
--color-brand-text: #09090b;
|
|
364
398
|
|
|
365
|
-
--shadow-btn-primary: 0 1px 2px rgba(
|
|
366
|
-
--shadow-btn-secondary: 0 1px 2px rgba(
|
|
399
|
+
--shadow-btn-primary: 0 1px 2px rgba(9, 9, 11, 0.12);
|
|
400
|
+
--shadow-btn-secondary: 0 1px 2px rgba(9, 9, 11, 0.05);
|
|
367
401
|
|
|
368
402
|
--color-secondary-fill: var(--color-surface-tint);
|
|
369
403
|
--color-secondary-border: var(--color-border-strong);
|
|
@@ -417,12 +451,15 @@
|
|
|
417
451
|
--shadow-md: 0 2px 4px -1px rgba(0, 0, 0, 0.4), 0 8px 22px -4px rgba(0, 0, 0, 0.6);
|
|
418
452
|
--shadow-lg: 0 4px 8px -2px rgba(0, 0, 0, 0.45), 0 24px 56px -12px rgba(0, 0, 0, 0.75);
|
|
419
453
|
|
|
420
|
-
/*
|
|
421
|
-
|
|
422
|
-
page
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
454
|
+
/* A distinct chrome rail, still — but a step *above* the canvas now
|
|
455
|
+
rather than below it. It used to be true black under a #0d0f13
|
|
456
|
+
page, which read as a rail. Against zinc-950 the same black is
|
|
457
|
+
three values away from the page and the rail disappeared, so the
|
|
458
|
+
separation now comes from the other direction: zinc-900, the same
|
|
459
|
+
surface as a card, which is where shadcn puts a sidebar too.
|
|
460
|
+
The frame still reads as structurally separate from content, which
|
|
461
|
+
was the point of the original choice. */
|
|
462
|
+
--sidebar-bg: #18181b;
|
|
426
463
|
--sidebar-text: var(--color-text-primary);
|
|
427
464
|
--sidebar-text-muted: var(--color-text-muted);
|
|
428
465
|
/* Two distinct white-overlay intensities on top of --sidebar-bg —
|
|
@@ -433,7 +470,7 @@
|
|
|
433
470
|
--sidebar-active-text: var(--color-text-primary);
|
|
434
471
|
--sidebar-hover-bg: rgba(255, 255, 255, 0.06);
|
|
435
472
|
--sidebar-active-icon: var(--sidebar-active-text);
|
|
436
|
-
--sidebar-rail-bg: #
|
|
473
|
+
--sidebar-rail-bg: #18181b;
|
|
437
474
|
|
|
438
475
|
color-scheme: dark;
|
|
439
476
|
}
|
|
@@ -444,15 +481,18 @@
|
|
|
444
481
|
takes the nearest declaration in the tree, so relying on :root
|
|
445
482
|
alone would lose to a dark attribute set higher up. */
|
|
446
483
|
[data-theme="light"] {
|
|
447
|
-
--color-background-global: #
|
|
484
|
+
--color-background-global: #f4f4f5;
|
|
448
485
|
--color-background-card: #ffffff;
|
|
449
|
-
--color-surface-tint: #
|
|
486
|
+
--color-surface-tint: #e8e8ea;
|
|
450
487
|
--color-input: #ffffff;
|
|
451
|
-
--color-text-primary: #
|
|
452
|
-
--color-text-secondary: #
|
|
453
|
-
--color-text-muted: #
|
|
454
|
-
--color-border:
|
|
455
|
-
--color-border-strong:
|
|
488
|
+
--color-text-primary: #09090b;
|
|
489
|
+
--color-text-secondary: #52525b;
|
|
490
|
+
--color-text-muted: #6b6b74;
|
|
491
|
+
--color-border: #e4e4e7;
|
|
492
|
+
--color-border-strong: #d4d4d8;
|
|
493
|
+
--color-surface-raised: #ffffff;
|
|
494
|
+
--color-border-raised: #d4d4d8;
|
|
495
|
+
--shadow-popover: 0 4px 6px -2px rgba(9, 9, 11, 0.08), 0 12px 28px -8px rgba(9, 9, 11, 0.18);
|
|
456
496
|
--color-hover: var(--color-surface-tint);
|
|
457
497
|
|
|
458
498
|
--color-brand: var(--color-text-primary);
|
|
@@ -517,7 +557,7 @@
|
|
|
517
557
|
--shadow-lg: none;
|
|
518
558
|
|
|
519
559
|
--sidebar-bg: var(--color-background-card);
|
|
520
|
-
--sidebar-text: #
|
|
560
|
+
--sidebar-text: #09090b;
|
|
521
561
|
--sidebar-text-muted: var(--color-text-muted);
|
|
522
562
|
--sidebar-active-bg: var(--color-surface-tint);
|
|
523
563
|
--sidebar-active-text: var(--color-text-primary);
|
|
@@ -811,17 +851,118 @@ textarea::placeholder {
|
|
|
811
851
|
bottom padding is what actually centers the selected value; the
|
|
812
852
|
native arrow's box was throwing that off by consuming space
|
|
813
853
|
asymmetrically. The open option list itself stays OS-native — no
|
|
814
|
-
browser lets CSS reach inside it.
|
|
815
|
-
|
|
854
|
+
browser lets CSS reach inside it.
|
|
855
|
+
|
|
856
|
+
`input[list]` gets the same chevron. It opens a dropdown of
|
|
857
|
+
suggestions exactly as a select does, but Chrome draws no affordance
|
|
858
|
+
for one at all — so a datalist field read as a plain text box while
|
|
859
|
+
sitting between two selects that both had an arrow. The difference
|
|
860
|
+
that remains, that you may also type a value not on the list, is the
|
|
861
|
+
right one to leave invisible: typing into a text box is
|
|
862
|
+
self-evidently allowed. */
|
|
863
|
+
/* ------------------------------------------------------------------
|
|
864
|
+
Choosing one of something: four controls, one appearance.
|
|
865
|
+
|
|
866
|
+
They are four because they do different jobs, and collapsing them
|
|
867
|
+
would cost something real each time:
|
|
868
|
+
|
|
869
|
+
select a closed set small enough to scroll. Cheap,
|
|
870
|
+
native, keyboard- and mobile-friendly.
|
|
871
|
+
Combobox a closed set too large to scroll — there are
|
|
872
|
+
4,021 customers here, and a <select> of 4,021
|
|
873
|
+
options is not a control, it is a punishment.
|
|
874
|
+
input[type=date] a date. The native one carries the OS picker,
|
|
875
|
+
typed entry, locale order and mobile wheels;
|
|
876
|
+
a hand-built calendar loses all four and is a
|
|
877
|
+
well-known accessibility swamp.
|
|
878
|
+
|
|
879
|
+
Which to reach for:
|
|
880
|
+
under ~15 fixed options, closed -> select
|
|
881
|
+
anything else -> Combobox
|
|
882
|
+
|
|
883
|
+
Not input[list]. A datalist accepts typed values, which is why it
|
|
884
|
+
looked like the right control for an open set — but its suggestion
|
|
885
|
+
popup is drawn by the browser and no CSS reaches inside it, so the
|
|
886
|
+
field opens looking like nothing else on the page. Combobox's
|
|
887
|
+
`onCreate` covers the open set with the app's own dropdown: where
|
|
888
|
+
there is no table to insert into, "creating" is just accepting the
|
|
889
|
+
typed text (see ChannelSelect, VariantSelect).
|
|
890
|
+
|
|
891
|
+
What they share is the mark at the right-hand end that says "this
|
|
892
|
+
opens something", and it is the same mark in the same place on all
|
|
893
|
+
of them. It was not: the Combobox had none at all, so a customer or
|
|
894
|
+
a warehouse read as a plain text box beside fields that plainly
|
|
895
|
+
opened.
|
|
896
|
+
------------------------------------------------------------------ */
|
|
897
|
+
select,
|
|
898
|
+
.combobox-input {
|
|
816
899
|
appearance: none;
|
|
817
900
|
-webkit-appearance: none;
|
|
818
|
-
line-height: normal;
|
|
819
901
|
padding-right: 32px;
|
|
820
902
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%23727676' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
821
903
|
background-repeat: no-repeat;
|
|
822
904
|
background-position: right 10px center;
|
|
823
905
|
}
|
|
824
906
|
|
|
907
|
+
/* Only a native select needs this, and sharing it was a bug worth
|
|
908
|
+
recording. `line-height: normal` is here to re-centre a select's
|
|
909
|
+
text after appearance:none strips the native box — a select does not
|
|
910
|
+
honour the 1.4 the other fields use. A .combobox-input is a real
|
|
911
|
+
<input> and does, so inheriting `normal` (about 1.2) made it roughly
|
|
912
|
+
three pixels shorter than the text field and the date field beside
|
|
913
|
+
it: same padding, same border, visibly smaller box.
|
|
914
|
+
|
|
915
|
+
The chevron above is what the two share. The line-height is not. */
|
|
916
|
+
select {
|
|
917
|
+
line-height: normal;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/* A date field's calendar button is drawn by the browser, not by us —
|
|
921
|
+
it cannot be swapped for the chevron above, but it can be given the
|
|
922
|
+
same weight and the same position, so a row of dates and selects
|
|
923
|
+
reads as one row of controls rather than two kinds. Sized and dimmed
|
|
924
|
+
to match; `color-scheme` (set on :root and both themes) is what
|
|
925
|
+
makes it and the popup follow the theme. */
|
|
926
|
+
input[type="date"]::-webkit-calendar-picker-indicator {
|
|
927
|
+
opacity: 0.55;
|
|
928
|
+
cursor: pointer;
|
|
929
|
+
padding: 0;
|
|
930
|
+
margin-right: 2px;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
input[type="date"]::-webkit-calendar-picker-indicator:hover {
|
|
934
|
+
opacity: 1;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/* A button that carries no button chrome — a chevron toggle, a
|
|
938
|
+
"Forgot password?" link, an inline remove. Seven of these were made
|
|
939
|
+
bare by hand with `style={{ background: "none", border: "none",
|
|
940
|
+
padding: 0 }}`, and every one of them missed the same thing: the
|
|
941
|
+
bare `button` rule above also sets `box-shadow:
|
|
942
|
+
var(--shadow-btn-primary)`, which an inline background and border
|
|
943
|
+
do not clear.
|
|
944
|
+
That was invisible while every --shadow-* token was `none`. Turning
|
|
945
|
+
them on gave each of these buttons a floating rectangle its author
|
|
946
|
+
had explicitly tried to remove — the "extra layer" behind
|
|
947
|
+
"Additional information". Declared once here so the next one cannot
|
|
948
|
+
miss it. */
|
|
949
|
+
.btn-bare {
|
|
950
|
+
background: none;
|
|
951
|
+
border: none;
|
|
952
|
+
box-shadow: none;
|
|
953
|
+
padding: 0;
|
|
954
|
+
font: inherit;
|
|
955
|
+
color: inherit;
|
|
956
|
+
cursor: pointer;
|
|
957
|
+
text-align: inherit;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
.btn-bare:hover:not(:disabled) {
|
|
961
|
+
background: none;
|
|
962
|
+
box-shadow: none;
|
|
963
|
+
transform: none;
|
|
964
|
+
}
|
|
965
|
+
|
|
825
966
|
/* Focus: the border goes to brand ink and a soft ring is drawn *by the
|
|
826
967
|
field itself*, with box-shadow rather than outline.
|
|
827
968
|
The border alone was the previous answer, after an `outline` with an
|
|
@@ -1137,10 +1278,10 @@ a.card:hover {
|
|
|
1137
1278
|
}
|
|
1138
1279
|
|
|
1139
1280
|
.modal-panel {
|
|
1140
|
-
background: var(--color-
|
|
1141
|
-
border: 1px solid var(--color-border);
|
|
1281
|
+
background: var(--color-surface-raised);
|
|
1282
|
+
border: 1px solid var(--color-border-raised);
|
|
1142
1283
|
border-radius: var(--radius-lg);
|
|
1143
|
-
box-shadow: var(--shadow-
|
|
1284
|
+
box-shadow: var(--shadow-popover);
|
|
1144
1285
|
width: 100%;
|
|
1145
1286
|
max-width: 640px;
|
|
1146
1287
|
max-height: 80vh;
|