@stonedogcode/style 0.12.0 → 0.13.0

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.
@@ -24,9 +24,16 @@ export const inputBoolRecipe = defineSlotRecipe({
24
24
  * Verified in the component-test harness rather than assumed: a raw
25
25
  * checkbox given a red 2px border and a slate background paints as the
26
26
  * default white box. The UA draws the widget and discards
27
- * `background-color`, `border-*` and `border-radius` — while
28
- * `getComputedStyle` cheerfully reports all of them, which is what made
29
- * this recipe look styled for so long.
27
+ * `background-color` and `border-*` — while `getComputedStyle`
28
+ * cheerfully reports both, which is what made this recipe look styled
29
+ * for so long.
30
+ *
31
+ * `border-radius` is worse still and worth separating out (NEH-310): it
32
+ * does not even COMPUTE. A control set to `9999px` reports `0px`, so it
33
+ * cannot be asserted on, cannot be differed by, and is not merely
34
+ * invisible. The `borderRadius: "md"` below is therefore inert too; it is
35
+ * kept only because it belongs to the same `appearance: none` fallback
36
+ * set as `border` and `background-color`.
30
37
  *
31
38
  * The three it DOES honour, and therefore the only levers here:
32
39
  * `accent-color` (the checked fill and tick), `box-shadow` (painted
@@ -77,9 +84,21 @@ export const inputBoolRecipe = defineSlotRecipe({
77
84
  *
78
85
  * `buttonRecipe` expresses outline as a 2px edge with squared corners.
79
86
  * A native checkbox discards `border`, so the same reading is carried by
80
- * a `box-shadow` ring, which it does paint — squared to match, and
81
- * themed. `solid` states `none` explicitly rather than by omission, so
82
- * switching between them cannot leave a ring behind.
87
+ * a `box-shadow` ring, which it does paint — themed. `solid` states
88
+ * `none` explicitly rather than by omission, so switching between them
89
+ * cannot leave a ring behind.
90
+ *
91
+ * **The squared corners were dropped in NEH-310, because they never
92
+ * existed.** This comment used to say the ring was "squared to match",
93
+ * and the variant carried `borderRadius: "0"` to do it. Probed in the
94
+ * harness: Chromium computes `border-radius: 0px` on a checkbox at
95
+ * `appearance: auto` **whatever the stylesheet says** — a control set to
96
+ * `9999px` reports `0px`, while a plain `<span>` beside it reports its
97
+ * `12px` correctly. So the property is not merely discarded at paint
98
+ * time like `background-color`; it does not even compute, and no variant
99
+ * here can differ by corner. The declaration is removed rather than left
100
+ * as decoration, since a recipe full of inert declarations is the exact
101
+ * condition that made this defect take three issues to find.
83
102
  */
84
103
  solid: {
85
104
  control: {
@@ -100,18 +119,60 @@ export const inputBoolRecipe = defineSlotRecipe({
100
119
  * different — and made a ticked outline checkbox a dark box on a dark
101
120
  * surface, which is the checked state, the one thing the control
102
121
  * exists to communicate. Distinguishing an appearance must not cost
103
- * state legibility, so the difference is carried entirely by the ring
104
- * and the corners.
122
+ * state legibility, so the difference is carried entirely by the
123
+ * ring.
105
124
  */
106
125
  accentColor: "buttonBgPrimary",
107
126
  boxShadow: "0 0 0 2px {colors.borderBgPrimary}",
108
- borderRadius: "0",
109
127
  },
110
128
  },
129
+ /**
130
+ * The remaining variants, given a painted difference (NEH-310).
131
+ *
132
+ * NEH-234 fixed `solid` vs `outline` and stopped there, so these still
133
+ * differed only in `background`, `background-image`, `color` and a
134
+ * pseudo-element — every one of which this control discards. A user
135
+ * picking `aurora` app-wide watched every other control change and every
136
+ * checkbox stay put: the same complaint NEH-234 was filed for, one layer
137
+ * down.
138
+ *
139
+ * ## The rule they all follow
140
+ *
141
+ * **Appearance is carried by the ring; the checked colour never varies.**
142
+ *
143
+ * Not a stylistic choice — it is the lesson recorded on `outline` above.
144
+ * Giving a variant a recessive `accentColor` did make it more distinct,
145
+ * and made a ticked box dark-on-dark: illegible in the one state the
146
+ * control exists to communicate. So every variant keeps
147
+ * `accentColor: buttonBgPrimary` and differs by `box-shadow` alone.
148
+ *
149
+ * `outline` (the CSS property) is not available as a lever either: it is
150
+ * the focus ring, and a variant using it would look permanently focused.
151
+ * `border-radius` is not available because it does not even COMPUTE here
152
+ * — see the note on the `outline` variant.
153
+ *
154
+ * ## What this deliberately does NOT attempt
155
+ *
156
+ * `aurora` is a gradient and `glass` is a blur; a box-shadow ring is
157
+ * neither. These are **approximations** — a two-tone ring, a soft halo —
158
+ * not renderings of the intent. The real thing needs `appearance: none`
159
+ * plus a hand-drawn tick, which means owning forced-colors mode and every
160
+ * engine's default widget, and this repo's CT tier is Chromium-only so it
161
+ * cannot answer that. NEH-310 names it as option 2 and says it needs
162
+ * someone to look at the result in more than one engine.
163
+ *
164
+ * The unpainted `bg` / `color` / gradient declarations are left exactly
165
+ * as they were, per the note in `base`.
166
+ */
111
167
  aurora: {
112
168
  control: {
113
169
  backgroundImage: "linear-gradient(to right, #ff7e5f, #feb47b)",
114
170
  color: "buttonTextPrimary",
171
+ accentColor: "buttonBgPrimary",
172
+ // Two stops, two rings — the nearest a box-shadow gets to the
173
+ // gradient this variant means. Layers paint inner-first.
174
+ boxShadow:
175
+ "0 0 0 2px {colors.borderBgAccent}, 0 0 0 4px {colors.borderBgPrimary}",
115
176
  },
116
177
  },
117
178
  glass: {
@@ -120,7 +181,6 @@ export const inputBoolRecipe = defineSlotRecipe({
120
181
  overflow: "hidden",
121
182
  bg: "buttonBgPrimary/20",
122
183
  color: "textPrimary/10",
123
- boxShadow: "xl",
124
184
  backdropFilter: "blur(8px)",
125
185
  fontWeight: "bold",
126
186
  lineHeight: "shorter",
@@ -135,6 +195,19 @@ export const inputBoolRecipe = defineSlotRecipe({
135
195
  "linear(to-br, rgba(255,255,255,0.1), rgba(255,255,255,0.05))",
136
196
  zIndex: -1,
137
197
  },
198
+ accentColor: "buttonBgPrimary",
199
+ // A soft halo rather than a hard edge — the nearest painted reading
200
+ // of "frosted".
201
+ //
202
+ // This REPLACES the `boxShadow: "xl"` this variant used to carry
203
+ // (removed above, not shadowed — a second `boxShadow` key here was a
204
+ // TS1117 duplicate-property error that the CSS build silently
205
+ // resolved in favour of the last one). `xl` was the only thing glass
206
+ // ever painted, and it is Panda's own neutral shadow: the same grey
207
+ // in every theme this package can wear, which is the one thing a
208
+ // themeable package must not ship.
209
+ boxShadow:
210
+ "0 0 0 1px {colors.borderBgSecondary}, 0 0 12px 2px {colors.boxshadowBgAccent}",
138
211
  },
139
212
  },
140
213
  matte: {
@@ -145,18 +218,46 @@ export const inputBoolRecipe = defineSlotRecipe({
145
218
  // is a FIXED dark gradient, so themed text on it risks dark-on-dark.
146
219
  color: "white",
147
220
  fontWeight: "bold",
221
+ accentColor: "buttonBgPrimary",
222
+ // Wide, blurred and low-contrast: a matte surface absorbs light
223
+ // rather than edging it. The only soft-edged ring in the set, so it
224
+ // cannot be mistaken for `outline` at a glance.
225
+ boxShadow: "0 2px 8px 0 {colors.boxshadowBgSecondary}",
148
226
  },
149
227
  },
150
228
  ghost: {
151
229
  control: {
152
230
  color: "textSecondary",
153
231
  bg: "buttonBgSecondary",
232
+ accentColor: "buttonBgPrimary",
233
+ // The thinnest ring in the set, in the secondary border colour.
234
+ // `ghost` means "present but not asserting itself", which every other
235
+ // recipe expresses by having no fill — exactly the property this
236
+ // control discards.
237
+ boxShadow: "0 0 0 1px {colors.borderBgSecondary}",
154
238
  },
155
239
  },
240
+ /**
241
+ * `none` is the one variant that CANNOT be distinguished, and saying so
242
+ * is more useful than inventing a difference (NEH-310).
243
+ *
244
+ * Every lever this control has is additive — a ring, a halo, a checked
245
+ * colour. `none` means "do not style this", so the only honest rendering
246
+ * of it is the bare widget, which is what `solid` already is. Giving it a
247
+ * ring to make a test pass would mean the variant named `none` was the
248
+ * only one wearing decoration.
249
+ *
250
+ * So `none` and `solid` render identically, deliberately, and the
251
+ * component test asserts that pair is equal rather than skipping it —
252
+ * so if a future `appearance: none` redesign (option 2 on NEH-310) makes
253
+ * them separable, the test says so instead of quietly passing.
254
+ */
156
255
  none: {
157
256
  control: {
158
257
  color: "buttonTextPrimary",
159
258
  bg: "gray.300",
259
+ accentColor: "buttonBgPrimary",
260
+ boxShadow: "none",
160
261
  },
161
262
  },
162
263
  button: {