@ultimat3/ui 22.3.1 → 22.3.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/CLAUDE.md CHANGED
@@ -98,6 +98,7 @@ Tier 4. Imports `@ultimat3/core`, `i18n`, `money`, `time` — **not `schema`**,
98
98
  |---|---|
99
99
  | `src/tokens/*.scss` | canonical token maps + `_mixins.scss` authoring helpers |
100
100
  | `src/tokens/theme.scss` | the only stylesheet that emits global custom properties |
101
+ | `src/tokens/reset.scss` | the reset, ZERO specificity: every rule a component may restyle sits in `:where(…)` whole, pseudo-class inside (`:where(a:hover)`, never `:where(a):hover`). `a:hover` (0,1,1) beat `.primary` and hid a button link's text until 22.3.2. `reset.test.ts` computes it |
101
102
  | `src/theme/runtime-slot.ts` | the module-scope slot holding the app's Solid runtime — and nothing else, so registering one costs an island 72 B |
102
103
  | `src/theme/solid-adapter.ts` | the runtime's SHAPE, and the one rule that decides which runtime a render gets |
103
104
  | `src/theme/inert-runtime.ts` | `INERT_SOLID_RUNTIME` — what a server render IS, not a stub of what it lacks |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/ui",
3
- "version": "22.3.1",
3
+ "version": "22.3.2",
4
4
  "description": "SolidJS design system: semantic design tokens, dark/RTL-ready SCSS modules, a11y primitives",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -48,10 +48,10 @@
48
48
  "icons": "bun run src/icons/build-icons.ts"
49
49
  },
50
50
  "dependencies": {
51
- "@ultimat3/core": "22.3.1",
52
- "@ultimat3/i18n": "22.3.1",
53
- "@ultimat3/money": "22.3.1",
54
- "@ultimat3/time": "22.3.1"
51
+ "@ultimat3/core": "22.3.2",
52
+ "@ultimat3/i18n": "22.3.2",
53
+ "@ultimat3/money": "22.3.2",
54
+ "@ultimat3/time": "22.3.2"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "solid-js": "^1.9.0"
@@ -1,6 +1,15 @@
1
1
  // Modern reset. Assumes `theme.scss` has already run — every value here is a
2
2
  // token, so the reset itself flips with the theme. Plus the one GLOBAL class the package owns:
3
3
  // the element wearing it is created by `announce()` at runtime, so no component module can hold it.
4
+ //
5
+ // ZERO SPECIFICITY, every rule a component might restyle: `:where(…)` around the whole selector
6
+ // (22.3.2). A reset is the floor, and any single class must beat it. `a:hover` is (0,1,1), so it
7
+ // beat `.primary` (0,1,0) on an `<a class="primary">` — a filled button link showed accent-strong
8
+ // text on its accent-strong hover background, i.e. no text. `:where(a):hover` is still (0,1,0):
9
+ // the pseudo-class goes INSIDE the `:where`. The rules deliberately left outside are the ones meant
10
+ // to win (the modal scroll lock, the live region, the reduced-motion guard) and `::selection`,
11
+ // which a `:where()` would drop outright — a pseudo-element is not valid inside one.
12
+ // `reset.test.ts` computes every selector's specificity.
4
13
 
5
14
  @use 'index' as t;
6
15
 
@@ -18,18 +27,18 @@
18
27
  // The `*` above outranks the UA stylesheet's `dialog { margin: auto }`, which is the ONLY thing
19
28
  // that centres a modal `<dialog>` in its viewport — so every `Dialog` and every app dialog opened
20
29
  // pinned to the top-left corner until the app restated the margin itself. Restated once, here.
21
- dialog {
30
+ :where(dialog) {
22
31
  margin: auto;
23
32
  }
24
33
 
25
- html {
34
+ :where(html) {
26
35
  -webkit-text-size-adjust: 100%;
27
36
  text-size-adjust: 100%;
28
37
  tab-size: 4;
29
38
  scroll-behavior: smooth;
30
39
  }
31
40
 
32
- body {
41
+ :where(body) {
33
42
  min-block-size: 100dvh;
34
43
  background: t.role('bg');
35
44
  color: t.role('fg');
@@ -40,12 +49,7 @@ body {
40
49
  text-rendering: optimizeLegibility;
41
50
  }
42
51
 
43
- h1,
44
- h2,
45
- h3,
46
- h4,
47
- h5,
48
- h6 {
52
+ :where(h1, h2, h3, h4, h5, h6) {
49
53
  color: t.role('fg-strong');
50
54
  font-weight: t.weight(semibold);
51
55
  line-height: t.leading(tight);
@@ -53,80 +57,69 @@ h6 {
53
57
  text-wrap: balance;
54
58
  }
55
59
 
56
- h1 { font-size: t.text(3xl); }
57
- h2 { font-size: t.text(2xl); }
58
- h3 { font-size: t.text(xl); }
59
- h4 { font-size: t.text(lg); }
60
+ :where(h1) { font-size: t.text(3xl); }
61
+ :where(h2) { font-size: t.text(2xl); }
62
+ :where(h3) { font-size: t.text(xl); }
63
+ :where(h4) { font-size: t.text(lg); }
60
64
 
61
- p,
62
- li {
65
+ :where(p, li) {
63
66
  text-wrap: pretty;
64
67
  }
65
68
 
66
- a {
69
+ :where(a) {
67
70
  color: t.role('accent');
68
71
  text-decoration-thickness: 1px;
69
72
  text-underline-offset: 0.15em;
73
+ }
70
74
 
71
- &:hover {
72
- color: t.role('accent-strong');
73
- }
75
+ :where(a:hover) {
76
+ color: t.role('accent-strong');
74
77
  }
75
78
 
76
79
  // Intrinsic ratio preserved and dimensions honoured so CLS stays at 0.
77
- img,
78
- picture,
79
- video,
80
- canvas,
81
- svg {
80
+ :where(img, picture, video, canvas, svg) {
82
81
  display: block;
83
82
  max-inline-size: 100%;
84
83
  block-size: auto;
85
84
  }
86
85
 
87
- input,
88
- button,
89
- textarea,
90
- select {
86
+ :where(input, button, textarea, select) {
91
87
  font: inherit;
92
88
  color: inherit;
93
89
  }
94
90
 
95
- button {
91
+ :where(button) {
96
92
  background: none;
97
93
  border: 0;
98
94
  cursor: pointer;
99
95
  }
100
96
 
101
- code,
102
- kbd,
103
- pre,
104
- samp {
97
+ :where(code, kbd, pre, samp) {
105
98
  font-family: var(--font-mono);
106
99
  font-size: 0.9em;
107
100
  }
108
101
 
109
- hr {
102
+ :where(hr) {
110
103
  border: 0;
111
104
  border-block-start: 1px solid t.role('line');
112
105
  }
113
106
 
114
- table {
107
+ :where(table) {
115
108
  border-collapse: collapse;
116
109
  inline-size: 100%;
117
110
  }
118
111
 
119
- :target {
112
+ :where(:target) {
120
113
  scroll-margin-block-start: var(--space-12);
121
114
  }
122
115
 
123
116
  // Themed keyboard focus for anything the component layer forgot.
124
- :focus-visible {
117
+ :where(:focus-visible) {
125
118
  outline: 2px solid t.role('accent');
126
119
  outline-offset: 2px;
127
120
  }
128
121
 
129
- :focus:not(:focus-visible) {
122
+ :where(:focus:not(:focus-visible)) {
130
123
  outline: none;
131
124
  }
132
125