@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.
- package/LICENSE +201 -0
- package/NOTICE +18 -0
- package/README.md +699 -0
- package/package.json +95 -0
- package/src/components/DictationControls.tsx +141 -0
- package/src/components/DictationPrompt.tsx +78 -0
- package/src/components/StyledBox.tsx +174 -0
- package/src/components/StyledButton.tsx +144 -0
- package/src/components/StyledCollapsible.tsx +127 -0
- package/src/components/StyledDefinitionList.tsx +134 -0
- package/src/components/StyledFieldset.tsx +157 -0
- package/src/components/StyledFlex.tsx +13 -0
- package/src/components/StyledFooter.tsx +399 -0
- package/src/components/StyledFormLabel.tsx +141 -0
- package/src/components/StyledGrid.tsx +109 -0
- package/src/components/StyledGridItem.tsx +19 -0
- package/src/components/StyledHStack.tsx +145 -0
- package/src/components/StyledHeading.tsx +79 -0
- package/src/components/StyledHrRule.tsx +33 -0
- package/src/components/StyledIcon.tsx +172 -0
- package/src/components/StyledIconButton.tsx +135 -0
- package/src/components/StyledInputBool.tsx +81 -0
- package/src/components/StyledInputRadio.tsx +141 -0
- package/src/components/StyledInputSelect.tsx +115 -0
- package/src/components/StyledInputSlider.tsx +83 -0
- package/src/components/StyledInputText.tsx +146 -0
- package/src/components/StyledInputTextArea.tsx +119 -0
- package/src/components/StyledInputToggle.tsx +224 -0
- package/src/components/StyledList.tsx +188 -0
- package/src/components/StyledScrollbar.tsx +53 -0
- package/src/components/StyledSearch.tsx +78 -0
- package/src/components/StyledSeparator.tsx +38 -0
- package/src/components/StyledSidebar.tsx +555 -0
- package/src/components/StyledSimpleGrid.tsx +99 -0
- package/src/components/StyledSparkLine.tsx +119 -0
- package/src/components/StyledSpinner.tsx +91 -0
- package/src/components/StyledStack.tsx +62 -0
- package/src/components/StyledText.tsx +99 -0
- package/src/components/StyledTooltip.tsx +398 -0
- package/src/components/StyledVStack.tsx +143 -0
- package/src/components/TitleLogo.tsx +223 -0
- package/src/components/create-icon.tsx +66 -0
- package/src/components/create-intent-button.tsx +134 -0
- package/src/components/dictation.ts +71 -0
- package/src/components/intent-buttons.ts +154 -0
- package/src/config/can-hover.ts +75 -0
- package/src/config/density.ts +138 -0
- package/src/config/font-size.ts +113 -0
- package/src/config/intent-icons.tsx +116 -0
- package/src/config/logger.ts +60 -0
- package/src/config/style-config.tsx +263 -0
- package/src/config/types.ts +137 -0
- package/src/index.ts +259 -0
- package/src/preset/index.ts +243 -0
- package/src/preset/recipes/arrows.ts +29 -0
- package/src/preset/recipes/box.ts +122 -0
- package/src/preset/recipes/button.ts +161 -0
- package/src/preset/recipes/dl-list.ts +109 -0
- package/src/preset/recipes/drawer.ts +125 -0
- package/src/preset/recipes/form.ts +95 -0
- package/src/preset/recipes/icon-button.ts +161 -0
- package/src/preset/recipes/icon.ts +34 -0
- package/src/preset/recipes/input-bool.ts +184 -0
- package/src/preset/recipes/input-dropdown.ts +93 -0
- package/src/preset/recipes/input-radio.ts +158 -0
- package/src/preset/recipes/input-surface.ts +152 -0
- package/src/preset/recipes/input-text.ts +17 -0
- package/src/preset/recipes/list.ts +196 -0
- package/src/preset/recipes/menu.ts +28 -0
- package/src/preset/recipes/separator.ts +89 -0
- package/src/preset/recipes/stack.ts +89 -0
- package/src/preset/recipes/striped.ts +34 -0
- package/src/preset/recipes/text.ts +41 -0
- package/src/preset/recipes/tooltip.ts +77 -0
- 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
|
+
});
|