@kalink-ui/seedly 0.8.1 → 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 (109) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/package.json +26 -18
  3. package/src/components/box/box.css.ts +6 -15
  4. package/src/components/box/box.tsx +2 -2
  5. package/src/components/box/index.ts +1 -1
  6. package/src/components/button/button.css.ts +45 -48
  7. package/src/components/button/button.tsx +11 -8
  8. package/src/components/button/index.ts +1 -1
  9. package/src/components/button-icon/button-icon.css.ts +90 -0
  10. package/src/components/button-icon/button-icon.tsx +23 -0
  11. package/src/components/button-icon/index.ts +1 -0
  12. package/src/components/card/card.css.ts +42 -0
  13. package/src/components/card/card.tsx +76 -0
  14. package/src/components/card/index.ts +1 -0
  15. package/src/components/center/center.css.ts +1 -1
  16. package/src/components/center/center.tsx +2 -2
  17. package/src/components/center/index.ts +1 -1
  18. package/src/components/cluster/cluster.css.ts +18 -1
  19. package/src/components/cluster/cluster.tsx +2 -2
  20. package/src/components/cluster/index.ts +1 -1
  21. package/src/components/cover/cover.css.ts +1 -1
  22. package/src/components/divider/divider.css.ts +11 -0
  23. package/src/components/divider/divider.tsx +11 -0
  24. package/src/components/divider/index.ts +1 -0
  25. package/src/components/form-field/form-field-context.ts +18 -0
  26. package/src/components/form-field/form-field-control.tsx +34 -0
  27. package/src/components/form-field/form-field-description.tsx +16 -0
  28. package/src/components/form-field/form-field-error.tsx +22 -0
  29. package/src/components/form-field/form-field-item-context.ts +6 -0
  30. package/src/components/form-field/form-field-item.tsx +28 -0
  31. package/src/components/form-field/form-field-label.tsx +27 -0
  32. package/src/components/form-field/form-field-message.tsx +33 -0
  33. package/src/components/form-field/form-field.css.ts +97 -0
  34. package/src/components/form-field/form-field.tsx +56 -0
  35. package/src/components/form-field/index.ts +9 -0
  36. package/src/components/frame/frame.css.ts +8 -8
  37. package/src/components/frame/frame.tsx +2 -6
  38. package/src/components/frame/index.ts +1 -1
  39. package/src/components/grid/grid.css.ts +1 -1
  40. package/src/components/heading/heading.css.ts +49 -2
  41. package/src/components/heading/heading.tsx +123 -69
  42. package/src/components/heading/index.ts +2 -1
  43. package/src/components/index.ts +27 -14
  44. package/src/components/input/index.ts +2 -0
  45. package/src/components/input/input-wrapper.tsx +58 -0
  46. package/src/components/input/input.css.ts +250 -0
  47. package/src/components/input/input.tsx +56 -0
  48. package/src/components/label/index.ts +1 -0
  49. package/src/components/label/label.css.ts +37 -0
  50. package/src/components/label/label.tsx +23 -0
  51. package/src/components/loader/index.ts +1 -0
  52. package/src/components/loader/loader.css.ts +109 -0
  53. package/src/components/loader/moon-loader.tsx +43 -0
  54. package/src/components/loader-overlay/index.ts +1 -0
  55. package/src/components/loader-overlay/loader-overlay.css.ts +35 -0
  56. package/src/components/loader-overlay/loader-overlay.tsx +28 -0
  57. package/src/components/menu/index.ts +2 -0
  58. package/src/components/menu/menu-item.css.ts +79 -0
  59. package/src/components/menu/menu-separator.css.ts +53 -0
  60. package/src/components/popover/index.ts +3 -0
  61. package/src/components/popover/popover-content.css.ts +107 -0
  62. package/src/components/popover/popover-content.tsx +78 -0
  63. package/src/components/popover/popover.tsx +6 -0
  64. package/src/components/scroll-area/index.ts +1 -0
  65. package/src/components/scroll-area/scroll-area.css.ts +72 -0
  66. package/src/components/scroll-area/scroll-area.tsx +39 -0
  67. package/src/components/scroll-area/scroll-bar.tsx +37 -0
  68. package/src/components/seed/index.ts +1 -1
  69. package/src/components/seed/seed.tsx +39 -2
  70. package/src/components/select/index.ts +5 -0
  71. package/src/components/select/select-content.css.ts +22 -0
  72. package/src/components/select/select-content.tsx +51 -0
  73. package/src/components/select/select-item.css.ts +24 -0
  74. package/src/components/select/select-item.tsx +24 -0
  75. package/src/components/select/select-root.tsx +14 -0
  76. package/src/components/select/select-trigger.css.ts +75 -0
  77. package/src/components/select/select-trigger.tsx +47 -0
  78. package/src/components/select/select.tsx +85 -0
  79. package/src/components/sheet/index.ts +5 -0
  80. package/src/components/sheet/sheet-content.css.ts +143 -0
  81. package/src/components/sheet/sheet-content.tsx +43 -0
  82. package/src/components/sheet/sheet-description.tsx +21 -0
  83. package/src/components/sheet/sheet-footer.tsx +15 -0
  84. package/src/components/sheet/sheet-header.css.ts +35 -0
  85. package/src/components/sheet/sheet-header.tsx +32 -0
  86. package/src/components/sheet/sheet-overlay.css.ts +43 -0
  87. package/src/components/sheet/sheet-overlay.tsx +14 -0
  88. package/src/components/sheet/sheet-title.tsx +31 -0
  89. package/src/components/sheet/sheet.tsx +8 -0
  90. package/src/components/stack/index.ts +1 -1
  91. package/src/components/stack/stack.tsx +2 -2
  92. package/src/components/text/index.ts +6 -0
  93. package/src/components/text/text.css.ts +173 -7
  94. package/src/components/text/text.tsx +19 -27
  95. package/src/components/text-field/index.ts +1 -0
  96. package/src/components/text-field/text-field.css.ts +3 -0
  97. package/src/components/text-field/text-field.tsx +64 -0
  98. package/src/components/textarea/index.ts +1 -0
  99. package/src/components/textarea/textarea-input.tsx +20 -0
  100. package/src/components/textarea/textarea.css.ts +10 -0
  101. package/src/components/textarea/textarea.tsx +69 -0
  102. package/src/styles/define-responsive-properties.ts +242 -0
  103. package/src/styles/extract-sprinkles-props.ts +29 -35
  104. package/src/styles/index.ts +9 -0
  105. package/src/styles/reset.css.ts +1 -0
  106. package/src/styles/system-contract.css.ts +0 -2
  107. package/src/styles/typography.css.ts +10 -5
  108. package/src/styles/visually-hidden.css.ts +21 -0
  109. package/build-storybook.log +0 -67
@@ -1,5 +1,52 @@
1
1
  import { recipe, type RecipeVariants } from '@vanilla-extract/recipes';
2
2
 
3
- export const headingRecipe = recipe({});
3
+ import { mapContractVars, sys } from '../../styles';
4
+ import { components } from '../../styles/layers.css';
4
5
 
5
- export type HeadingVariants = NonNullable<RecipeVariants<typeof headingRecipe>>;
6
+ export const headingRoot = recipe({
7
+ base: {
8
+ display: 'flex',
9
+ flexDirection: 'column',
10
+ },
11
+
12
+ variants: {
13
+ align: {
14
+ start: {
15
+ '@layer': {
16
+ [components]: {
17
+ alignItems: 'flex-start',
18
+ textAlign: 'start',
19
+ },
20
+ },
21
+ },
22
+ center: {
23
+ '@layer': {
24
+ [components]: {
25
+ alignItems: 'center',
26
+ textAlign: 'center',
27
+ },
28
+ },
29
+ },
30
+ end: {
31
+ '@layer': {
32
+ [components]: {
33
+ alignItems: 'flex-end',
34
+ textAlign: 'end',
35
+ },
36
+ },
37
+ },
38
+ },
39
+
40
+ spacing: mapContractVars(sys.spacing, (key) => ({
41
+ '@layer': {
42
+ [components]: {
43
+ gap: sys.spacing[key],
44
+ },
45
+ },
46
+ })),
47
+ },
48
+ });
49
+
50
+ export type HeadingRootVariants = NonNullable<
51
+ RecipeVariants<typeof headingRoot>
52
+ >;
@@ -1,83 +1,137 @@
1
- import { getProp, PolymorphicComponentProps } from '@kalink-ui/dibbly';
2
1
  import { clsx } from 'clsx';
2
+ import { ElementType, ReactElement, ReactNode } from 'react';
3
3
 
4
- import {
5
- typography,
6
- Spacing,
7
- TypographySize,
8
- TypographyVariant,
9
- } from '../../styles';
4
+ import { Spacing, TypographySize, TypographyVariant } from '../../styles';
10
5
  import { ConditionalWrapper } from '../conditional-wrapper';
11
- import { Stack } from '../stack';
12
-
13
- import { headingRecipe } from './heading.css';
14
-
15
- type HeadingTypes = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
16
-
17
- type HeadingProps<TUse extends HeadingTypes> =
18
- PolymorphicComponentProps<TUse> & {
19
- /**
20
- * The size of the typography used to render the text.
21
- */
22
- size?: TypographySize;
23
-
24
- /**
25
- * The typography used to render the text.
26
- */
27
- variant: Extract<TypographyVariant, 'display' | 'headline' | 'title'>;
28
-
29
- /**
30
- * The text to render.
31
- */
32
- children: string;
33
-
34
- /**
35
- * If provided, the text will be rendered before the title.
36
- */
37
- pretitle?: string;
38
-
39
- /**
40
- * If provided, the text will be rendered after the title.
41
- */
42
- subtitle?: string;
43
-
44
- /**
45
- * The spacing between the title and the pretitle or subtitle.
46
- */
47
- spacing?: Spacing;
48
- };
49
-
50
- export function Heading<TUse extends HeadingTypes>(props: HeadingProps<TUse>) {
51
- const {
52
- children,
53
- className,
54
- size = 'medium',
55
- use: Comp = 'h1',
56
- variant,
57
- pretitle,
58
- subtitle,
59
- spacing,
60
- ...rest
61
- } = props;
6
+ import { Text, TextProps } from '../text';
62
7
 
8
+ import { headingRoot } from './heading.css';
9
+
10
+ export type HeadingTypes = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
11
+
12
+ export type HeadingProps<TUse extends ElementType = 'h2'> = Omit<
13
+ TextProps<TUse>,
14
+ 'variant' | 'children' | 'align'
15
+ > & {
16
+ align?: Extract<
17
+ Pick<TextProps<TUse>, 'align'>['align'],
18
+ 'start' | 'center' | 'end'
19
+ >;
20
+ /**
21
+ * The typography used to render the text.
22
+ */
23
+ variant: Extract<TypographyVariant, 'display' | 'headline' | 'title'>;
24
+
25
+ /**
26
+ * If provided, the text will be rendered before the title.
27
+ */
28
+ pretitle?: ReactElement<TextProps<'p'>>;
29
+
30
+ /**
31
+ * If provided, the text will be rendered after the title.
32
+ */
33
+ subtitle?: ReactElement<TextProps<'p'>>;
34
+
35
+ /**
36
+ * The spacing between the title and the pretitle or subtitle.
37
+ */
38
+ spacing?: Spacing;
39
+
40
+ /**
41
+ * The text to render.
42
+ */
43
+ children: ReactNode;
44
+
45
+ /**
46
+ * The class to pass to the root element.
47
+ */
48
+ rootClassName?: string;
49
+ };
50
+
51
+ const headingMapping: Record<
52
+ HeadingTypes,
53
+ { variant: TypographyVariant; size: TypographySize }
54
+ > = {
55
+ h1: { variant: 'display', size: 'large' },
56
+ h2: { variant: 'display', size: 'medium' },
57
+ h3: { variant: 'display', size: 'small' },
58
+ h4: { variant: 'headline', size: 'large' },
59
+ h5: { variant: 'headline', size: 'medium' },
60
+ h6: { variant: 'headline', size: 'small' },
61
+ };
62
+
63
+ export function Heading<TUse extends HeadingTypes>({
64
+ children,
65
+ use = 'h2',
66
+ size,
67
+ variant,
68
+ align,
69
+ spacing,
70
+ pretitle,
71
+ subtitle,
72
+ rootClassName,
73
+ ref,
74
+ ...rest
75
+ }: HeadingProps<TUse>) {
63
76
  return (
64
77
  <ConditionalWrapper
65
- use={Stack}
66
- spacing={spacing}
78
+ ref={ref}
79
+ use={'hgroup'}
67
80
  condition={!!pretitle || !!subtitle}
81
+ className={clsx(headingRoot({ align, spacing }), rootClassName)}
68
82
  >
69
- {pretitle && <span>{pretitle}</span>}
70
- <Comp
71
- className={clsx(
72
- headingRecipe(),
73
- getProp(typography, `${variant}.${size}`),
74
- className,
75
- )}
83
+ {pretitle}
84
+
85
+ <Text
86
+ {...(!pretitle && !subtitle && { ref })}
87
+ use={use}
88
+ align={align}
89
+ variant={variant ?? headingMapping[use].variant}
90
+ size={size ?? headingMapping[use].size}
76
91
  {...rest}
77
92
  >
78
93
  {children}
79
- </Comp>
80
- {subtitle && <span>{subtitle}</span>}
94
+ </Text>
95
+
96
+ {subtitle}
81
97
  </ConditionalWrapper>
82
98
  );
83
99
  }
100
+
101
+ type HeadingPretitleProps = Omit<TextProps<'p'>, 'children'> & {
102
+ children?: string | null;
103
+ };
104
+
105
+ Heading.Pretitle = function HeadingPretitle({
106
+ variant = 'title',
107
+ size = 'medium',
108
+ children,
109
+ ...rest
110
+ }: HeadingPretitleProps) {
111
+ return (
112
+ children && (
113
+ <Text use="p" variant={variant} size={size} {...rest}>
114
+ {children}
115
+ </Text>
116
+ )
117
+ );
118
+ };
119
+
120
+ type HeadingSubtitleProps = Omit<TextProps<'p'>, 'children'> & {
121
+ children?: string | null;
122
+ };
123
+
124
+ Heading.Subtitle = function HeadingSubtitle({
125
+ variant = 'title',
126
+ size = 'medium',
127
+ children,
128
+ ...rest
129
+ }: HeadingSubtitleProps) {
130
+ return (
131
+ children && (
132
+ <Text use="p" variant={variant} size={size} {...rest}>
133
+ {children}
134
+ </Text>
135
+ )
136
+ );
137
+ };
@@ -1 +1,2 @@
1
- export { Heading } from './heading';
1
+ export { Heading, type HeadingTypes, type HeadingProps } from './heading';
2
+ export { headingRoot, type HeadingRootVariants } from './heading.css';
@@ -1,14 +1,27 @@
1
- export { Box } from './box';
2
- export { Button } from './button';
3
- export { Center } from './center';
4
- export { Cluster } from './cluster';
5
- export { ConditionalWrapper } from "./conditional-wrapper";
6
- export { Cover } from './cover';
7
- export { Frame } from './frame';
8
- export { Grid } from './grid';
9
- export { Heading } from "./heading";
10
- export { plantSeed } from './seed';
11
- export { Sidebar } from './sidebar';
12
- export { Stack } from './stack';
13
- export { Switcher } from './switcher';
14
- export { Text } from './text';
1
+ export * from './box';
2
+ export * from './button';
3
+ export * from './button-icon';
4
+ export * from './card';
5
+ export * from './center';
6
+ export * from './cluster';
7
+ export * from './conditional-wrapper';
8
+ export * from './cover';
9
+ export * from './divider';
10
+ export * from './form-field';
11
+ export * from './frame';
12
+ export * from './grid';
13
+ export * from './heading';
14
+ export * from './input';
15
+ export * from './label';
16
+ export * from './loader';
17
+ export * from './loader-overlay';
18
+ export * from './scroll-area';
19
+ export * from './seed';
20
+ export * from './select';
21
+ export * from './sheet';
22
+ export * from './sidebar';
23
+ export * from './stack';
24
+ export * from './switcher';
25
+ export * from './text';
26
+ export * from './text-field';
27
+ export * from './textarea';
@@ -0,0 +1,2 @@
1
+ export { Input, type InputProps } from './input';
2
+ export { inputAppearance, type InputAppearanceVariants } from './input.css';
@@ -0,0 +1,58 @@
1
+ import { clsx } from 'clsx';
2
+ import {
3
+ ComponentPropsWithRef,
4
+ ForwardedRef,
5
+ MouseEventHandler,
6
+ ReactNode,
7
+ RefObject,
8
+ useCallback,
9
+ } from 'react';
10
+
11
+ import {
12
+ inputAppearance,
13
+ InputAppearanceVariants,
14
+ inputWrapper,
15
+ } from './input.css';
16
+
17
+ export type InputWrapperProps = ComponentPropsWithRef<'div'> & {
18
+ children: ReactNode;
19
+ className?: string;
20
+ inputRef: RefObject<HTMLInputElement | null>;
21
+ disabled?: boolean;
22
+ } & InputAppearanceVariants;
23
+
24
+ export function InputWrapper({
25
+ children,
26
+ className,
27
+ inputRef,
28
+ disabled,
29
+ variant = 'outlined',
30
+ size = 'md',
31
+ ref,
32
+ }: InputWrapperProps) {
33
+ const handleInputFocus = useCallback<MouseEventHandler<HTMLElement>>(
34
+ (e) => {
35
+ if (disabled || !inputRef?.current || e.target === inputRef.current) {
36
+ return;
37
+ }
38
+
39
+ inputRef.current.click();
40
+ inputRef.current.focus();
41
+ },
42
+ [inputRef, disabled],
43
+ );
44
+
45
+ return (
46
+ <div
47
+ ref={ref as ForwardedRef<HTMLDivElement>}
48
+ className={clsx(
49
+ inputAppearance({ variant, size }),
50
+ inputWrapper,
51
+ className,
52
+ )}
53
+ onClick={handleInputFocus}
54
+ >
55
+ {children}
56
+ </div>
57
+ );
58
+ }
@@ -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';