@stonedogcode/style 0.9.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.
Files changed (75) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +18 -0
  3. package/README.md +699 -0
  4. package/package.json +95 -0
  5. package/src/components/DictationControls.tsx +141 -0
  6. package/src/components/DictationPrompt.tsx +78 -0
  7. package/src/components/StyledBox.tsx +174 -0
  8. package/src/components/StyledButton.tsx +144 -0
  9. package/src/components/StyledCollapsible.tsx +127 -0
  10. package/src/components/StyledDefinitionList.tsx +134 -0
  11. package/src/components/StyledFieldset.tsx +157 -0
  12. package/src/components/StyledFlex.tsx +13 -0
  13. package/src/components/StyledFooter.tsx +399 -0
  14. package/src/components/StyledFormLabel.tsx +141 -0
  15. package/src/components/StyledGrid.tsx +109 -0
  16. package/src/components/StyledGridItem.tsx +19 -0
  17. package/src/components/StyledHStack.tsx +145 -0
  18. package/src/components/StyledHeading.tsx +79 -0
  19. package/src/components/StyledHrRule.tsx +33 -0
  20. package/src/components/StyledIcon.tsx +172 -0
  21. package/src/components/StyledIconButton.tsx +135 -0
  22. package/src/components/StyledInputBool.tsx +81 -0
  23. package/src/components/StyledInputRadio.tsx +141 -0
  24. package/src/components/StyledInputSelect.tsx +115 -0
  25. package/src/components/StyledInputSlider.tsx +83 -0
  26. package/src/components/StyledInputText.tsx +146 -0
  27. package/src/components/StyledInputTextArea.tsx +119 -0
  28. package/src/components/StyledInputToggle.tsx +224 -0
  29. package/src/components/StyledList.tsx +188 -0
  30. package/src/components/StyledScrollbar.tsx +53 -0
  31. package/src/components/StyledSearch.tsx +78 -0
  32. package/src/components/StyledSeparator.tsx +38 -0
  33. package/src/components/StyledSidebar.tsx +555 -0
  34. package/src/components/StyledSimpleGrid.tsx +99 -0
  35. package/src/components/StyledSparkLine.tsx +119 -0
  36. package/src/components/StyledSpinner.tsx +91 -0
  37. package/src/components/StyledStack.tsx +62 -0
  38. package/src/components/StyledText.tsx +99 -0
  39. package/src/components/StyledTooltip.tsx +398 -0
  40. package/src/components/StyledVStack.tsx +143 -0
  41. package/src/components/TitleLogo.tsx +223 -0
  42. package/src/components/create-icon.tsx +66 -0
  43. package/src/components/create-intent-button.tsx +134 -0
  44. package/src/components/dictation.ts +71 -0
  45. package/src/components/intent-buttons.ts +154 -0
  46. package/src/config/can-hover.ts +75 -0
  47. package/src/config/density.ts +138 -0
  48. package/src/config/font-size.ts +113 -0
  49. package/src/config/intent-icons.tsx +116 -0
  50. package/src/config/logger.ts +60 -0
  51. package/src/config/style-config.tsx +263 -0
  52. package/src/config/types.ts +137 -0
  53. package/src/index.ts +259 -0
  54. package/src/preset/index.ts +243 -0
  55. package/src/preset/recipes/arrows.ts +29 -0
  56. package/src/preset/recipes/box.ts +122 -0
  57. package/src/preset/recipes/button.ts +161 -0
  58. package/src/preset/recipes/dl-list.ts +109 -0
  59. package/src/preset/recipes/drawer.ts +125 -0
  60. package/src/preset/recipes/form.ts +95 -0
  61. package/src/preset/recipes/icon-button.ts +161 -0
  62. package/src/preset/recipes/icon.ts +34 -0
  63. package/src/preset/recipes/input-bool.ts +184 -0
  64. package/src/preset/recipes/input-dropdown.ts +93 -0
  65. package/src/preset/recipes/input-radio.ts +158 -0
  66. package/src/preset/recipes/input-surface.ts +152 -0
  67. package/src/preset/recipes/input-text.ts +17 -0
  68. package/src/preset/recipes/list.ts +196 -0
  69. package/src/preset/recipes/menu.ts +28 -0
  70. package/src/preset/recipes/separator.ts +89 -0
  71. package/src/preset/recipes/stack.ts +89 -0
  72. package/src/preset/recipes/striped.ts +34 -0
  73. package/src/preset/recipes/text.ts +41 -0
  74. package/src/preset/recipes/tooltip.ts +77 -0
  75. package/src/preset/semantic-variables.ts +283 -0
@@ -0,0 +1,243 @@
1
+ import { definePreset } from "@pandacss/dev";
2
+
3
+ import { arrowRecipe } from "./recipes/arrows";
4
+ import { boxRecipe } from "./recipes/box";
5
+ import { buttonRecipe } from "./recipes/button";
6
+ import { buttonIconRecipe } from "./recipes/icon-button";
7
+ import { dlRecipe } from "./recipes/dl-list";
8
+ import { drawerRecipe } from "./recipes/drawer";
9
+ import { formRecipe } from "./recipes/form";
10
+ import { iconRecipe } from "./recipes/icon";
11
+ import { inputBoolRecipe } from "./recipes/input-bool";
12
+ import {
13
+ inputDropdownContentRecipe,
14
+ inputDropdownItemRecipe,
15
+ inputDropdownRecipe,
16
+ } from "./recipes/input-dropdown";
17
+ import { inputRadioRootRecipe } from "./recipes/input-radio";
18
+ import { inputTextRecipe } from "./recipes/input-text";
19
+ import { listRecipe } from "./recipes/list";
20
+ import { menuRecipe } from "./recipes/menu";
21
+ import {
22
+ separatorHorizontalRecipe,
23
+ separatorVerticalRecipe,
24
+ } from "./recipes/separator";
25
+ import { stackRecipe } from "./recipes/stack";
26
+ import { stripedRecipe } from "./recipes/striped";
27
+ import { textRecipe } from "./recipes/text";
28
+ import { tooltipRecipe } from "./recipes/tooltip";
29
+
30
+ import {
31
+ DEFAULT_CSS_VAR_PREFIX,
32
+ createSemanticColors,
33
+ createSemanticFontWeights,
34
+ createSemanticFonts,
35
+ createSemanticSizes,
36
+ } from "./semantic-variables";
37
+
38
+ export interface StonedogStylePresetOptions {
39
+ /**
40
+ * Namespace for the CSS custom properties the colour tokens read.
41
+ *
42
+ * `"hopper"` yields `var(--hopper-box-primary-bg)`; `"optima"` yields
43
+ * `var(--optima-box-primary-bg)`. Only change this if the host application
44
+ * emits its theme under a different namespace — the value must match whatever
45
+ * writes those properties at runtime, and a mismatch renders every colour as
46
+ * nothing at all (see semantic-variables.ts).
47
+ *
48
+ * @default "hopper"
49
+ */
50
+ cssVarPrefix?: string;
51
+ }
52
+
53
+ /**
54
+ * Every recipe, keyed by the name it is exported under in `styled-system/recipes`.
55
+ *
56
+ * Four of these (`listRecipe`, `menuRecipe`, `inputBoolRecipe`,
57
+ * `inputRadioRootRecipe`) are slot recipes declared with `defineSlotRecipe`.
58
+ * Panda accepts them here rather than under `slotRecipes` and generates them
59
+ * correctly — verified against HopperGuard's own generated output. Moving them
60
+ * to `slotRecipes` would be more "correct" by the docs and would change the
61
+ * generated surface, so it is deliberately not done during extraction.
62
+ */
63
+ const recipes = {
64
+ arrowRecipe,
65
+ boxRecipe,
66
+ buttonRecipe,
67
+ buttonIconRecipe,
68
+ dlRecipe,
69
+ drawerRecipe,
70
+ formRecipe,
71
+ iconRecipe,
72
+ inputBoolRecipe,
73
+ inputDropdownRecipe,
74
+ inputDropdownContentRecipe,
75
+ inputDropdownItemRecipe,
76
+ inputRadioRootRecipe,
77
+ inputTextRecipe,
78
+ listRecipe,
79
+ menuRecipe,
80
+ separatorHorizontalRecipe,
81
+ separatorVerticalRecipe,
82
+ stackRecipe,
83
+ stripedRecipe,
84
+ textRecipe,
85
+ tooltipRecipe,
86
+ };
87
+
88
+ /**
89
+ * Force every variant of every recipe into the stylesheet.
90
+ *
91
+ * The style variant (`solid | outline | aurora | glass | matte`) is chosen by
92
+ * the *user* at runtime, not by the code, so Panda's static extractor has no way
93
+ * to know which classes will be needed — it only ever sees `variant={variant}`.
94
+ * Without this, switching variants at runtime yields elements with class names
95
+ * that have no corresponding CSS, which fails as an unstyled component rather
96
+ * than as an error.
97
+ */
98
+ const staticCssRecipes = Object.fromEntries(
99
+ Object.keys(recipes).map((name) => [name, ["*"]]),
100
+ ) as Record<keyof typeof recipes, ["*"]>;
101
+
102
+ /**
103
+ * Force the flexbox alignment utilities into the stylesheet (NEH-288).
104
+ *
105
+ * Same reasoning as the recipes above, one layer down. `StyledHStack` and
106
+ * `StyledVStack` accept `align`/`justify` as aliases and rename them to
107
+ * `alignItems`/`justifyContent` at runtime. Panda's extractor only reads source
108
+ * text: it sees `align="baseline"`, finds no utility by that name, and generates
109
+ * nothing — yet the component emits `ai_baseline`. Same for any value the caller
110
+ * computes rather than writes as a literal.
111
+ *
112
+ * That is this package's recurring failure mode: a class name with no rule
113
+ * behind it, which produces no build error, no console warning, and renders as
114
+ * silently-wrong layout. Fourteen declarations is a cheap price for closing it.
115
+ */
116
+ const staticCssAlignment = [
117
+ {
118
+ properties: {
119
+ alignItems: ["flex-start", "flex-end", "center", "baseline", "stretch", "start", "end"],
120
+ justifyContent: [
121
+ "flex-start",
122
+ "flex-end",
123
+ "center",
124
+ "space-between",
125
+ "space-around",
126
+ "space-evenly",
127
+ "start",
128
+ "end",
129
+ ],
130
+ },
131
+ },
132
+ ];
133
+
134
+ /**
135
+ * The @stonedogcode/style Panda preset: colour tokens, breakpoints, keyframes, and
136
+ * the 22 recipes the component library is built on.
137
+ *
138
+ * Deliberately does NOT set `globalCss`, `preflight`, `include`, or `outdir` —
139
+ * those are application decisions, and a preset that quietly restyles `body` is
140
+ * a preset that is hard to adopt. The consuming app owns them. See CLAUDE.md.
141
+ */
142
+ export function stonedogStylePreset(options: StonedogStylePresetOptions = {}) {
143
+ const { cssVarPrefix = DEFAULT_CSS_VAR_PREFIX } = options;
144
+
145
+ return definePreset({
146
+ name: "@stonedogcode/style",
147
+ theme: {
148
+ extend: {
149
+ /**
150
+ * The full responsive scale, declared here rather than only the one
151
+ * value that differs from Panda's default.
152
+ *
153
+ * The originating app declared only `3xl` and inherited `sm`–`2xl` from
154
+ * `@pandacss/preset-panda`. That works right up until a consumer passes
155
+ * a `presets` array — which **replaces** Panda's defaults rather than
156
+ * adding to them — at which point `md` silently stops being a valid
157
+ * breakpoint and every responsive prop in the library becomes a type
158
+ * error, or worse, a dropped style. Restating all six makes the preset
159
+ * self-sufficient for the values its components actually reference.
160
+ *
161
+ * The base presets are still required for tokens and utilities — see
162
+ * the consumer wiring in CLAUDE.md.
163
+ */
164
+ breakpoints: {
165
+ sm: "640px",
166
+ md: "768px",
167
+ lg: "1024px",
168
+ xl: "1280px",
169
+ "2xl": "1536px",
170
+ "3xl": "1600px",
171
+ },
172
+ tokens: {
173
+ colors: createSemanticColors(cssVarPrefix),
174
+ sizes: createSemanticSizes(cssVarPrefix),
175
+ /**
176
+ * The host's typeface (NEH-289). `fontWeights` deliberately reuses
177
+ * Panda's own token names, so the `fontWeight: "bold"` already
178
+ * written across seven recipes starts reading the theme without a
179
+ * call site moving. Both carry fallbacks — see semantic-variables.
180
+ */
181
+ fonts: createSemanticFonts(cssVarPrefix),
182
+ fontWeights: createSemanticFontWeights(cssVarPrefix),
183
+ },
184
+ keyframes: {
185
+ spin: {
186
+ "0%": { transform: "rotate(0deg)" },
187
+ "100%": { transform: "rotate(360deg)" },
188
+ },
189
+ // The disabled strike-through on StyledInputToggle. A keyframe rather
190
+ // than a transition because it plays once on appearance, and there is
191
+ // no "before" state to transition from.
192
+ stonedogStrikeIn: {
193
+ "0%": { transform: "scaleX(0)" },
194
+ "100%": { transform: "scaleX(1)" },
195
+ },
196
+ },
197
+ recipes,
198
+ },
199
+ },
200
+ staticCss: {
201
+ recipes: staticCssRecipes,
202
+ css: staticCssAlignment,
203
+ },
204
+ });
205
+ }
206
+
207
+ export {
208
+ DEFAULT_CSS_VAR_PREFIX,
209
+ TEXT_BACKGROUND_PAIRS,
210
+ colorTokenNames,
211
+ createSemanticColors,
212
+ createSemanticFontWeights,
213
+ createSemanticFonts,
214
+ createSemanticSizes,
215
+ fontTokenNames,
216
+ fontWeightTokenNames,
217
+ getBackgroundForText,
218
+ requiredCssCustomProperties,
219
+ } from "./semantic-variables";
220
+
221
+ export { recipes as stonedogStyleRecipes };
222
+
223
+ /* ------------------------------------------------------------------------- *
224
+ * Deprecated `hopper*` aliases — NEH-251.
225
+ *
226
+ * The package renamed hopper-style → @stonedogcode/style. These re-exports exist so
227
+ * each consumer can bump its submodule pointer on its own schedule instead of
228
+ * every repo having to move in one lockstep sweep, which is what would make an
229
+ * ordered set of PRs impossible.
230
+ *
231
+ * They are a migration seam with an end date, not a compatibility promise.
232
+ * Remove them once HopperGuard, optima-filings and optima-cloud-saas have all
233
+ * landed their consumer PRs.
234
+ * ------------------------------------------------------------------------- */
235
+
236
+ /** @deprecated Renamed to `stonedogStylePreset`. Removed once every consumer has migrated (NEH-251). */
237
+ export const hopperStylePreset = stonedogStylePreset;
238
+
239
+ /** @deprecated Renamed to `StonedogStylePresetOptions`. Removed once every consumer has migrated (NEH-251). */
240
+ export type HopperStylePresetOptions = StonedogStylePresetOptions;
241
+
242
+ /** @deprecated Renamed to `stonedogStyleRecipes`. Removed once every consumer has migrated (NEH-251). */
243
+ export { recipes as hopperStyleRecipes };
@@ -0,0 +1,29 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const arrowRecipe = defineRecipe({
4
+ className: "arrow",
5
+ description: "The style for an arrow",
6
+ base: {
7
+ width: "0",
8
+ height: "0",
9
+ },
10
+ variants: {
11
+ variant: {
12
+ solid: {
13
+ "--arrow-color": "red",
14
+ },
15
+ outline: {
16
+ "--arrow-color": "red",
17
+ },
18
+ aurora: {
19
+ "--arrow-color": "red",
20
+ },
21
+ glass: {
22
+ "--arrow-color": "red",
23
+ },
24
+ matte: {
25
+ "--arrow-color": "red",
26
+ },
27
+ },
28
+ },
29
+ });
@@ -0,0 +1,122 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const boxRecipe = defineRecipe({
4
+ className: "box",
5
+ description: "The styles for the Box component",
6
+ base: {
7
+ display: "flex",
8
+ flexDirection: "column",
9
+ width: "100%",
10
+ },
11
+ variants: {
12
+ variant: {
13
+ none: {
14
+ border: "none",
15
+ backgroundColor: "transparent",
16
+ },
17
+ unstyled: {
18
+ border: "none",
19
+ backgroundColor: "transparent",
20
+ },
21
+ solid: {
22
+ px: { base: 6, md: 8 },
23
+ py: { base: 2, md: 4 },
24
+ bg: "boxBgPrimary",
25
+ color: "textPrimary",
26
+ },
27
+ outline: {
28
+ px: { base: 6, md: 8 },
29
+ py: { base: 2, md: 4 },
30
+ border: "1px solid",
31
+ borderColor: "borderBgSecondary",
32
+ color: "textPrimary",
33
+ bg: "boxBgPrimary",
34
+ },
35
+ link: {
36
+ bg: "boxBgPrimary",
37
+ _hover: {
38
+ textDecoration: "underline",
39
+ },
40
+ },
41
+ aurora: {
42
+ px: { base: 6, md: 8 },
43
+ py: { base: 2, md: 4 },
44
+ border: "1px solid",
45
+ borderRadius: "md",
46
+ backgroundImage: "linear-gradient(to right, #ff7e5f, #feb47b)",
47
+ color: "textPrimary",
48
+ borderColor: "borderBgSecondary",
49
+ },
50
+ glass: {
51
+ px: { base: 6, md: 8 },
52
+ py: { base: 2, md: 4 },
53
+ position: "relative",
54
+ overflow: "hidden",
55
+ borderRadius: "2xl", // more rounded for curved glass effect
56
+ borderWidth: "2px",
57
+ borderStyle: "solid",
58
+ bg: "boxBgSecondary/60",
59
+ color: "textPrimary",
60
+ boxShadow: "xl",
61
+ fontWeight: "bold",
62
+ borderColor: "borderBgPrimary/10",
63
+ _before: {
64
+ content: '""',
65
+ position: "absolute",
66
+ top: 0,
67
+ left: 0,
68
+ right: 0,
69
+ bottom: 0,
70
+ borderRadius: "inherit",
71
+ bgGradient:
72
+ "linear(to-br, rgba(255,255,255,0.08), rgba(255,255,255,0.02))",
73
+ zIndex: -1,
74
+ },
75
+ },
76
+ matte: {
77
+ px: { base: 6, md: 8 },
78
+ py: { base: 2, md: 4 },
79
+ bgGradient: "linear(to-b, gray.800, gray.900)",
80
+ borderColor: "gray.700",
81
+ borderWidth: "1px",
82
+ boxShadow: "md",
83
+ /**
84
+ * `whiteAlpha.900` was undefined vocabulary, so this never painted and
85
+ * matte text inherited whatever it landed on — dark-on-dark against
86
+ * the fixed gradient above (NEH-301).
87
+ *
88
+ * `white`, not a token, and that is deliberate. The surface here is
89
+ * `gray.800`→`gray.900`: a FIXED dark gradient that does not follow the
90
+ * host's theme. Pointing the text at a host token while the surface
91
+ * stays fixed is how you get dark-on-dark in a light theme — a
92
+ * contrast regression traded for a style-rule win. The literal is the
93
+ * honest description of what matte currently is, and it joins the
94
+ * tracked literal-colour cleanup (`gray.*`, `black`/`white` in
95
+ * input-text.ts) that has to move the surface and the text together.
96
+ */
97
+ color: "white",
98
+ borderRadius: "lg",
99
+ fontWeight: "bold",
100
+ },
101
+ ghost: {
102
+ px: { base: 6, md: 8 },
103
+ py: { base: 2, md: 4 },
104
+ color: "textSecondary",
105
+ bg: "boxBgSecondary",
106
+ },
107
+ },
108
+ layout: {
109
+ vertical: {}, // Base is already vertical
110
+ horizontal: {
111
+ flexDirection: { base: "column", lg: "row" },
112
+ gap: 4,
113
+ alignItems: "center",
114
+ },
115
+ },
116
+ clickable: {
117
+ true: {
118
+ cursor: "pointer",
119
+ },
120
+ },
121
+ },
122
+ });
@@ -0,0 +1,161 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const buttonRecipe = defineRecipe({
4
+ className: "button",
5
+ base: {
6
+ display: "inline-flex",
7
+ alignItems: "center",
8
+ justifyContent: "center",
9
+ // A `<button>` does not inherit the page font — see input-surface (NEH-289).
10
+ fontFamily: "body",
11
+ fontWeight: "semibold",
12
+ padding: "calc(.2rem + var(--panda-density-padding, 8px))",
13
+ /**
14
+ * The tap-target floor, enforced structurally (NEH-220, NEH-251).
15
+ *
16
+ * Until now this recipe set no minimum and the button's size *emerged*
17
+ * from padding plus the inherited font size. That looked fine and was not:
18
+ * a short label produced a 42.375px-tall control against a 44px
19
+ * requirement, and the two component tests asserting the floor were marked
20
+ * `test.fail()` — the requirement was documented, visible, and unmet.
21
+ *
22
+ * Emergent sizing is also fragile in a way a constant is not. The font
23
+ * scale is host-tunable and just moved (md 1.375rem -> 1rem), which drops
24
+ * every button that depends on font size for its height. A floor that
25
+ * survives a typography change has to be stated, not derived.
26
+ */
27
+ minHeight: "48px",
28
+ minWidth: "48px",
29
+ _hover: {
30
+ cursor: "pointer",
31
+ },
32
+ border: "1px solid",
33
+ borderColor: "borderBgPrimary",
34
+ borderRadius: "var(--radii-md, 0.375rem)",
35
+ },
36
+ variants: {
37
+ variant: {
38
+ solid: {
39
+ bg: "buttonBgAccent",
40
+ color: "textPrimary",
41
+ _hover: {
42
+ bg: "buttonBgSecondary",
43
+ color: "textPrimary",
44
+ },
45
+ },
46
+ outline: {
47
+ bg: "buttonBgAccent",
48
+ border: "2px solid",
49
+ borderRadius: 0,
50
+ _hover: {
51
+ border: "2px solid",
52
+ bg: "buttonBgAccentHover",
53
+ },
54
+ },
55
+ aurora: {
56
+ backgroundImage: "linear-gradient(to right, #ff7e5f, #feb47b)",
57
+ color: "buttonTextPrimary",
58
+ _hover: {
59
+ opacity: 0.9,
60
+ },
61
+ },
62
+ glass: {
63
+ position: "relative",
64
+ overflow: "hidden",
65
+ border: "2px solid",
66
+ borderRadius: "xl",
67
+ bg: "buttonBgAccent",
68
+ color: "textPrimary",
69
+ boxShadow: "0 8px 32px rgba(0,0,0,0.2)",
70
+ backdropFilter: "blur(12px)",
71
+ WebkitBackdropFilter: "blur(12px)",
72
+ fontWeight: "bold",
73
+ lineHeight: "shorter",
74
+ transition: "all 0.3s ease",
75
+ _hover: {
76
+ bg: "buttonBgSecondary",
77
+ borderColor: "rgba(255,255,255,0.4)",
78
+ boxShadow: "0 8px 32px rgba(0,0,0,0.3), inset 0 0 20px rgba(255,255,255,0.1)",
79
+ transform: "translateY(-1px)",
80
+ textDecoration: "none",
81
+ },
82
+ _active: {
83
+ transform: "translateY(0)",
84
+ bg: "rgba(255,255,255,0.15)",
85
+ },
86
+ _before: {
87
+ content: '""',
88
+ position: "absolute",
89
+ top: 0,
90
+ left: 0,
91
+ right: 0,
92
+ bottom: "50%",
93
+ borderRadius: "inherit",
94
+ bg: "linear-gradient(to bottom, rgba(255,255,255,0.15), transparent)",
95
+ zIndex: 0,
96
+ pointerEvents: "none",
97
+ },
98
+ },
99
+ matte: {
100
+ bgGradient: "linear(to-b, gray.800, gray.900)",
101
+ borderColor: "gray.700",
102
+ borderWidth: "1px",
103
+ boxShadow: "md",
104
+ bg: "buttonBgAccent",
105
+ color: "textPrimary",
106
+ borderRadius: "lg",
107
+ fontWeight: "bold",
108
+ },
109
+ ghost: {
110
+ bg: "boxBgSecondary/90",
111
+ color: "textPrimary",
112
+ _hover: {
113
+ bg: "boxBgSecondary",
114
+ },
115
+ },
116
+ selected: {
117
+ color: "textPrimary",
118
+ border: "3px dashed black",
119
+ borderRadius: "xl",
120
+ bg: "boxBgAccent",
121
+ },
122
+ none: {
123
+ color: "textMain",
124
+ bg: "white"
125
+ },
126
+ unstyled: {
127
+ color: "inherit",
128
+ border: "none",
129
+ backgroundColor: "transparent",
130
+ },
131
+ link: {
132
+ color: "textMain",
133
+ /**
134
+ * Stated, not omitted (NEH-307).
135
+ *
136
+ * A `<button>` that declares no background does not render
137
+ * transparent — the user agent paints its own `ButtonFace`, a system
138
+ * grey that ignores the theme and moves with the browser's colour
139
+ * scheme (measured: `rgb(239,239,239)` light, `rgb(107,107,107)`
140
+ * dark). This preset sets `preflight: false` and imposes no reset on
141
+ * its consumers, so there is nothing between this recipe and the UA's
142
+ * paint except this line. `unstyled` has always said it; `link` was
143
+ * the only one of the ten variants that did not.
144
+ *
145
+ * Transparent is the right answer for a link-styled button — the
146
+ * themed surface behind it should show through — but silence gets the
147
+ * browser's grey, not transparency.
148
+ */
149
+ backgroundColor: "transparent",
150
+ border: "1px solid transparent",
151
+ textDecoration: "underline",
152
+ _hover: {
153
+ color: "buttonTextAccent",
154
+ },
155
+ _active: {
156
+ color: "buttonTextSecondary",
157
+ },
158
+ },
159
+ },
160
+ },
161
+ });
@@ -0,0 +1,109 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const dlRecipe = defineRecipe({
4
+ className: "dl-list",
5
+ base: {
6
+ border: "1px solid",
7
+ borderRadius: "md",
8
+ // Was a literal `purple` (NEH-301): it rendered, but it was the same
9
+ // purple in every theme and in every colour mode. The row separators
10
+ // below already use this token — the outer border had simply never been
11
+ // moved onto it.
12
+ borderColor: "borderBgPrimary",
13
+ // Add vertical padding and margin between dt/dd pairs
14
+ "& > dt, & > dd": {
15
+ paddingTop: "0.5rem",
16
+ paddingBottom: "0.5rem",
17
+ },
18
+ "& > dt:not(:first-child), & > dd:not(:first-child)": {
19
+ marginTop: "0.5rem",
20
+ },
21
+ // The separator was `& > li`, which a `<dl>` never contains — the rule was
22
+ // valid, and matched nothing, so the row separators had never once
23
+ // rendered (NEH-167, cycle 9). `dd` puts the line after each completed
24
+ // pair; `dt` would have drawn it between a term and its own definition.
25
+ //
26
+ // Merged into the existing `dd` rule rather than added beside it: a second
27
+ // key with the same selector is a duplicate object key, and the later one
28
+ // replaces the earlier wholesale — which would have dropped this margin.
29
+ "& > dd:not(:last-child)": {
30
+ marginBottom: "0.5rem",
31
+ borderBottom: "1px solid",
32
+ borderColor: "borderBgPrimary",
33
+ },
34
+ },
35
+ variants: {
36
+ variant: {
37
+ solid: {
38
+ // `bgAccent` was Chakra vocabulary this package never defined, so the
39
+ // surface never painted (NEH-301). `textAccent` rather than
40
+ // `textPrimary` because TEXT_BACKGROUND_PAIRS is what a host's
41
+ // contrast check reads: text on `boxBgAccent` must be `textAccent`, or
42
+ // the pair that gets validated is not the pair that renders.
43
+ bg: "boxBgAccent",
44
+ color: "textAccent",
45
+ borderColor: "borderBgPrimary",
46
+ },
47
+ outline: {
48
+ borderColor: "borderBgSecondary",
49
+ color: "textPrimary",
50
+ "& > dd:not(:last-child)": {
51
+ borderBottom: "1px solid",
52
+ borderColor: "borderBgSecondary",
53
+ },
54
+ },
55
+ aurora: {
56
+ // The token names were QUOTED, so they were CSS strings, so the whole
57
+ // gradient was invalid and this variant had no background at all
58
+ // (NEH-301). `{colors.X}` is the syntax that actually substitutes a
59
+ // token inside an arbitrary value — see drawerRecipe, the one aurora
60
+ // that has been rendering. Surface tokens, not `textPrimary`: this is
61
+ // a background.
62
+ backgroundImage: `linear-gradient(to right, {colors.boxBgAccent}, {colors.boxBgSecondary})`,
63
+ color: "textPrimary",
64
+ borderColor: "transparent",
65
+ "& > dd:not(:last-child)": {
66
+ borderBottom: "1px solid",
67
+ borderColor: "borderBgPrimary",
68
+ },
69
+ },
70
+ glass: {
71
+ backdropFilter: "blur(10px)",
72
+ backgroundColor: "rgba(255, 255, 255, 0.1)",
73
+ border: "1px solid rgba(255, 255, 255, 0.2)",
74
+ color: "textPrimary",
75
+ "& > dd:not(:last-child)": {
76
+ borderBottom: "1px solid rgba(255, 255, 255, 0.2)",
77
+ },
78
+ },
79
+ matte: {
80
+ // `secondary` was undefined vocabulary — the surface never painted
81
+ // (NEH-301). Paired text, per TEXT_BACKGROUND_PAIRS.
82
+ bg: "boxBgSecondary",
83
+ color: "textSecondary",
84
+ borderColor: "borderBgPrimary",
85
+ "& > dd:not(:last-child)": {
86
+ borderBottom: "1px solid",
87
+ borderColor: "borderBgPrimary",
88
+ },
89
+ },
90
+ none: {
91
+ border: "none",
92
+ backgroundColor: "inherit",
93
+ "& > dd:not(:last-child)": {
94
+ borderBottom: "1px solid",
95
+ borderColor: "borderBgPrimary",
96
+ },
97
+ },
98
+ unstyled: {
99
+ border: "none",
100
+ p: "0",
101
+ m: "0",
102
+ backgroundColor: "inherit",
103
+ "& > dd:not(:last-child)": {
104
+ borderBottom: "none",
105
+ },
106
+ },
107
+ },
108
+ },
109
+ });