@stonedogcode/style 0.20.1 → 0.20.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonedogcode/style",
3
- "version": "0.20.1",
3
+ "version": "0.20.3",
4
4
  "description": "A Panda CSS design system: a themeable Panda preset plus the React components built on it.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "StoneDogCode L.L.C.",
@@ -48,6 +48,9 @@
48
48
  "gate": "npm run type-check && npm run lint && npm run test",
49
49
  "//publish:stonedog-style": "Publish to npm, end to end. Run from a terminal, interactively — npm prompts for the 2FA one-time password and the login flow needs a browser. It refuses a checkout that is detached, dirty, or behind origin/main: a submodule sits detached at the consumer's gitlink by default, and publishing from one commit behind ships a tarball missing the very thing you are publishing for while looking like a success (it did, on 2026-08-04, without TitleLogo.tsx). Runs the gate, prints the tarball listing, then proves the result by installing from the registry into a temp directory.",
50
50
  "publish:stonedog-style": "bash scripts/publish-package.sh",
51
+ "publishnpm": "npm run publish:stonedog-style",
52
+ "//release": "One memorable command per repo. It cannot be called `publish`: that is a reserved npm lifecycle name, so `npm publish` inside scripts/publish-package.sh would fire it and run the whole gate and publish a second time, hitting the already-published guard and reporting a successful release as a failure.",
53
+ "release": "npm run publish:stonedog-style",
51
54
  "version:bump:patch": "npm version patch --no-git-tag-version",
52
55
  "version:bump:minor": "npm version minor --no-git-tag-version",
53
56
  "audit": "npm audit --audit-level=moderate"
@@ -1,3 +1,30 @@
1
+ "use client";
2
+
3
+ /**
4
+ * `"use client"`, and it is load-bearing.
5
+ *
6
+ * This component calls `useFontSizeProfile()` (a client hook) during its
7
+ * render. Without the directive above, the module is a Server Component in a
8
+ * consumer's App Router tree, the hook is invoked on the server, and React
9
+ * throws:
10
+ *
11
+ * Attempted to call useFontSizeProfile() from the server but
12
+ * useFontSizeProfile is on the client.
13
+ *
14
+ * Next serves that as its blank "This page couldn't load" page with no detail
15
+ * anywhere in the browser, so a consumer sees a dead route and nothing naming
16
+ * this component. Every PRD and how-to page on stonedogcode.com was unreachable
17
+ * this way (NEH-1290).
18
+ *
19
+ * Every other component here that calls the hook already declared it — this was
20
+ * the only one that did not, which is why the failure looked like something
21
+ * specific to whichever page happened to render a heading on the server.
22
+ *
23
+ * `src/components/__tests__/client-directive.test.ts` keeps this honest. It has
24
+ * to be a source assertion: a jsdom render imports the module directly, so no
25
+ * RSC boundary exists and every test here passes with or without the directive.
26
+ */
27
+
1
28
  import React from "react";
2
29
  import StyledSeparator from "./StyledSeparator";
3
30
  import StyledText from "./StyledText";
@@ -133,13 +133,24 @@ export const buttonRecipe = defineRecipe({
133
133
  pointerEvents: "none",
134
134
  },
135
135
  },
136
+ /**
137
+ * The same correction `iconButton`'s `matte` takes, for the same reason
138
+ * (NEH-881) — see the long note there.
139
+ *
140
+ * NEH-881 named only `iconButton`. These two recipes are the same control
141
+ * in two shapes and their `matte` blocks were byte-identical, including
142
+ * the inert `bgGradient` that kept the pairing guard from inspecting
143
+ * either of them. Fixing one and leaving the other would ship the defect
144
+ * under a different class name, so both move together: the same 8-of-18
145
+ * measurement applies unchanged, because it is a property of the surface
146
+ * and the text token, not of the shape of the control.
147
+ */
136
148
  matte: {
137
- bgGradient: "linear(to-b, gray.800, gray.900)",
138
149
  borderColor: "gray.700",
139
150
  borderWidth: "1px",
140
151
  boxShadow: "md",
141
152
  bg: "buttonBgAccent",
142
- color: "textPrimary",
153
+ color: "buttonTextAccent",
143
154
  borderRadius: "lg",
144
155
  fontWeight: "bold",
145
156
  },
@@ -155,13 +155,50 @@ export const buttonIconRecipe = defineRecipe({
155
155
  pointerEvents: "none",
156
156
  },
157
157
  },
158
+ /**
159
+ * The accent pairing again, and the gradient that was hiding it
160
+ * (NEH-881).
161
+ *
162
+ * This variant was filed as a different defect class: a FIXED dark
163
+ * `gray.800`→`gray.900` gradient painting over the accent fill in every
164
+ * theme, with a themed `textPrimary` glyph left dark-on-dark on top of
165
+ * it. The proposed fix was a deliberate literal `color: "white"`, as
166
+ * `box` and `input-bool` had already taken for their own `matte`.
167
+ *
168
+ * **There is no gradient.** `bgGradient` is Chakra v2 syntax; Panda has
169
+ * no such utility and no `linear()` shorthand, so it emitted
170
+ * `background-image: linear(to-b, gray.800, gray.900)` — not valid CSS,
171
+ * discarded at parse time by every engine. Chromium reads the element
172
+ * back as `background-image: none`, and the `background` shorthand
173
+ * emitted just above it had already reset `background-image` in any case.
174
+ *
175
+ * So the surface here has always been plain `buttonBgAccent`, and this is
176
+ * the ordinary NEH-796 / NEH-877 mispairing after all — `textPrimary` is
177
+ * the contract's partner for `boxBgPrimary`, not for an accent fill.
178
+ * Measured over nine host themes in both modes, 18 pairs: `textPrimary`
179
+ * is below WCAG AA on 8 of them, every one in dark mode, the worst at
180
+ * 2.15:1 (white on `#F59E0B`). `buttonTextAccent` is below AA on 0 of the
181
+ * 18, and reaches 9.78:1 on that same worst pair.
182
+ *
183
+ * Had `color: "white"` been taken as filed, it would have pinned the
184
+ * failing half of that measurement in place under a comment calling it
185
+ * deliberate — the shape where a test makes a bug unfixable by review.
186
+ *
187
+ * The dead declaration goes too, and that is not tidying. The pairing
188
+ * sweep in `variant-contrast-pairing.test.ts` reads `background-image`
189
+ * before `background`, so while the invalid gradient was emitted the
190
+ * guard took it as this variant's surface, found the token contract said
191
+ * nothing about it, and skipped the variant entirely. Removing it is what
192
+ * puts `matte` back under the guard that already covers its five
193
+ * siblings — verified by planting the old colour back and watching that
194
+ * guard name both selectors.
195
+ */
158
196
  matte: {
159
- bgGradient: "linear(to-b, gray.800, gray.900)",
160
197
  borderColor: "gray.700",
161
198
  borderWidth: "1px",
162
199
  boxShadow: "md",
163
200
  bg: "buttonBgAccent",
164
- color: "textPrimary",
201
+ color: "buttonTextAccent",
165
202
  borderRadius: "lg",
166
203
  fontWeight: "bold",
167
204
  },