@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,125 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const drawerRecipe = defineRecipe({
4
+ className: "drawer",
5
+ base: {
6
+ position: "fixed",
7
+ zIndex: "modal",
8
+ border: "1px solid",
9
+ borderColor: "borderBgPrimary",
10
+ px: { base: 2, md: 4 },
11
+ py: { base: 2, md: 4 },
12
+ background: "boxBgAccent",
13
+ color: "textPrimary",
14
+ boxShadow: "lg", // Use token for shadow
15
+ outline: "none",
16
+ transition: "transform 0.3s ease-in-out", // Smooth transition
17
+ display: "flex",
18
+ flexDirection: "column",
19
+ _focusVisible: {
20
+ outline: "3px solid token(colors.accent)",
21
+ outlineOffset: "2px",
22
+ },
23
+ },
24
+ variants: {
25
+ variant: {
26
+ solid: {
27
+ bg: "boxBgSecondary",
28
+ color: "textSecondary", // Updated to match tokens
29
+ },
30
+ outline: {
31
+ bg: "boxBgPrimary", // Changed from inherit to a specific background to avoid transparency issue if that's the intent, or keep inherit if it should be transparent but with border. User complained about transparency. Let's try matching solid but with border.
32
+ color: "textPrimary",
33
+ border: "1px solid",
34
+ borderColor: "borderBgPrimary",
35
+ },
36
+ aurora: {
37
+ // Token references, not literal `var(--hopper-…)`: the custom-property
38
+ // prefix is configurable per consumer, so a hardcoded namespace paints
39
+ // nothing for any host that chose a different one.
40
+ backgroundImage:
41
+ "linear-gradient(to right, {colors.boxBgAccent}, {colors.boxBgSecondary})",
42
+ color: "white",
43
+ borderColor: "transparent",
44
+ textShadow: "0 1px 2px rgba(0,0,0,0.5)",
45
+ },
46
+ glass: {
47
+ bg: "boxBgSecondary",
48
+ color: "textSecondary",
49
+ backdropFilter: "blur(15px)",
50
+ borderWidth: "1px",
51
+ borderColor: "borderBgSecondary/20",
52
+ boxShadow: "2xl",
53
+ lineHeight: "base",
54
+ },
55
+ matte: {
56
+ bg: "boxBgSecondary",
57
+ color: "textSecondary",
58
+ borderColor: "borderBgSecondary",
59
+ },
60
+ none: {},
61
+ },
62
+ placement: {
63
+ left: {
64
+ top: 0,
65
+ left: 0,
66
+ height: "100dvh",
67
+ width: { base: "100%", sm: "375px", md: "450px", lg: "600px" },
68
+ },
69
+ right: {
70
+ top: 0,
71
+ right: 0,
72
+ height: "100dvh",
73
+ width: { base: "100%", sm: "375px", md: "450px", lg: "600px" },
74
+ },
75
+ top: {
76
+ top: 0,
77
+ left: 0,
78
+ right: 0,
79
+ width: "100vw",
80
+ height: "auto",
81
+ },
82
+ bottom: {
83
+ bottom: 0,
84
+ left: 0,
85
+ right: 0,
86
+ width: "100vw",
87
+ height: "auto",
88
+ },
89
+ },
90
+ open: {
91
+ true: {
92
+ transform: "none", // Drawer is visible
93
+ },
94
+ false: {}, // Handled by compound variants
95
+ },
96
+ },
97
+ // Use compound variants to combine placement and state for a clean API
98
+ compoundVariants: [
99
+ {
100
+ placement: "left",
101
+ open: false,
102
+ css: { transform: "translateX(-100%)" },
103
+ },
104
+ {
105
+ placement: "right",
106
+ open: false,
107
+ css: { transform: "translateX(100%)" },
108
+ },
109
+ {
110
+ placement: "top",
111
+ open: false,
112
+ css: { transform: "translateY(-100%)" },
113
+ },
114
+ {
115
+ placement: "bottom",
116
+ open: false,
117
+ css: { transform: "translateY(100%)" },
118
+ },
119
+ ],
120
+ defaultVariants: {
121
+ variant: "solid",
122
+ placement: "right",
123
+ open: false,
124
+ },
125
+ });
@@ -0,0 +1,95 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const formRecipe = defineRecipe({
4
+ className: "form",
5
+ base: {
6
+ border: "1px solid",
7
+ borderRadius: "md",
8
+ p: "4",
9
+ "& > li:not(:last-child)": {
10
+ borderBottom: "1px solid",
11
+ borderColor: "borderBgPrimary",
12
+ },
13
+ },
14
+ variants: {
15
+ variant: {
16
+ solid: {
17
+ bg: "boxBgAccent",
18
+ color: "textPrimary",
19
+ borderColor: "borderBgPrimary",
20
+ "& > li:not(:last-child)": {
21
+ borderBottom: "1px solid",
22
+ borderColor: "borderBgPrimary",
23
+ },
24
+ },
25
+ outline: {
26
+ borderColor: "borderBgPrimary",
27
+ color: "textPrimary",
28
+ _hover: {
29
+ bg: "boxBgAccent",
30
+ },
31
+ "& > li:not(:last-child)": {
32
+ borderBottom: "1px solid",
33
+ borderColor: "borderBgPrimary",
34
+ },
35
+ },
36
+ lines: {
37
+ border: "none",
38
+ borderRadius: "md",
39
+ p: "4",
40
+ color: "black",
41
+ "& > li:not(:last-child)": {
42
+ borderBottom: "1px solid",
43
+ borderColor: "borderBgPrimary",
44
+ },
45
+ },
46
+ aurora: {
47
+ // Quoted token names are CSS strings, so this gradient was invalid and
48
+ // never painted (NEH-301). `{colors.X}` is the substituting syntax.
49
+ backgroundImage: `linear-gradient(to right, {colors.boxBgAccent}, {colors.boxBgSecondary})`,
50
+ color: "textPrimary",
51
+ borderColor: "transparent",
52
+ "& > li:not(:last-child)": {
53
+ borderBottom: "1px solid",
54
+ borderColor: "borderBgPrimary",
55
+ },
56
+ },
57
+ glass: {
58
+ backdropFilter: "blur(10px)",
59
+ backgroundColor: "rgba(255, 255, 255, 0.1)",
60
+ border: "1px solid rgba(255, 255, 255, 0.2)",
61
+ color: "textPrimary",
62
+ "& > li:not(:last-child)": {
63
+ borderBottom: "1px solid rgba(255, 255, 255, 0.2)",
64
+ },
65
+ },
66
+ matte: {
67
+ // `secondary` was undefined vocabulary — never painted (NEH-301).
68
+ bg: "boxBgSecondary",
69
+ color: "textSecondary",
70
+ borderColor: "borderBgPrimary",
71
+ "& > li:not(:last-child)": {
72
+ borderBottom: "1px solid",
73
+ borderColor: "borderBgPrimary",
74
+ },
75
+ },
76
+ none: {
77
+ border: "none",
78
+ backgroundColor: "inherit",
79
+ "& > li:not(:last-child)": {
80
+ borderBottom: "1px solid",
81
+ borderColor: "borderBgPrimary",
82
+ },
83
+ },
84
+ unstyled: {
85
+ border: "none",
86
+ p: "0",
87
+ m: "0",
88
+ backgroundColor: "inherit",
89
+ "& > li:not(:last-child)": {
90
+ borderBottom: "none",
91
+ },
92
+ },
93
+ },
94
+ },
95
+ });
@@ -0,0 +1,161 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const buttonIconRecipe = defineRecipe({
4
+ className: "iconButton",
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
+ borderRadius: "full",
12
+ padding: "calc(.1rem + var(--panda-density-padding, 8px))",
13
+ /**
14
+ * The tap-target floor (NEH-220, NEH-251). See `button.ts` for why this is
15
+ * a stated constant rather than something padding happens to produce.
16
+ *
17
+ * It applies to the BASE, so the `size` variants below shrink the padding
18
+ * and the glyph but not the hit area. That is deliberate and is the whole
19
+ * point: `size="1x"` exists to make an icon look small in a dense toolbar,
20
+ * not to make it hard to hit. A 20px control is a WCAG 2.5.5 failure
21
+ * whatever it is called, and this audience has elevated rates of motor
22
+ * impairment.
23
+ */
24
+ minHeight: "48px",
25
+ minWidth: "48px",
26
+ _hover: {
27
+ cursor: "pointer",
28
+ },
29
+ },
30
+ variants: {
31
+ size: {
32
+ "1x": {
33
+ padding: "2px",
34
+ fontSize: "0.75rem",
35
+ },
36
+ sm: {
37
+ padding: "4px",
38
+ fontSize: "0.875rem",
39
+ },
40
+ /**
41
+ * `md` states its font size rather than inheriting (NEH-251).
42
+ *
43
+ * It used to be `{}`. That does not mean "the base size" — the base sets
44
+ * no `font-size`, so a `<button>` fell through to the USER-AGENT
45
+ * stylesheet, which in Chrome is `13.3333px`. Three consequences, none
46
+ * of them visible without measuring:
47
+ *
48
+ * - `md` rendered SMALLER than `sm` (13.33px vs 14px), so the size
49
+ * scale ran 12, 14, 13.33, 20 — non-monotonic in the middle
50
+ * - the default icon button was the one control in the system not
51
+ * using the type scale at all
52
+ * - it was a px value, so it ignored the browser's own font setting
53
+ *
54
+ * Found by the component tier the moment it started asserting glyph size
55
+ * instead of box size; the old assertion only required two distinct box
56
+ * heights, which a broken middle satisfies.
57
+ */
58
+ md: {
59
+ fontSize: "1rem",
60
+ },
61
+ lg: {
62
+ padding: "12px",
63
+ fontSize: "1.25rem",
64
+ },
65
+ },
66
+ variant: {
67
+ solid: {
68
+ bg: "buttonBgAccent",
69
+ color: "textPrimary",
70
+ _hover: {
71
+ bg: "buttonBgSecondary",
72
+ color: "textPrimary",
73
+ },
74
+ },
75
+ outline: {
76
+ bg: "buttonBgAccent",
77
+ color: "textPrimary",
78
+ border: "1px solid",
79
+ borderColor: "borderBgSecondary",
80
+ borderRadius: 0,
81
+ _hover: {
82
+ border: "2px solid",
83
+ bg: "buttonBgAccentHover",
84
+ },
85
+ },
86
+ aurora: {
87
+ backgroundImage: "linear-gradient(to right, #ff7e5f, #feb47b)",
88
+ color: "buttonTextPrimary",
89
+ borderColor: "transparent",
90
+ _hover: {
91
+ opacity: 0.9,
92
+ },
93
+ },
94
+ glass: {
95
+ position: "relative",
96
+ overflow: "hidden",
97
+ border: "2px solid",
98
+ borderColor: "black",
99
+ borderRadius: "xl",
100
+ bg: "buttonBgAccent",
101
+ color: "textPrimary",
102
+ boxShadow: "0 8px 32px rgba(0,0,0,0.2)",
103
+ backdropFilter: "blur(12px)",
104
+ WebkitBackdropFilter: "blur(12px)",
105
+ fontWeight: "bold",
106
+ lineHeight: "shorter",
107
+ transition: "all 0.3s ease",
108
+ _hover: {
109
+ bg: "buttonBgSecondary",
110
+ borderColor: "rgba(255,255,255,0.4)",
111
+ boxShadow: "0 8px 32px rgba(0,0,0,0.3), inset 0 0 20px rgba(255,255,255,0.1)",
112
+ transform: "translateY(-1px)",
113
+ textDecoration: "none",
114
+ },
115
+ _active: {
116
+ transform: "translateY(0)",
117
+ bg: "rgba(255,255,255,0.15)",
118
+ },
119
+ _before: {
120
+ content: '""',
121
+ position: "absolute",
122
+ top: 0,
123
+ left: 0,
124
+ right: 0,
125
+ bottom: "50%",
126
+ borderRadius: "inherit",
127
+ bg: "linear-gradient(to bottom, rgba(255,255,255,0.15), transparent)",
128
+ zIndex: 0,
129
+ pointerEvents: "none",
130
+ },
131
+ },
132
+ matte: {
133
+ bgGradient: "linear(to-b, gray.800, gray.900)",
134
+ borderColor: "gray.700",
135
+ borderWidth: "1px",
136
+ boxShadow: "md",
137
+ bg: "buttonBgAccent",
138
+ color: "textPrimary",
139
+ borderRadius: "lg",
140
+ fontWeight: "bold",
141
+ },
142
+ ghost: {
143
+ bg: "buttonBgAccent/50",
144
+ color: "textPrimary",
145
+ _hover: {
146
+ bg: "buttonBgAccent",
147
+ color: "textPrimary",
148
+ border: "1px solid",
149
+ borderColor: "gray.700",
150
+ },
151
+ },
152
+ none: {
153
+ color: "textMain",
154
+ bg: "gray.300",
155
+ _hover: {
156
+ bg: "gray.100",
157
+ },
158
+ },
159
+ },
160
+ },
161
+ });
@@ -0,0 +1,34 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+
3
+ export const iconRecipe = defineRecipe({
4
+ className: "icon",
5
+ base: {
6
+ display: "inline-block",
7
+ verticalAlign: "middle",
8
+ lineHeight: 1,
9
+ fontSize: "var(--font-sizes-2xl, 1.5rem)",
10
+ "& .fa-secondary": {
11
+ color: "iconBgPrimary",
12
+ },
13
+ "& .fa-primary": {
14
+ color: "iconBgSecondary",
15
+ },
16
+ _hover: {
17
+ fontSize: "var(--font-sizes-2xl, 1.5rem)",
18
+ "& .fa-secondary": {
19
+ color: "iconBgSecondary",
20
+ },
21
+ "& .fa-primary": {
22
+ color: "iconBgPrimary",
23
+ },
24
+ },
25
+ },
26
+ variants: {
27
+ size: {
28
+ sm: { fontSize: "1em" },
29
+ md: { fontSize: "1.5em" },
30
+ lg: { fontSize: "2em" },
31
+ xl: { fontSize: "3em" },
32
+ },
33
+ },
34
+ });
@@ -0,0 +1,184 @@
1
+ import { defineSlotRecipe } from "@pandacss/dev";
2
+
3
+ export const inputBoolRecipe = defineSlotRecipe({
4
+ className: "input-bool",
5
+ slots: ["root", "control", "label"],
6
+ base: {
7
+ root: {
8
+ display: "flex",
9
+ alignItems: "center",
10
+ gap: "2",
11
+ },
12
+ control: {
13
+ display: "inline-flex",
14
+ alignItems: "center",
15
+ justifyContent: "center",
16
+ padding: "var(--panda-density-padding, 8px)",
17
+ margin: "var(--panda-density-margin, 8px)",
18
+ minHeight: "48px",
19
+ width: "48px",
20
+ /**
21
+ * This slot is a native `<input type="checkbox">` at `appearance: auto`,
22
+ * which changes what styling it is even possible to express (NEH-234).
23
+ *
24
+ * Verified in the component-test harness rather than assumed: a raw
25
+ * checkbox given a red 2px border and a slate background paints as the
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.
30
+ *
31
+ * The three it DOES honour, and therefore the only levers here:
32
+ * `accent-color` (the checked fill and tick), `box-shadow` (painted
33
+ * outside the widget) and `outline` (the focus ring).
34
+ *
35
+ * The `border`/`background` declarations are kept and pointed at real
36
+ * tokens anyway: they cost nothing, they say what the control means, and
37
+ * they are what would render if a consumer ever sets `appearance: none`.
38
+ */
39
+ border: "1px solid",
40
+ borderColor: "borderBgPrimary",
41
+ borderRadius: "md",
42
+ backgroundColor: "boxBgMain",
43
+ // Carries the host's theme into the tick. Without it a checked box is
44
+ // Chromium's own blue in every theme this package can wear.
45
+ accentColor: "buttonBgPrimary",
46
+ cursor: "pointer",
47
+ "&:focus": {
48
+ // Was `2px solid var(--colors-blue-500, #3182ce)` — Panda's blue, fixed
49
+ // in every theme including dark and high-contrast, which is exactly
50
+ // where a keyboard user cannot afford to lose the focus ring.
51
+ outline: "2px solid",
52
+ outlineColor: "textPop",
53
+ outlineOffset: "2px",
54
+ },
55
+ boxShadow: "none",
56
+ _hover: {
57
+ cursor: "pointer",
58
+ },
59
+ // `primary` was undefined vocabulary, so a ticked checkbox got no fill
60
+ // of its own and fell back to the UA's (NEH-301).
61
+ _checked: {
62
+ bg: "buttonBgPrimary",
63
+ borderColor: "borderBgPrimary",
64
+ },
65
+ },
66
+ label: {},
67
+ },
68
+ variants: {
69
+ variant: {
70
+ /**
71
+ * solid vs outline (NEH-234).
72
+ *
73
+ * These were declared identically — same `buttonBgAccent`, same
74
+ * `textPrimary` — so two of the five appearances a user can pick app-wide
75
+ * rendered the same checkbox. Worse, neither declaration painted at all
76
+ * (see the note in `base`), so the variant was doubly a lie.
77
+ *
78
+ * `buttonRecipe` expresses outline as a 2px edge with squared corners.
79
+ * 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.
83
+ */
84
+ solid: {
85
+ control: {
86
+ bg: "buttonBgAccent",
87
+ color: "textPrimary",
88
+ accentColor: "buttonBgPrimary",
89
+ boxShadow: "none",
90
+ },
91
+ },
92
+ outline: {
93
+ control: {
94
+ bg: "buttonBgAccent",
95
+ color: "textPrimary",
96
+ /**
97
+ * The SAME checked fill as `solid`, deliberately.
98
+ *
99
+ * Giving outline a recessive `accentColor` did make the two more
100
+ * different — and made a ticked outline checkbox a dark box on a dark
101
+ * surface, which is the checked state, the one thing the control
102
+ * 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.
105
+ */
106
+ accentColor: "buttonBgPrimary",
107
+ boxShadow: "0 0 0 2px {colors.borderBgPrimary}",
108
+ borderRadius: "0",
109
+ },
110
+ },
111
+ aurora: {
112
+ control: {
113
+ backgroundImage: "linear-gradient(to right, #ff7e5f, #feb47b)",
114
+ color: "buttonTextPrimary",
115
+ },
116
+ },
117
+ glass: {
118
+ control: {
119
+ position: "relative",
120
+ overflow: "hidden",
121
+ bg: "buttonBgPrimary/20",
122
+ color: "textPrimary/10",
123
+ boxShadow: "xl",
124
+ backdropFilter: "blur(8px)",
125
+ fontWeight: "bold",
126
+ lineHeight: "shorter",
127
+ _before: {
128
+ content: '""',
129
+ position: "absolute",
130
+ top: 0,
131
+ left: 0,
132
+ right: 0,
133
+ bottom: 0,
134
+ bgGradient:
135
+ "linear(to-br, rgba(255,255,255,0.1), rgba(255,255,255,0.05))",
136
+ zIndex: -1,
137
+ },
138
+ },
139
+ },
140
+ matte: {
141
+ control: {
142
+ bgGradient: "linear(to-b, gray.800, gray.900)",
143
+ // `whiteAlpha.900` never painted (NEH-301). `white` rather than a
144
+ // token for the same reason as boxRecipe's matte: the surface above
145
+ // is a FIXED dark gradient, so themed text on it risks dark-on-dark.
146
+ color: "white",
147
+ fontWeight: "bold",
148
+ },
149
+ },
150
+ ghost: {
151
+ control: {
152
+ color: "textSecondary",
153
+ bg: "buttonBgSecondary",
154
+ },
155
+ },
156
+ none: {
157
+ control: {
158
+ color: "buttonTextPrimary",
159
+ bg: "gray.300",
160
+ },
161
+ },
162
+ button: {
163
+ control: {
164
+ bg: "gray.200",
165
+ color: "gray.800",
166
+ // `primary` / `primary.600` were undefined vocabulary, so the
167
+ // checked and checked-hover fills never painted (NEH-301). The
168
+ // hover step is the matching `*Hover` token rather than an invented
169
+ // darker shade — this package holds no colour scales to step along.
170
+ _checked: {
171
+ bg: "buttonBgPrimary",
172
+ color: "buttonTextPrimary",
173
+ _hover: {
174
+ bg: "buttonBgPrimaryHover",
175
+ },
176
+ },
177
+ _hover: {
178
+ bg: "gray.300",
179
+ },
180
+ },
181
+ },
182
+ },
183
+ },
184
+ });
@@ -0,0 +1,93 @@
1
+ import { defineRecipe } from "@pandacss/dev";
2
+ import { inputSurfaceBase, inputSurfaceVariants } from "./input-surface";
3
+
4
+ // Trigger / closed-state appearance.
5
+ //
6
+ // The surface is shared with `inputTextRecipe` — see `input-surface.ts` for
7
+ // why the two must not be maintained separately (NEH-84). Anything specific to
8
+ // a dropdown trigger belongs here; anything that should also be true of a text
9
+ // input belongs in the shared surface.
10
+ export const inputDropdownRecipe = defineRecipe({
11
+ className: "input-dropdown",
12
+ base: inputSurfaceBase,
13
+ variants: {
14
+ variant: inputSurfaceVariants,
15
+ },
16
+ });
17
+
18
+ // Expanded-state appearance: content container, groups, and group labels
19
+ export const inputDropdownContentRecipe = defineRecipe({
20
+ className: "input-dropdown-content",
21
+ base: {},
22
+ variants: {
23
+ part: {
24
+ content: {
25
+ borderRadius: "md",
26
+ boxShadow: "lg",
27
+ maxHeight: "widgetBaseHeight",
28
+ overflowY: "auto",
29
+ },
30
+ item: {
31
+ bg: "boxBgPrimary",
32
+ borderBottom: "1px solid",
33
+ borderColor: "borderBgSecondary",
34
+ padding: "var(--panda-density-padding, 8px)",
35
+ borderRadius: "sm",
36
+ cursor: "pointer",
37
+ "&:hover": {
38
+ backgroundColor: "boxBgSecondary",
39
+ },
40
+ "&[data-highlighted]": {
41
+ backgroundColor: "boxBgSecondary",
42
+ },
43
+ },
44
+ itemGroup: {
45
+ zIndex: 30020,
46
+ },
47
+ itemGroupLabel: {
48
+ zIndex: 30020,
49
+ fontWeight: "bold",
50
+ // A token, not gray.500: the label sits on boxBgPrimary, whose colour
51
+ // the theme decides, so a fixed mid-grey is an unverified contrast bet
52
+ // in every palette but the one it was picked against.
53
+ color: "textSecondary",
54
+ fontSize: "sm",
55
+ padding: "calc(var(--panda-density-padding, 8px) * 0.5)",
56
+ },
57
+ },
58
+ },
59
+ });
60
+
61
+ // Individual dropdown item styling
62
+ export const inputDropdownItemRecipe = defineRecipe({
63
+ className: "input-dropdown-item",
64
+ base: {
65
+ display: "flex",
66
+ alignItems: "center",
67
+ padding: "10px 20px",
68
+ cursor: "pointer",
69
+ fontSize: "var(--font-sizes-lg, 0.95rem)",
70
+ color: "textPrimary",
71
+ bg: "boxBgPrimary",
72
+ transition: "background 0.15s ease, color 0.15s ease",
73
+ "&:hover": {
74
+ bg: "boxBgSecondary",
75
+ },
76
+ "&[data-highlighted]": {
77
+ bg: "boxBgSecondary",
78
+ },
79
+ "&:not(:last-child)": {
80
+ borderBottom: "1px solid",
81
+ borderColor: "borderBgSecondary/40",
82
+ },
83
+ "&:active": {
84
+ bg: "boxBgSecondary",
85
+ opacity: 0.85,
86
+ },
87
+ },
88
+ variants: {
89
+ part: {
90
+ item: {},
91
+ },
92
+ },
93
+ });