@crystallize/design-system 0.0.2 → 0.2.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/CHANGELOG.md +23 -0
- package/dist/index.css +242 -5
- package/dist/index.d.ts +111 -20
- package/dist/index.js +495 -165
- package/dist/index.mjs +482 -163
- package/package.json +15 -12
- package/src/action-menu/action-item.tsx +2 -2
- package/src/action-menu/action-menu.tsx +2 -2
- package/src/checkbox/checkbox.stories.tsx +62 -0
- package/src/checkbox/checkbox.tsx +36 -0
- package/src/checkbox/index.ts +1 -0
- package/src/dialog/dialog.tsx +6 -6
- package/src/dropdown-menu/DropdownMenu.stories.tsx +1 -2
- package/src/dropdown-menu/dropdown-menu-item.tsx +3 -3
- package/src/dropdown-menu/dropdown-menu-label.tsx +3 -3
- package/src/icons/error.tsx +22 -29
- package/src/icons/info.tsx +25 -32
- package/src/icons/warning.tsx +34 -41
- package/src/index.ts +13 -1
- package/src/inline-radio/index.ts +1 -0
- package/src/inline-radio/inline-radio.stories.tsx +62 -0
- package/src/inline-radio/inline-radio.tsx +36 -0
- package/src/input/Input.stories.tsx +19 -0
- package/src/input/index.ts +1 -0
- package/src/input/input.tsx +33 -0
- package/src/label/index.ts +1 -0
- package/src/label/label.stories.tsx +19 -0
- package/src/label/label.tsx +11 -0
- package/src/progress/Progress.stories.tsx +26 -0
- package/src/progress/index.ts +1 -0
- package/src/progress/progress.tsx +16 -0
- package/src/radio/index.ts +1 -0
- package/src/radio/radio.stories.tsx +142 -0
- package/src/radio/radio.tsx +26 -0
- package/src/select/index.ts +1 -0
- package/src/select/select-item.tsx +27 -0
- package/src/select/select-root.tsx +41 -0
- package/src/select/select.stories.tsx +62 -0
- package/src/select/select.ts +7 -0
- package/src/text-field/TextField.stories.tsx +20 -0
- package/src/text-field/index.ts +1 -0
- package/src/text-field/text-field.tsx +60 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { cva, VariantProps } from 'class-variance-authority';
|
|
2
|
+
import { ComponentPropsWithRef, forwardRef } from 'react';
|
|
3
|
+
|
|
4
|
+
type InputStylesProps = VariantProps<typeof inputStyles>;
|
|
5
|
+
const inputStyles = cva(
|
|
6
|
+
[
|
|
7
|
+
'p-0 border-none text-zinc-800',
|
|
8
|
+
'focus:outline-none',
|
|
9
|
+
'placeholder:italic placeholder:font-light placeholder:text-gray-400 placeholder:text-sm',
|
|
10
|
+
'disabled:cursor-default',
|
|
11
|
+
],
|
|
12
|
+
{
|
|
13
|
+
variants: {
|
|
14
|
+
paper: {
|
|
15
|
+
white: 'bg-white',
|
|
16
|
+
gray: 'bg-jupiter',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
paper: 'gray',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
type InputProps = InputStylesProps & ComponentPropsWithRef<'input'>;
|
|
26
|
+
|
|
27
|
+
export type InputRef = HTMLInputElement;
|
|
28
|
+
|
|
29
|
+
export const Input = forwardRef<InputRef, InputProps>(({ className, paper, ...delegated }, ref) => {
|
|
30
|
+
return <input ref={ref} className={inputStyles({ className, paper })} type="text" {...delegated} />;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
Input.displayName = 'Input';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './label';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Label } from './label';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Label> = {
|
|
5
|
+
title: 'Components/Label',
|
|
6
|
+
component: Label,
|
|
7
|
+
argTypes: {},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof Label>;
|
|
13
|
+
|
|
14
|
+
export const Default: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
htmlFor: 'id',
|
|
17
|
+
children: 'Hello, World!',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { forwardRef, LabelHTMLAttributes } from 'react';
|
|
2
|
+
import { cx } from 'class-variance-authority';
|
|
3
|
+
|
|
4
|
+
type LabelRef = HTMLLabelElement;
|
|
5
|
+
type LabelProps = LabelHTMLAttributes<LabelRef>;
|
|
6
|
+
|
|
7
|
+
export const Label = forwardRef<LabelRef, LabelProps>(({ className, ...delegated }, ref) => {
|
|
8
|
+
return <label ref={ref} className={cx('text-xs font-medium text-gray-400', className)} {...delegated} />;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
Label.displayName = 'Label';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Progress } from '.';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Progress> = {
|
|
6
|
+
title: 'Components/Progress',
|
|
7
|
+
component: Progress,
|
|
8
|
+
argTypes: {},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof Progress>;
|
|
13
|
+
|
|
14
|
+
export const Default: Story = {
|
|
15
|
+
name: 'Default',
|
|
16
|
+
render: () => {
|
|
17
|
+
const [progress, setProgress] = useState(13);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const timer = setTimeout(() => setProgress(100), 1500);
|
|
21
|
+
return () => clearTimeout(timer);
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
24
|
+
return <Progress value={progress} />;
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Progress } from './progress';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as ProgressPrimitives from '@radix-ui/react-progress';
|
|
2
|
+
|
|
3
|
+
type ProgressProps = {
|
|
4
|
+
value: number;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function Progress({ value }: ProgressProps) {
|
|
8
|
+
return (
|
|
9
|
+
<ProgressPrimitives.Root className="relative overflow-hidden rounded-full w-full h-6 bg-neutral-200" value={value}>
|
|
10
|
+
<ProgressPrimitives.Indicator
|
|
11
|
+
className="bg-[#50dbdc] w-full h-full transform ease-linear duration-500"
|
|
12
|
+
style={{ transform: `translateX(-${100 - value}%)` }}
|
|
13
|
+
/>
|
|
14
|
+
</ProgressPrimitives.Root>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './radio';
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
import { Radio } from './radio';
|
|
5
|
+
import { Label } from '../label';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Radio.Group> = {
|
|
8
|
+
title: 'Components/Radio',
|
|
9
|
+
component: Radio.Group,
|
|
10
|
+
argTypes: {},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof Radio.Group>;
|
|
16
|
+
|
|
17
|
+
export const Example: Story = {
|
|
18
|
+
render: () => {
|
|
19
|
+
return (
|
|
20
|
+
<Radio.Group defaultValue="default">
|
|
21
|
+
<div className="flex items-center space-x-2">
|
|
22
|
+
<Radio.Item value="default" id="example-r1" />
|
|
23
|
+
<Label htmlFor="example-r1">Default</Label>
|
|
24
|
+
</div>
|
|
25
|
+
<div className="flex items-center space-x-2">
|
|
26
|
+
<Radio.Item value="comfortable" id="example-r2" />
|
|
27
|
+
<Label htmlFor="example-r2">Comfortable</Label>
|
|
28
|
+
</div>
|
|
29
|
+
<div className="flex items-center space-x-2">
|
|
30
|
+
<Radio.Item value="compact" id="example-r3" />
|
|
31
|
+
<Label htmlFor="example-r3">Compact</Label>
|
|
32
|
+
</div>
|
|
33
|
+
</Radio.Group>
|
|
34
|
+
);
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const Uncontrolled: Story = {
|
|
39
|
+
render: () => {
|
|
40
|
+
return (
|
|
41
|
+
<Radio.Group defaultValue="default">
|
|
42
|
+
<div className="flex items-center space-x-2">
|
|
43
|
+
<Radio.Item value="default" id="uncontrolled-r1" />
|
|
44
|
+
<Label htmlFor="uncontrolled-r1">Default</Label>
|
|
45
|
+
</div>
|
|
46
|
+
<div className="flex items-center space-x-2">
|
|
47
|
+
<Radio.Item value="comfortable" id="uncontrolled-r2" />
|
|
48
|
+
<Label htmlFor="uncontrolled-r2">Comfortable</Label>
|
|
49
|
+
</div>
|
|
50
|
+
<div className="flex items-center space-x-2">
|
|
51
|
+
<Radio.Item value="compact" id="uncontrolled-r3" />
|
|
52
|
+
<Label htmlFor="uncontrolled-r3">Compact</Label>
|
|
53
|
+
</div>
|
|
54
|
+
</Radio.Group>
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const Controlled: Story = {
|
|
60
|
+
render: () => {
|
|
61
|
+
const [value, setValue] = useState('default');
|
|
62
|
+
return (
|
|
63
|
+
<Radio.Group value={value} onValueChange={v => setValue(v)}>
|
|
64
|
+
<div className="flex items-center space-x-2">
|
|
65
|
+
<Radio.Item value="default" id="controlled-r1" />
|
|
66
|
+
<Label htmlFor="controlled-r1">Default</Label>
|
|
67
|
+
</div>
|
|
68
|
+
<div className="flex items-center space-x-2">
|
|
69
|
+
<Radio.Item value="comfortable" id="controlled-r2" />
|
|
70
|
+
<Label htmlFor="controlled-r2">Comfortable</Label>
|
|
71
|
+
</div>
|
|
72
|
+
<div className="flex items-center space-x-2">
|
|
73
|
+
<Radio.Item value="compact" id="controlled-r3" />
|
|
74
|
+
<Label htmlFor="controlled-r3">Compact</Label>
|
|
75
|
+
</div>
|
|
76
|
+
</Radio.Group>
|
|
77
|
+
);
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const Horizontal: Story = {
|
|
82
|
+
render: () => {
|
|
83
|
+
return (
|
|
84
|
+
<Radio.Group defaultValue="default" orientation="horizontal" className="flex space-x-6">
|
|
85
|
+
<div className="flex items-center space-x-2">
|
|
86
|
+
<Radio.Item value="default" id="horizontal-r1" />
|
|
87
|
+
<Label htmlFor="horizontal-r1">Default</Label>
|
|
88
|
+
</div>
|
|
89
|
+
<div className="flex items-center space-x-2">
|
|
90
|
+
<Radio.Item value="comfortable" id="horizontal-r2" />
|
|
91
|
+
<Label htmlFor="horizontal-r2">Comfortable</Label>
|
|
92
|
+
</div>
|
|
93
|
+
<div className="flex items-center space-x-2">
|
|
94
|
+
<Radio.Item value="compact" id="horizontal-r3" />
|
|
95
|
+
<Label htmlFor="horizontal-r3">Compact</Label>
|
|
96
|
+
</div>
|
|
97
|
+
</Radio.Group>
|
|
98
|
+
);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const NoLoop: Story = {
|
|
103
|
+
render: () => {
|
|
104
|
+
return (
|
|
105
|
+
<Radio.Group defaultValue="default" loop={false}>
|
|
106
|
+
<div className="flex items-center space-x-2">
|
|
107
|
+
<Radio.Item value="default" id="noloop-r1" />
|
|
108
|
+
<Label htmlFor="noloop-r1">Default</Label>
|
|
109
|
+
</div>
|
|
110
|
+
<div className="flex items-center space-x-2">
|
|
111
|
+
<Radio.Item value="comfortable" id="noloop-r2" />
|
|
112
|
+
<Label htmlFor="noloop-r2">Comfortable</Label>
|
|
113
|
+
</div>
|
|
114
|
+
<div className="flex items-center space-x-2">
|
|
115
|
+
<Radio.Item value="compact" id="noloop-r3" />
|
|
116
|
+
<Label htmlFor="noloop-r3">Compact</Label>
|
|
117
|
+
</div>
|
|
118
|
+
</Radio.Group>
|
|
119
|
+
);
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const Disabled: Story = {
|
|
124
|
+
render: () => {
|
|
125
|
+
return (
|
|
126
|
+
<Radio.Group defaultValue="default">
|
|
127
|
+
<div className="flex items-center space-x-2">
|
|
128
|
+
<Radio.Item value="default" id="disabled-r1" />
|
|
129
|
+
<Label htmlFor="disabled-r1">Default</Label>
|
|
130
|
+
</div>
|
|
131
|
+
<div className="flex items-center space-x-2">
|
|
132
|
+
<Radio.Item value="comfortable" id="disabled-r2" disabled />
|
|
133
|
+
<Label htmlFor="disabled-r2">Comfortable</Label>
|
|
134
|
+
</div>
|
|
135
|
+
<div className="flex items-center space-x-2">
|
|
136
|
+
<Radio.Item value="compact" id="disabled-r3" />
|
|
137
|
+
<Label htmlFor="disabled-r3">Compact</Label>
|
|
138
|
+
</div>
|
|
139
|
+
</Radio.Group>
|
|
140
|
+
);
|
|
141
|
+
},
|
|
142
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
2
|
+
import { cx } from 'class-variance-authority';
|
|
3
|
+
import type { ComponentProps } from 'react';
|
|
4
|
+
|
|
5
|
+
type RadioGroupItemProps = ComponentProps<typeof RadioGroupPrimitive.Item>;
|
|
6
|
+
|
|
7
|
+
function RadioGroupItem(props: RadioGroupItemProps) {
|
|
8
|
+
return (
|
|
9
|
+
<RadioGroupPrimitive.Item
|
|
10
|
+
{...props}
|
|
11
|
+
className={cx(
|
|
12
|
+
'flex h-3 w-3 flex-shrink-0 items-center justify-center rounded-full border border-solid border-[#ddd] bg-white p-0',
|
|
13
|
+
'focus:outline-none',
|
|
14
|
+
'disabled:bg-[#ddd]/20',
|
|
15
|
+
'radix-state-checked:border-[#528693] radix-state-checked:bg-neptune',
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
<RadioGroupPrimitive.Indicator className={cx('block h-[6px] w-[6px] rounded-full bg-[#528693]')} />
|
|
19
|
+
</RadioGroupPrimitive.Item>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const Radio = {
|
|
24
|
+
Group: RadioGroupPrimitive.Root,
|
|
25
|
+
Item: RadioGroupItem,
|
|
26
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './select';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ComponentProps, forwardRef } from 'react';
|
|
2
|
+
import * as SelectPrimitives from '@radix-ui/react-select';
|
|
3
|
+
import { cx } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
export type SelectItemRef = HTMLDivElement;
|
|
6
|
+
export type SelectItemProps = ComponentProps<typeof SelectPrimitives.Item>;
|
|
7
|
+
|
|
8
|
+
export const SelectItem = forwardRef<SelectItemRef, SelectItemProps>((props, ref) => {
|
|
9
|
+
const { children, ...delegated } = props;
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<SelectPrimitives.Item
|
|
13
|
+
className={cx(
|
|
14
|
+
'flex cursor-pointer items-center whitespace-nowrap px-6 py-2 font-medium',
|
|
15
|
+
'focus:bg-neptune/20',
|
|
16
|
+
'hover:bg-neptune/20',
|
|
17
|
+
)}
|
|
18
|
+
ref={ref}
|
|
19
|
+
{...delegated}
|
|
20
|
+
>
|
|
21
|
+
<SelectPrimitives.ItemText>{children}</SelectPrimitives.ItemText>
|
|
22
|
+
<SelectPrimitives.ItemIndicator />
|
|
23
|
+
</SelectPrimitives.Item>
|
|
24
|
+
);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
SelectItem.displayName = 'SelectItem';
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ComponentProps, forwardRef } from 'react';
|
|
2
|
+
import * as SelectPrimitives from '@radix-ui/react-select';
|
|
3
|
+
|
|
4
|
+
import { Icon } from '../icons';
|
|
5
|
+
|
|
6
|
+
export type SelectRef = HTMLButtonElement;
|
|
7
|
+
export type SelectProps = ComponentProps<typeof SelectPrimitives.Root> & {
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
id?: string;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const SelectContainer = forwardRef<SelectRef, SelectProps>(
|
|
14
|
+
({ children, id, placeholder, disabled, ...delegated }, ref) => {
|
|
15
|
+
return (
|
|
16
|
+
<SelectPrimitives.Root {...delegated}>
|
|
17
|
+
<SelectPrimitives.Trigger
|
|
18
|
+
ref={ref}
|
|
19
|
+
className="inline-flex cursor-pointer items-center justify-center gap-4 whitespace-nowrap rounded border-0 bg-white px-4 py-3 text-sm font-medium text-black-text shadow disabled:cursor-default disabled:opacity-50"
|
|
20
|
+
disabled={disabled}
|
|
21
|
+
id={id}
|
|
22
|
+
>
|
|
23
|
+
<SelectPrimitives.Value
|
|
24
|
+
placeholder={<span className="italic text-label">{placeholder ?? 'Select...'}</span>}
|
|
25
|
+
/>
|
|
26
|
+
<Icon.Arrow />
|
|
27
|
+
</SelectPrimitives.Trigger>
|
|
28
|
+
|
|
29
|
+
<SelectPrimitives.Portal>
|
|
30
|
+
<SelectPrimitives.Content className="overflow-hidden rounded bg-white text-black-text shadow">
|
|
31
|
+
<SelectPrimitives.ScrollUpButton />
|
|
32
|
+
<SelectPrimitives.Viewport className="py-2">{children}</SelectPrimitives.Viewport>
|
|
33
|
+
<SelectPrimitives.ScrollDownButton />
|
|
34
|
+
</SelectPrimitives.Content>
|
|
35
|
+
</SelectPrimitives.Portal>
|
|
36
|
+
</SelectPrimitives.Root>
|
|
37
|
+
);
|
|
38
|
+
},
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
SelectContainer.displayName = 'Select';
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { Meta } from '@storybook/react';
|
|
3
|
+
import { Select } from './select';
|
|
4
|
+
import { Label } from '../label';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Components/Select',
|
|
8
|
+
parameters: {
|
|
9
|
+
backgrounds: { default: 'gray' },
|
|
10
|
+
},
|
|
11
|
+
} as Meta<typeof Select.Container>;
|
|
12
|
+
|
|
13
|
+
export const Example = () => {
|
|
14
|
+
return (
|
|
15
|
+
<Select.Container>
|
|
16
|
+
<Select.Item value="react">React</Select.Item>
|
|
17
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
18
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
19
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
20
|
+
</Select.Container>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const Uncontrolled = () => {
|
|
25
|
+
return (
|
|
26
|
+
<Select.Container>
|
|
27
|
+
<Select.Item value="react">React</Select.Item>
|
|
28
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
29
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
30
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
31
|
+
</Select.Container>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Controlled = () => {
|
|
36
|
+
const [value, setValue] = useState('react');
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Select.Container value={value} onValueChange={setValue}>
|
|
40
|
+
<Select.Item value="react">React</Select.Item>
|
|
41
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
42
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
43
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
44
|
+
</Select.Container>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const WithLabel = () => {
|
|
49
|
+
const [value, setValue] = useState('react');
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className="flex flex-col items-start space-y-2">
|
|
53
|
+
<Label htmlFor="with-label-c1">Select framework</Label>
|
|
54
|
+
<Select.Container id="with-label-c1" value={value} onValueChange={setValue}>
|
|
55
|
+
<Select.Item value="react">React</Select.Item>
|
|
56
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
57
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
58
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
59
|
+
</Select.Container>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { TextField } from '.';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof TextField> = {
|
|
6
|
+
title: 'Components/TextField',
|
|
7
|
+
component: TextField,
|
|
8
|
+
argTypes: {},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof TextField>;
|
|
14
|
+
|
|
15
|
+
export const Default: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
placeholder: 'Luke Skywalker',
|
|
18
|
+
label: 'Name',
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TextField } from './text-field';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ComponentPropsWithRef, forwardRef, ReactNode } from 'react';
|
|
2
|
+
import { cva, VariantProps } from 'class-variance-authority';
|
|
3
|
+
|
|
4
|
+
import { Input } from '../input';
|
|
5
|
+
|
|
6
|
+
type TextFieldStylesProps = VariantProps<typeof textFieldStyles>;
|
|
7
|
+
const textFieldStyles = cva(
|
|
8
|
+
['relative gap-3 flex flex-col p-3 text-sm font-medium text-gray-400 rounded border border-transparent border-solid'],
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
outlined: '',
|
|
13
|
+
filled: '',
|
|
14
|
+
standard: '',
|
|
15
|
+
},
|
|
16
|
+
raised: {
|
|
17
|
+
sm: 'shadow-sm',
|
|
18
|
+
md: 'shadow-md',
|
|
19
|
+
lg: 'shadow-lg',
|
|
20
|
+
},
|
|
21
|
+
paper: {
|
|
22
|
+
white: 'bg-white',
|
|
23
|
+
gray: 'bg-jupiter',
|
|
24
|
+
},
|
|
25
|
+
error: {
|
|
26
|
+
true: 'border-rose-800 text-rose-800',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
variant: 'standard',
|
|
31
|
+
paper: 'white',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
export type TextFieldProps = Omit<TextFieldStylesProps, 'error'> & {
|
|
37
|
+
label: string;
|
|
38
|
+
startAdornment?: ReactNode;
|
|
39
|
+
endAdornment?: ReactNode;
|
|
40
|
+
error?: string;
|
|
41
|
+
} & ComponentPropsWithRef<'input'>;
|
|
42
|
+
|
|
43
|
+
export type TextFieldRef = HTMLInputElement;
|
|
44
|
+
|
|
45
|
+
export const TextField = forwardRef<TextFieldRef, TextFieldProps>(
|
|
46
|
+
({ variant, raised, className, label, paper, endAdornment, error, ...delegated }, ref) => {
|
|
47
|
+
return (
|
|
48
|
+
<>
|
|
49
|
+
<label className={textFieldStyles({ variant, raised, paper, error: Boolean(error), className })}>
|
|
50
|
+
{label}
|
|
51
|
+
<Input ref={ref} className="w-10/12 text-ellipsis overflow-hidden" type="text" {...delegated} />
|
|
52
|
+
<div className="absolute right-1 top-2/3 -translate-y-1/2 ">{endAdornment}</div>
|
|
53
|
+
</label>
|
|
54
|
+
{error && <div className="text-rose-800 text-sm px-3 !mt-1">{error}</div>}
|
|
55
|
+
</>
|
|
56
|
+
);
|
|
57
|
+
},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
TextField.displayName = 'TextField';
|