@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. 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.6",
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: #f7f8fa;
35
+ --color-background-global: #f4f4f5;
36
36
  --color-background-card: #ffffff;
37
- --color-surface-tint: #f0f2f6;
37
+ --color-surface-tint: #e8e8ea;
38
38
  --color-input: #ffffff;
39
- --color-text-primary: #10141a;
39
+ --color-text-primary: #09090b;
40
40
  /* ~6.4:1 on card */
41
- --color-text-secondary: #4b5563;
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: #5f6874;
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: rgba(16, 20, 26, 0.09);
49
- --color-border-strong: rgba(16, 20, 26, 0.16);
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(16, 20, 26, 0.14);
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(16, 20, 26, 0.04);
195
- --shadow-sm: 0 1px 2px rgba(16, 20, 26, 0.05), 0 2px 8px -3px rgba(16, 20, 26, 0.08);
196
- --shadow-md: 0 2px 4px -1px rgba(16, 20, 26, 0.04), 0 8px 20px -4px rgba(16, 20, 26, 0.12);
197
- --shadow-lg: 0 4px 8px -2px rgba(16, 20, 26, 0.06), 0 20px 48px -12px rgba(16, 20, 26, 0.22);
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: #0d0f13;
324
- --color-background-card: #16191e;
325
- --color-surface-tint: #1f232a;
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: #e9ebef;
359
+ --color-text-primary: #fafafa;
331
360
  /* ~7:1 on card */
332
- --color-text-secondary: #9ba4b2;
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: #8b94a2;
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: rgba(233, 235, 239, 0.10);
338
- --color-border-strong: rgba(233, 235, 239, 0.18);
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: #0d0f13;
397
+ --color-brand-text: #09090b;
364
398
 
365
- --shadow-btn-primary: 0 1px 2px rgba(16, 20, 26, 0.12);
366
- --shadow-btn-secondary: 0 1px 2px rgba(16, 20, 26, 0.05);
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
- /* Deliberately NOT --color-background-card — the sidebar is now a
421
- distinct chrome rail, true black, sitting a full step below the
422
- page canvas rather than matching the card surface. Common
423
- enterprise-dark-theme pattern (VS Code's activity bar, Slack's
424
- rail): the frame reads as structurally separate from content. */
425
- --sidebar-bg: #000000;
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: #000000;
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: #f7f8fa;
484
+ --color-background-global: #f4f4f5;
448
485
  --color-background-card: #ffffff;
449
- --color-surface-tint: #f0f2f6;
486
+ --color-surface-tint: #e8e8ea;
450
487
  --color-input: #ffffff;
451
- --color-text-primary: #10141a;
452
- --color-text-secondary: #4b5563;
453
- --color-text-muted: #5f6874;
454
- --color-border: rgba(16, 20, 26, 0.09);
455
- --color-border-strong: rgba(16, 20, 26, 0.16);
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: #10141a;
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
- select {
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-background-card);
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-lg);
1284
+ box-shadow: var(--shadow-popover);
1144
1285
  width: 100%;
1145
1286
  max-width: 640px;
1146
1287
  max-height: 80vh;