@kalink-ui/seedly 0.9.0 → 0.10.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 (94) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +12 -6
  3. package/src/components/box/box.css.ts +2 -2
  4. package/src/components/button/button.css.ts +45 -48
  5. package/src/components/button/button.tsx +11 -8
  6. package/src/components/button/index.ts +1 -1
  7. package/src/components/button-icon/button-icon.css.ts +90 -0
  8. package/src/components/button-icon/button-icon.tsx +23 -0
  9. package/src/components/button-icon/index.ts +1 -0
  10. package/src/components/card/card.tsx +7 -4
  11. package/src/components/card/index.ts +1 -1
  12. package/src/components/center/center.tsx +2 -2
  13. package/src/components/center/index.ts +1 -1
  14. package/src/components/cluster/cluster.css.ts +17 -0
  15. package/src/components/divider/divider.css.ts +11 -0
  16. package/src/components/divider/divider.tsx +11 -0
  17. package/src/components/divider/index.ts +1 -0
  18. package/src/components/form-field/form-field-context.ts +18 -0
  19. package/src/components/form-field/form-field-control.tsx +34 -0
  20. package/src/components/form-field/form-field-description.tsx +16 -0
  21. package/src/components/form-field/form-field-error.tsx +22 -0
  22. package/src/components/form-field/form-field-item-context.ts +6 -0
  23. package/src/components/form-field/form-field-item.tsx +28 -0
  24. package/src/components/form-field/form-field-label.tsx +27 -0
  25. package/src/components/form-field/form-field-message.tsx +33 -0
  26. package/src/components/form-field/form-field.css.ts +97 -0
  27. package/src/components/form-field/form-field.tsx +56 -0
  28. package/src/components/form-field/index.ts +9 -0
  29. package/src/components/frame/frame.css.ts +8 -8
  30. package/src/components/frame/frame.tsx +2 -6
  31. package/src/components/frame/index.ts +1 -1
  32. package/src/components/heading/heading.tsx +43 -8
  33. package/src/components/index.ts +27 -15
  34. package/src/components/input/index.ts +2 -0
  35. package/src/components/input/input-wrapper.tsx +58 -0
  36. package/src/components/input/input.css.ts +250 -0
  37. package/src/components/input/input.tsx +56 -0
  38. package/src/components/label/index.ts +1 -0
  39. package/src/components/label/label.css.ts +37 -0
  40. package/src/components/label/label.tsx +23 -0
  41. package/src/components/loader/index.ts +1 -0
  42. package/src/components/loader/loader.css.ts +109 -0
  43. package/src/components/loader/moon-loader.tsx +43 -0
  44. package/src/components/loader-overlay/index.ts +1 -0
  45. package/src/components/loader-overlay/loader-overlay.css.ts +35 -0
  46. package/src/components/loader-overlay/loader-overlay.tsx +28 -0
  47. package/src/components/menu/index.ts +2 -0
  48. package/src/components/menu/menu-item.css.ts +79 -0
  49. package/src/components/menu/menu-separator.css.ts +53 -0
  50. package/src/components/popover/index.ts +3 -0
  51. package/src/components/popover/popover-content.css.ts +107 -0
  52. package/src/components/popover/popover-content.tsx +78 -0
  53. package/src/components/popover/popover.tsx +6 -0
  54. package/src/components/scroll-area/index.ts +1 -0
  55. package/src/components/scroll-area/scroll-area.css.ts +72 -0
  56. package/src/components/scroll-area/scroll-area.tsx +39 -0
  57. package/src/components/scroll-area/scroll-bar.tsx +37 -0
  58. package/src/components/seed/seed.tsx +4 -4
  59. package/src/components/select/index.ts +5 -0
  60. package/src/components/select/select-content.css.ts +22 -0
  61. package/src/components/select/select-content.tsx +51 -0
  62. package/src/components/select/select-item.css.ts +24 -0
  63. package/src/components/select/select-item.tsx +24 -0
  64. package/src/components/select/select-root.tsx +14 -0
  65. package/src/components/select/select-trigger.css.ts +75 -0
  66. package/src/components/select/select-trigger.tsx +47 -0
  67. package/src/components/select/select.tsx +85 -0
  68. package/src/components/sheet/index.ts +5 -0
  69. package/src/components/sheet/sheet-content.css.ts +143 -0
  70. package/src/components/sheet/sheet-content.tsx +43 -0
  71. package/src/components/sheet/sheet-description.tsx +21 -0
  72. package/src/components/sheet/sheet-footer.tsx +15 -0
  73. package/src/components/sheet/sheet-header.css.ts +35 -0
  74. package/src/components/sheet/sheet-header.tsx +32 -0
  75. package/src/components/sheet/sheet-overlay.css.ts +43 -0
  76. package/src/components/sheet/sheet-overlay.tsx +14 -0
  77. package/src/components/sheet/sheet-title.tsx +31 -0
  78. package/src/components/sheet/sheet.tsx +8 -0
  79. package/src/components/stack/index.ts +1 -1
  80. package/src/components/stack/stack.tsx +2 -2
  81. package/src/components/text/index.ts +6 -0
  82. package/src/components/text/text.css.ts +31 -4
  83. package/src/components/text-field/index.ts +1 -0
  84. package/src/components/text-field/text-field.css.ts +3 -0
  85. package/src/components/text-field/text-field.tsx +64 -0
  86. package/src/components/textarea/index.ts +1 -0
  87. package/src/components/textarea/textarea-input.tsx +20 -0
  88. package/src/components/textarea/textarea.css.ts +10 -0
  89. package/src/components/textarea/textarea.tsx +69 -0
  90. package/src/styles/define-responsive-properties.ts +242 -0
  91. package/src/styles/extract-sprinkles-props.ts +29 -35
  92. package/src/styles/index.ts +9 -0
  93. package/src/styles/reset.css.ts +1 -0
  94. package/src/styles/visually-hidden.css.ts +21 -0
@@ -0,0 +1,250 @@
1
+ import { style, globalStyle, createGlobalTheme } from '@vanilla-extract/css';
2
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
+
4
+ import { sys, transition, typography } from '../../styles';
5
+ import { components } from '../../styles/layers.css';
6
+
7
+ export const inputVars = createGlobalTheme(':root', {
8
+ '@layer': components,
9
+
10
+ color: {
11
+ foreground: 'inherit',
12
+ background: sys.color.background,
13
+ outline: sys.color.foreground,
14
+ error: 'red',
15
+ },
16
+
17
+ spacing: {
18
+ block: sys.spacing[2],
19
+ inline: sys.spacing[4],
20
+ },
21
+
22
+ shape: {
23
+ corner: sys.shape.corner.none,
24
+ },
25
+ });
26
+
27
+ export const inputAppearance = recipe({
28
+ base: [
29
+ {
30
+ '@layer': {
31
+ [components]: {
32
+ boxSizing: 'border-box',
33
+ position: 'relative',
34
+
35
+ color: inputVars.color.foreground,
36
+
37
+ backgroundColor: 'transparent',
38
+ borderRadius: inputVars.shape.corner,
39
+
40
+ cursor: 'inherit',
41
+
42
+ transition: transition(
43
+ ['background-color', 'border-color', 'box-shadow'],
44
+ {
45
+ duration: 'short.2',
46
+ },
47
+ ),
48
+
49
+ selectors: {
50
+ '&:disabled, &:has(:disabled)': {
51
+ backgroundColor: `color-mix(in srgb, ${inputVars.color.foreground} calc(${sys.state.muted.dark} * 100%), transparent)`,
52
+
53
+ vars: {
54
+ [inputVars.color.foreground]:
55
+ `color(from ${sys.color.foreground} srgb r g b / 0.38)`,
56
+ },
57
+ },
58
+
59
+ '&:focus, &:focus-within, &:focus-visible': {
60
+ boxShadow: `0 0 0 1px ${inputVars.color.outline} inset`,
61
+ outline: 'none',
62
+ },
63
+
64
+ '&[aria-invalid], &:has([aria-invalid])': {
65
+ vars: {
66
+ [inputVars.color.foreground]: 'red',
67
+ },
68
+ },
69
+ },
70
+
71
+ vars: {
72
+ [inputVars.color.foreground]: sys.color.foreground,
73
+ [inputVars.color.background]: sys.color.background,
74
+ [inputVars.color.outline]: inputVars.color.foreground,
75
+ [inputVars.spacing.block]: sys.spacing[2],
76
+ [inputVars.spacing.inline]: sys.spacing[4],
77
+ },
78
+ },
79
+ },
80
+ },
81
+ ],
82
+
83
+ variants: {
84
+ variant: {
85
+ outlined: {
86
+ '@layer': {
87
+ [components]: {
88
+ paddingInline: inputVars.spacing.inline,
89
+ paddingBlock: inputVars.spacing.block,
90
+
91
+ borderColor: inputVars.color.outline,
92
+ borderStyle: 'solid',
93
+ borderWidth: 1,
94
+ },
95
+ },
96
+ },
97
+
98
+ plain: {
99
+ '@layer': {
100
+ [components]: {
101
+ paddingInline: inputVars.spacing.inline,
102
+ paddingBlock: inputVars.spacing.block,
103
+
104
+ backgroundColor: inputVars.color.background,
105
+ borderRadius: inputVars.shape.corner,
106
+
107
+ vars: {
108
+ [inputVars.color.background]:
109
+ `color-mix(in srgb, ${inputVars.color.foreground} calc(${sys.state.muted.dark} * 100%), transparent)`,
110
+ },
111
+ },
112
+ },
113
+ },
114
+
115
+ bare: {},
116
+ },
117
+
118
+ size: {
119
+ sm: [
120
+ typography.body.small,
121
+ {
122
+ '@layer': {
123
+ [components]: {
124
+ /**
125
+ * Force the font size to 16px to avoid zooming on mobile
126
+ */
127
+ fontSize: `max(16px, ${sys.typography.body.small.size})`,
128
+
129
+ vars: {
130
+ [inputVars.spacing.block]: sys.spacing[1],
131
+ [inputVars.spacing.inline]: sys.spacing[1],
132
+ },
133
+ },
134
+ },
135
+ },
136
+ ],
137
+
138
+ md: [
139
+ typography.body.medium,
140
+ {
141
+ '@layer': {
142
+ [components]: {
143
+ /**
144
+ * Force the font size to 16px to avoid zooming on mobile
145
+ */
146
+ fontSize: `max(16px, ${sys.typography.body.medium.size})`,
147
+
148
+ vars: {
149
+ [inputVars.spacing.block]: sys.spacing[2],
150
+ [inputVars.spacing.inline]: sys.spacing[2],
151
+ },
152
+ },
153
+ },
154
+ },
155
+ ],
156
+
157
+ lg: [
158
+ typography.body.large,
159
+ {
160
+ '@layer': {
161
+ [components]: {
162
+ /**
163
+ * Force the font size to 16px to avoid zooming on mobile
164
+ */
165
+ fontSize: `max(16px, ${sys.typography.body.large.size})`,
166
+
167
+ vars: {
168
+ [inputVars.spacing.block]: sys.spacing[3],
169
+ [inputVars.spacing.inline]: sys.spacing[3],
170
+ },
171
+ },
172
+ },
173
+ },
174
+ ],
175
+ },
176
+ },
177
+
178
+ defaultVariants: {
179
+ variant: 'outlined',
180
+ size: 'md',
181
+ },
182
+ });
183
+
184
+ export const inputWrapper = style({
185
+ '@layer': {
186
+ [components]: {
187
+ display: 'flex',
188
+ alignItems: 'center',
189
+ justifyContent: 'space-between',
190
+ gap: inputVars.spacing.inline,
191
+
192
+ width: '100%',
193
+
194
+ position: 'relative',
195
+
196
+ cursor: 'text',
197
+
198
+ selectors: {
199
+ '&:disabled, &:has(:disabled)': {
200
+ cursor: 'inherit',
201
+ },
202
+ },
203
+ },
204
+ },
205
+ });
206
+
207
+ export const input = style({
208
+ '@layer': {
209
+ [components]: {
210
+ appearance: 'none',
211
+
212
+ flexGrow: 1,
213
+ flexBasis: 1,
214
+
215
+ paddingTop: 0,
216
+ paddingBottom: 0,
217
+
218
+ color: 'inherit',
219
+
220
+ border: 'none',
221
+ backgroundColor: 'transparent',
222
+ cursor: 'inherit',
223
+ },
224
+ },
225
+ });
226
+
227
+ export const inputAddornment = style({
228
+ '@layer': {
229
+ [components]: {
230
+ flexShrink: 0,
231
+
232
+ color: 'inherit',
233
+ },
234
+ },
235
+ });
236
+
237
+ globalStyle(
238
+ `${inputAppearance.classNames.base} input:is(:focus, :focus-visible)`,
239
+ {
240
+ '@layer': {
241
+ [components]: {
242
+ outline: 'none',
243
+ },
244
+ },
245
+ },
246
+ );
247
+
248
+ export type InputAppearanceVariants = NonNullable<
249
+ RecipeVariants<typeof inputAppearance>
250
+ >;
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { mergeRefs } from '@kalink-ui/dibbly';
4
+ import { clsx } from 'clsx';
5
+ import { ComponentPropsWithRef, ReactNode, RefObject, useRef } from 'react';
6
+
7
+ import { useFormFieldContext } from '../form-field/form-field-context';
8
+
9
+ import { InputWrapper } from './input-wrapper';
10
+ import { InputAppearanceVariants, input, inputAddornment } from './input.css';
11
+
12
+ export type InputProps = Omit<ComponentPropsWithRef<'input'>, 'size'> & {
13
+ startAdornment?: ReactNode;
14
+ endAdornment?: ReactNode;
15
+ inputRef?: RefObject<HTMLInputElement>;
16
+ } & InputAppearanceVariants;
17
+
18
+ export function Input({
19
+ className,
20
+ type = 'text',
21
+ startAdornment,
22
+ endAdornment,
23
+ disabled,
24
+ inputRef,
25
+ children,
26
+ variant,
27
+ size,
28
+ ref,
29
+ ...props
30
+ }: InputProps) {
31
+ const innerRef = useRef<HTMLInputElement>(null);
32
+ const { errors } = useFormFieldContext();
33
+
34
+ return (
35
+ <InputWrapper
36
+ ref={ref}
37
+ inputRef={innerRef}
38
+ disabled={disabled}
39
+ variant={variant}
40
+ size={size}
41
+ >
42
+ {startAdornment && (
43
+ <div className={inputAddornment}>{startAdornment}</div>
44
+ )}
45
+ <input
46
+ ref={mergeRefs([inputRef, innerRef])}
47
+ type={type}
48
+ className={clsx(input, className)}
49
+ disabled={disabled}
50
+ aria-invalid={errors ? 'true' : undefined}
51
+ {...props}
52
+ />
53
+ {endAdornment && <div className={inputAddornment}>{endAdornment}</div>}
54
+ </InputWrapper>
55
+ );
56
+ }
@@ -0,0 +1 @@
1
+ export { Label, type LabelProps } from './label';
@@ -0,0 +1,37 @@
1
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
2
+
3
+ import { typography } from '../../styles';
4
+ import { components } from '../../styles/layers.css';
5
+
6
+ export const label = recipe({
7
+ base: {
8
+ '@layer': {
9
+ [components]: {
10
+ cursor: 'default',
11
+ },
12
+ },
13
+ },
14
+
15
+ variants: {
16
+ disabled: {
17
+ true: {
18
+ '@layer': {
19
+ [components]: {
20
+ cursor: 'not-allowed',
21
+ },
22
+ },
23
+ },
24
+ },
25
+ error: {
26
+ true: {},
27
+ },
28
+
29
+ size: {
30
+ sm: [typography.label.small],
31
+ md: [typography.label.medium],
32
+ lg: [typography.label.large],
33
+ },
34
+ },
35
+ });
36
+
37
+ export type LabelVariants = NonNullable<RecipeVariants<typeof label>>;
@@ -0,0 +1,23 @@
1
+ import { clsx } from 'clsx';
2
+ import { ComponentPropsWithRef } from 'react';
3
+
4
+ import { label, LabelVariants } from './label.css';
5
+
6
+ export type LabelProps = ComponentPropsWithRef<'label'> & {
7
+ required?: boolean;
8
+ } & LabelVariants;
9
+
10
+ export function Label({
11
+ className,
12
+ disabled,
13
+ error,
14
+ size = 'md',
15
+ ...props
16
+ }: LabelProps) {
17
+ return (
18
+ <label
19
+ className={clsx(label({ disabled, error, size }), className)}
20
+ {...props}
21
+ />
22
+ );
23
+ }
@@ -0,0 +1 @@
1
+ export { MoonLoader } from './moon-loader';
@@ -0,0 +1,109 @@
1
+ import { createVar, keyframes, style } from '@vanilla-extract/css';
2
+ import { calc } from '@vanilla-extract/css-utils';
3
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
4
+
5
+ import { sys, transition } from '../../styles';
6
+
7
+ export const loader = recipe({
8
+ variants: {
9
+ active: {
10
+ true: {
11
+ opacity: 1,
12
+ visibility: 'visible',
13
+
14
+ animationPlayState: 'running',
15
+ },
16
+ false: {
17
+ opacity: 0,
18
+ visibility: 'hidden',
19
+
20
+ animationPlayState: 'paused',
21
+ },
22
+ },
23
+ },
24
+ });
25
+
26
+ const size = createVar();
27
+ const moonSize = createVar();
28
+
29
+ const loaderAnimation = keyframes({
30
+ '100%': {
31
+ transform: 'rotate(360deg)',
32
+ },
33
+ });
34
+
35
+ export const loaderWrapper = recipe({
36
+ base: {
37
+ overflow: 'hidden',
38
+ width: size,
39
+ height: size,
40
+
41
+ animationName: loaderAnimation,
42
+ animationDuration: '1s',
43
+ animationIterationCount: 'infinite',
44
+ animationTimingFunction: 'linear',
45
+ animationFillMode: 'forwards',
46
+
47
+ transition: transition(['opacity', 'visibility']),
48
+ pointerEvents: 'none',
49
+
50
+ vars: {
51
+ [moonSize]: calc.divide(size, 7),
52
+ },
53
+ },
54
+
55
+ variants: {
56
+ size: {
57
+ sm: {
58
+ vars: {
59
+ [size]: sys.spacing[4],
60
+ },
61
+ },
62
+ md: {
63
+ vars: {
64
+ [size]: sys.spacing[5],
65
+ },
66
+ },
67
+ lg: {
68
+ vars: {
69
+ [size]: sys.spacing[6],
70
+ },
71
+ },
72
+ },
73
+ },
74
+ });
75
+
76
+ export const ellipse = style({
77
+ width: size,
78
+ height: size,
79
+
80
+ position: 'absolute',
81
+ insetBlockStart: 0,
82
+ insetInlineStart: 0,
83
+
84
+ borderRadius: '100%',
85
+ borderWidth: moonSize,
86
+ borderStyle: 'solid',
87
+ borderColor: `color-mix(in srgb, ${sys.color.foreground} 30%, transparent)`,
88
+ });
89
+
90
+ export const moon = style({
91
+ width: moonSize,
92
+ height: moonSize,
93
+
94
+ position: 'absolute',
95
+ insetBlockStart: calc.subtract(
96
+ calc.divide(size, 2),
97
+ calc.divide(moonSize, 2),
98
+ ),
99
+ insetInlineStart: 0,
100
+
101
+ backgroundColor: sys.color.foreground,
102
+
103
+ borderRadius: '100%',
104
+ });
105
+
106
+ export type LoaderVariants = NonNullable<RecipeVariants<typeof loader>>;
107
+ export type MoonLoaderVariants = NonNullable<
108
+ RecipeVariants<typeof loaderWrapper>
109
+ >;
@@ -0,0 +1,43 @@
1
+ import { clsx } from 'clsx';
2
+ import { ElementType } from 'react';
3
+
4
+ import { Box, BoxProps } from '../box';
5
+
6
+ import {
7
+ ellipse,
8
+ moon,
9
+ loaderWrapper,
10
+ loader,
11
+ LoaderVariants,
12
+ MoonLoaderVariants,
13
+ } from './loader.css';
14
+
15
+ export type LoaderProps<TUse extends ElementType> = BoxProps<TUse> & {
16
+ forceMount?: boolean;
17
+ className?: string;
18
+ } & LoaderVariants;
19
+
20
+ /**
21
+ * Heavily inspired by https://github.com/davidhu2000/react-spinners/blob/main/src/MoonLoader.tsx
22
+ */
23
+ export function MoonLoader<TUse extends ElementType>({
24
+ active,
25
+ size = 'md',
26
+ forceMount = false,
27
+ className,
28
+ ...props
29
+ }: LoaderProps<TUse> & MoonLoaderVariants) {
30
+ if (!active && !forceMount) {
31
+ return null;
32
+ }
33
+
34
+ return (
35
+ <Box
36
+ className={clsx(loaderWrapper({ size }), loader({ active }), className)}
37
+ {...props}
38
+ >
39
+ <span className={ellipse} />
40
+ <span className={moon} />
41
+ </Box>
42
+ );
43
+ }
@@ -0,0 +1 @@
1
+ export { LoaderOverlay } from './loader-overlay';
@@ -0,0 +1,35 @@
1
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
2
+
3
+ import { sys } from '../../styles';
4
+
5
+ export const loaderOverlay = recipe({
6
+ base: {
7
+ display: 'flex',
8
+ justifyContent: 'center',
9
+ alignItems: 'center',
10
+
11
+ height: '100%',
12
+ width: '100%',
13
+
14
+ zIndex: 1000,
15
+
16
+ backgroundColor: `color-mix(in srgb, ${sys.color.foreground} 10%, transparent)`,
17
+ },
18
+
19
+ variants: {
20
+ position: {
21
+ absolute: {
22
+ position: 'absolute',
23
+ top: 0,
24
+ left: 0,
25
+ },
26
+ relative: {
27
+ position: 'relative',
28
+ },
29
+ },
30
+ },
31
+ });
32
+
33
+ export type LoaderOverlayVariants = NonNullable<
34
+ RecipeVariants<typeof loaderOverlay>
35
+ >;
@@ -0,0 +1,28 @@
1
+ import { clsx } from 'clsx';
2
+
3
+ import { Center } from '../center';
4
+ import { MoonLoader } from '../loader';
5
+ import { Stack } from '../stack';
6
+ import { Text } from '../text';
7
+
8
+ import { loaderOverlay, LoaderOverlayVariants } from './loader-overlay.css';
9
+
10
+ interface LoaderOverlayProps extends LoaderOverlayVariants {
11
+ text?: string;
12
+ className?: string;
13
+ }
14
+
15
+ export function LoaderOverlay({
16
+ className,
17
+ text,
18
+ position,
19
+ }: LoaderOverlayProps) {
20
+ return (
21
+ <div className={clsx(loaderOverlay({ position }), className)}>
22
+ <Stack use={Center}>
23
+ <MoonLoader active forceMount />
24
+ {text && <Text>{text}</Text>}
25
+ </Stack>
26
+ </div>
27
+ );
28
+ }
@@ -0,0 +1,2 @@
1
+ export { menuItem, menuItemIcon } from './menu-item.css';
2
+ export { menuSeparator } from './menu-separator.css';
@@ -0,0 +1,79 @@
1
+ import { style } from '@vanilla-extract/css';
2
+ import { recipe, RecipeVariants } from '@vanilla-extract/recipes';
3
+
4
+ import { sys, typography } from '../../styles';
5
+
6
+ export const menuItem = recipe({
7
+ base: [
8
+ typography.body.medium,
9
+ {
10
+ display: 'flex',
11
+ alignItems: 'center',
12
+ gap: sys.spacing[2],
13
+
14
+ paddingInline: sys.spacing[2],
15
+ paddingBlock: sys.spacing[1],
16
+ width: '100%',
17
+
18
+ position: 'relative',
19
+
20
+ textAlign: 'start',
21
+
22
+ borderRadius: sys.shape.corner.small,
23
+
24
+ cursor: 'pointer',
25
+ userSelect: 'none',
26
+
27
+ selectors: {
28
+ '&[data-disabled="true"], &[aria-disabled="true"]': {
29
+ pointerEvents: 'none',
30
+ opacity: 0.5,
31
+ },
32
+
33
+ '&:before': {
34
+ content: '""',
35
+
36
+ width: '100%',
37
+ height: '100%',
38
+
39
+ position: 'absolute',
40
+ top: 0,
41
+ left: 0,
42
+
43
+ backgroundColor: sys.color.foreground,
44
+ opacity: 0,
45
+ borderRadius: 'inherit',
46
+
47
+ pointerEvents: 'none',
48
+ },
49
+
50
+ '&:hover::before': {
51
+ opacity: sys.state.hovered.opacity,
52
+ },
53
+
54
+ '&:is(:focus, :focus-visible, [aria-selected="true"])': {
55
+ outline: 'none',
56
+ },
57
+
58
+ '&:focus::before, &:focus-visible::before, &[aria-selected="true"]::before':
59
+ {
60
+ opacity: sys.state.focused.opacity,
61
+ },
62
+ },
63
+ },
64
+ ],
65
+
66
+ variants: {
67
+ inset: {
68
+ true: {
69
+ paddingInlineStart: sys.spacing[4],
70
+ },
71
+ },
72
+ },
73
+ });
74
+
75
+ export const menuItemIcon = style({
76
+ color: sys.color.foreground,
77
+ });
78
+
79
+ export type MenuItemVariants = NonNullable<RecipeVariants<typeof menuItem>>;