@crystallize/design-system 1.3.0 → 1.3.2
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 +106 -0
- package/dist/index.css +1813 -0
- package/dist/index.d.ts +345 -2
- package/dist/index.js +2631 -5
- package/dist/index.mjs +2574 -0
- package/package.json +90 -78
- package/readme.md +9 -0
- package/src/Tokens.stories.tsx +18 -0
- package/src/action-menu/ActionMenu.stories.tsx +25 -0
- package/src/action-menu/action-item.tsx +16 -0
- package/src/action-menu/action-menu.css +38 -0
- package/src/action-menu/action-menu.tsx +25 -0
- package/src/action-menu/index.tsx +3 -0
- package/src/avatar/Avatar.stories.tsx +20 -0
- package/src/avatar/avatar.css +23 -0
- package/src/avatar/avatar.tsx +34 -0
- package/src/avatar/get-initials.ts +5 -0
- package/src/avatar/index.ts +1 -0
- package/src/button/Button.stories.tsx +105 -0
- package/src/button/button.css +116 -0
- package/src/button/button.tsx +136 -0
- package/src/button/index.ts +3 -0
- package/src/card/card.css +7 -0
- package/src/card/card.stories.tsx +24 -0
- package/src/card/card.tsx +27 -0
- package/src/card/index.ts +3 -0
- package/src/checkbox/checkbox.css +30 -0
- package/src/checkbox/checkbox.stories.tsx +62 -0
- package/src/checkbox/checkbox.test.tsx +16 -0
- package/src/checkbox/checkbox.tsx +28 -0
- package/src/checkbox/index.ts +1 -0
- package/src/colors/Colors.stories.tsx +127 -0
- package/src/colors/color-defaults.json +15 -0
- package/src/colors/color-pairing.json +12 -0
- package/src/colors/colors.json +158 -0
- package/src/colors/index.ts +1 -0
- package/src/colors/old-to-new.txt +19 -0
- package/src/colors/types.ts +29 -0
- package/src/dialog/Dialog.stories.tsx +168 -0
- package/src/dialog/Dialog.test.tsx +25 -0
- package/src/dialog/config.tsx +139 -0
- package/src/dialog/confirm-dialog.tsx +70 -0
- package/src/dialog/destroyFns.ts +1 -0
- package/src/dialog/dialog.css +27 -0
- package/src/dialog/dialog.tsx +94 -0
- package/src/dialog/index.tsx +40 -0
- package/src/dialog/types.ts +70 -0
- package/src/dropdown-menu/DropdownMenu.stories.tsx +38 -0
- package/src/dropdown-menu/dropdown-menu-item.tsx +15 -0
- package/src/dropdown-menu/dropdown-menu-label.tsx +10 -0
- package/src/dropdown-menu/dropdown-menu-root.tsx +33 -0
- package/src/dropdown-menu/dropdown-menu.css +20 -0
- package/src/dropdown-menu/index.ts +11 -0
- package/src/icon-button/IconButton.stories.tsx +45 -0
- package/src/icon-button/icon-button.css +48 -0
- package/src/icon-button/icon-button.tsx +39 -0
- package/src/icon-button/index.ts +3 -0
- package/src/iconography/Icon.stories.tsx +47 -0
- package/src/iconography/add.tsx +30 -0
- package/src/iconography/arrow.tsx +15 -0
- package/src/iconography/atom.tsx +59 -0
- package/src/iconography/cancel.tsx +26 -0
- package/src/iconography/catalogue.tsx +26 -0
- package/src/iconography/copy.tsx +24 -0
- package/src/iconography/crystal.tsx +93 -0
- package/src/iconography/customers.tsx +38 -0
- package/src/iconography/edit.tsx +30 -0
- package/src/iconography/error.tsx +40 -0
- package/src/iconography/fulfilment.tsx +58 -0
- package/src/iconography/glasses.tsx +62 -0
- package/src/iconography/graphQL.tsx +90 -0
- package/src/iconography/grid.tsx +84 -0
- package/src/iconography/hooks.tsx +26 -0
- package/src/iconography/image.tsx +47 -0
- package/src/iconography/index.ts +63 -0
- package/src/iconography/info.tsx +41 -0
- package/src/iconography/key.tsx +19 -0
- package/src/iconography/language.tsx +38 -0
- package/src/iconography/nail-polish.tsx +84 -0
- package/src/iconography/order.tsx +38 -0
- package/src/iconography/particle.tsx +88 -0
- package/src/iconography/percentage.tsx +44 -0
- package/src/iconography/price-tag.tsx +40 -0
- package/src/iconography/shapes.tsx +48 -0
- package/src/iconography/subscription.tsx +34 -0
- package/src/iconography/topics.tsx +58 -0
- package/src/iconography/triangle.tsx +27 -0
- package/src/iconography/usage.tsx +34 -0
- package/src/iconography/users.tsx +44 -0
- package/src/iconography/warning.tsx +51 -0
- package/src/index.css +14 -0
- package/src/index.ts +33 -0
- package/src/inline-radio/index.ts +1 -0
- package/src/inline-radio/inline-radio.css +36 -0
- package/src/inline-radio/inline-radio.stories.tsx +81 -0
- package/src/inline-radio/inline-radio.tsx +41 -0
- package/src/input/Input.stories.tsx +26 -0
- package/src/input/index.ts +1 -0
- package/src/input/input.css +7 -0
- package/src/input/input.tsx +20 -0
- package/src/input-with-label/InputWithLabel.stories.tsx +98 -0
- package/src/input-with-label/index.ts +3 -0
- package/src/input-with-label/input-with-label.css +35 -0
- package/src/input-with-label/input-with-label.tsx +59 -0
- package/src/label/index.ts +1 -0
- package/src/label/label.css +3 -0
- package/src/label/label.stories.tsx +19 -0
- package/src/label/label.tsx +13 -0
- package/src/progress/Progress.stories.tsx +26 -0
- package/src/progress/index.ts +1 -0
- package/src/progress/progress.css +7 -0
- package/src/progress/progress.tsx +17 -0
- package/src/radio/index.ts +1 -0
- package/src/radio/radio.css +20 -0
- package/src/radio/radio.stories.tsx +142 -0
- package/src/radio/radio.tsx +19 -0
- package/src/select/index.ts +1 -0
- package/src/select/select-item.tsx +18 -0
- package/src/select/select-root.tsx +50 -0
- package/src/select/select.css +44 -0
- package/src/select/select.stories.tsx +74 -0
- package/src/select/select.ts +9 -0
- package/src/slider/Slider.stories.tsx +54 -0
- package/src/slider/index.ts +1 -0
- package/src/slider/slider.css +27 -0
- package/src/slider/slider.tsx +20 -0
- package/src/spinner/Spinner.stories.tsx +19 -0
- package/src/spinner/index.tsx +48 -0
- package/src/spinner/spinner.css +11 -0
- package/src/tag/Tag.stories.tsx +32 -0
- package/src/tag/index.ts +1 -0
- package/src/tag/tag.css +7 -0
- package/src/tag/tag.tsx +27 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.cjs +51 -0
- package/LICENSE +0 -21
- package/README.md +0 -35
- package/dist/components/Button.d.ts +0 -11
- package/dist/components/Typography.d.ts +0 -14
- package/dist/design-system.cjs.development.js +0 -164
- package/dist/design-system.cjs.development.js.map +0 -1
- package/dist/design-system.cjs.production.min.js +0 -2
- package/dist/design-system.cjs.production.min.js.map +0 -1
- package/dist/design-system.esm.js +0 -156
- package/dist/design-system.esm.js.map +0 -1
- package/dist/styles/theme.d.ts +0 -2
|
@@ -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,19 @@
|
|
|
1
|
+
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
2
|
+
import type { ComponentProps } from 'react';
|
|
3
|
+
|
|
4
|
+
import './radio.css';
|
|
5
|
+
|
|
6
|
+
type RadioGroupItemProps = ComponentProps<typeof RadioGroupPrimitive.Item>;
|
|
7
|
+
|
|
8
|
+
function RadioGroupItem(props: RadioGroupItemProps) {
|
|
9
|
+
return (
|
|
10
|
+
<RadioGroupPrimitive.Item {...props} className="c-radio-item">
|
|
11
|
+
<RadioGroupPrimitive.Indicator className="c-radio-indicator" />
|
|
12
|
+
</RadioGroupPrimitive.Item>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const Radio = {
|
|
17
|
+
Group: RadioGroupPrimitive.Root,
|
|
18
|
+
Item: RadioGroupItem,
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './select';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ComponentProps, forwardRef } from 'react';
|
|
2
|
+
import * as SelectPrimitives from '@radix-ui/react-select';
|
|
3
|
+
|
|
4
|
+
export type SelectItemRef = HTMLDivElement;
|
|
5
|
+
export type SelectItemProps = ComponentProps<typeof SelectPrimitives.Item>;
|
|
6
|
+
|
|
7
|
+
export const SelectItem = forwardRef<SelectItemRef, SelectItemProps>((props, ref) => {
|
|
8
|
+
const { children, ...delegated } = props;
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<SelectPrimitives.Item className="c-select-item" ref={ref} {...delegated}>
|
|
12
|
+
<SelectPrimitives.ItemText>{children}</SelectPrimitives.ItemText>
|
|
13
|
+
<SelectPrimitives.ItemIndicator />
|
|
14
|
+
</SelectPrimitives.Item>
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
SelectItem.displayName = 'SelectItem';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ComponentProps, forwardRef } from 'react';
|
|
2
|
+
import * as SelectPrimitives from '@radix-ui/react-select';
|
|
3
|
+
import { cva, VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { Icon } from '../iconography';
|
|
6
|
+
|
|
7
|
+
const selectTriggerStyles = cva('c-select-trigger', {
|
|
8
|
+
variants: {
|
|
9
|
+
size: {
|
|
10
|
+
xs: 'c-select-trigger-xs',
|
|
11
|
+
sm: 'c-select-trigger-sm',
|
|
12
|
+
md: 'c-select-trigger-md',
|
|
13
|
+
lg: 'c-select-trigger-lg',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
size: 'sm',
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
export type SelectRef = HTMLButtonElement;
|
|
22
|
+
export type SelectProps = ComponentProps<typeof SelectPrimitives.Root> &
|
|
23
|
+
VariantProps<typeof selectTriggerStyles> & {
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
id?: string;
|
|
26
|
+
placeholder?: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const SelectContainer = forwardRef<SelectRef, SelectProps>(
|
|
30
|
+
({ children, id, placeholder, disabled, size, ...delegated }, ref) => {
|
|
31
|
+
return (
|
|
32
|
+
<SelectPrimitives.Root {...delegated}>
|
|
33
|
+
<SelectPrimitives.Trigger ref={ref} className={selectTriggerStyles({ size })} disabled={disabled} id={id}>
|
|
34
|
+
<SelectPrimitives.Value placeholder={<span className="c-select-value">{placeholder ?? 'Select...'}</span>} />
|
|
35
|
+
<Icon.Arrow />
|
|
36
|
+
</SelectPrimitives.Trigger>
|
|
37
|
+
|
|
38
|
+
<SelectPrimitives.Portal>
|
|
39
|
+
<SelectPrimitives.Content className="c-select-content">
|
|
40
|
+
<SelectPrimitives.ScrollUpButton />
|
|
41
|
+
<SelectPrimitives.Viewport className="c-select-viewport">{children}</SelectPrimitives.Viewport>
|
|
42
|
+
<SelectPrimitives.ScrollDownButton />
|
|
43
|
+
</SelectPrimitives.Content>
|
|
44
|
+
</SelectPrimitives.Portal>
|
|
45
|
+
</SelectPrimitives.Root>
|
|
46
|
+
);
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
SelectContainer.displayName = 'Select';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
.c-select-trigger {
|
|
2
|
+
@apply inline-flex cursor-pointer items-center justify-center gap-4 whitespace-nowrap rounded border-0 bg-elevate px-4 text-sm font-medium text-gray shadow;
|
|
3
|
+
|
|
4
|
+
&:disabled {
|
|
5
|
+
@apply cursor-default opacity-50;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
&-xs {
|
|
9
|
+
@apply h-6;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&-sm {
|
|
13
|
+
@apply h-9 text-sm;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&-md {
|
|
17
|
+
@apply h-11 text-base;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&-lg {
|
|
21
|
+
@apply h-14 text-lg;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.c-select-value {
|
|
26
|
+
@apply italic text-gray-500-400;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.c-select-content {
|
|
30
|
+
@apply overflow-hidden rounded bg-elevate text-gray shadow;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.c-select-viewport {
|
|
34
|
+
@apply py-2;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.c-select-item {
|
|
38
|
+
@apply flex cursor-pointer items-center whitespace-nowrap px-6 py-2 font-medium text-gray;
|
|
39
|
+
|
|
40
|
+
&:hover,
|
|
41
|
+
&:focus {
|
|
42
|
+
@apply bg-gray-50-900 outline-none;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { Meta } from '@storybook/react';
|
|
3
|
+
|
|
4
|
+
import { Select } from './select';
|
|
5
|
+
import { Label } from '../label';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title: 'Components/Select',
|
|
9
|
+
parameters: {
|
|
10
|
+
backgrounds: { default: 'gray' },
|
|
11
|
+
},
|
|
12
|
+
} as Meta<typeof Select.Container>;
|
|
13
|
+
|
|
14
|
+
export const Example = () => {
|
|
15
|
+
return (
|
|
16
|
+
<Select.Container>
|
|
17
|
+
<Select.Item value="react">React</Select.Item>
|
|
18
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
19
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
20
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
21
|
+
</Select.Container>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Uncontrolled = () => {
|
|
26
|
+
return (
|
|
27
|
+
<Select.Container>
|
|
28
|
+
<Select.Item value="react">React</Select.Item>
|
|
29
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
30
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
31
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
32
|
+
</Select.Container>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const Controlled = () => {
|
|
37
|
+
const [value, setValue] = useState('react');
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<Select.Container value={value} onValueChange={setValue}>
|
|
41
|
+
<Select.Item value="react">React</Select.Item>
|
|
42
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
43
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
44
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
45
|
+
</Select.Container>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const WithLabel = () => {
|
|
50
|
+
const [value, setValue] = useState('react');
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className="flex flex-col items-start space-y-2">
|
|
54
|
+
<Label htmlFor="with-label-c1">Select framework</Label>
|
|
55
|
+
<Select.Container id="with-label-c1" value={value} onValueChange={setValue}>
|
|
56
|
+
<Select.Item value="react">React</Select.Item>
|
|
57
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
58
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
59
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
60
|
+
</Select.Container>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const Disabled = () => {
|
|
66
|
+
return (
|
|
67
|
+
<Select.Container disabled>
|
|
68
|
+
<Select.Item value="react">React</Select.Item>
|
|
69
|
+
<Select.Item value="vue">Vue</Select.Item>
|
|
70
|
+
<Select.Item value="svelte">Svelte</Select.Item>
|
|
71
|
+
<Select.Item value="angular">Angular</Select.Item>
|
|
72
|
+
</Select.Container>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Slider } from '.';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof Slider> = {
|
|
6
|
+
title: 'Components/Slider',
|
|
7
|
+
component: Slider,
|
|
8
|
+
argTypes: {},
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof Slider>;
|
|
13
|
+
|
|
14
|
+
export const Default: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
'aria-label': 'volume',
|
|
17
|
+
defaultValue: [50],
|
|
18
|
+
max: 100,
|
|
19
|
+
step: 1,
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const Vertical: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
'aria-label': 'volume',
|
|
26
|
+
defaultValue: [25],
|
|
27
|
+
max: 100,
|
|
28
|
+
orientation: 'vertical',
|
|
29
|
+
step: 1,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const TransparentRange: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
'aria-label': 'volume',
|
|
36
|
+
defaultValue: [25],
|
|
37
|
+
max: 100,
|
|
38
|
+
step: 1,
|
|
39
|
+
transparentRange: true,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Controlled: Story = {
|
|
44
|
+
render: () => {
|
|
45
|
+
const [value, setValue] = useState<number[]>([25]);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="space-y-6">
|
|
49
|
+
<Slider aria-label="volume" step={1} max={100} onValueChange={setValue} value={value} />
|
|
50
|
+
<pre>{value}</pre>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Slider } from './slider';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.c-slider-root {
|
|
2
|
+
@apply relative flex w-52 touch-none select-none items-center;
|
|
3
|
+
@apply data-[orientation='horizontal']:h-5;
|
|
4
|
+
@apply data-[orientation='vertical']:h-28 data-[orientation='vertical']:w-5 data-[orientation='vertical']:flex-col;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.c-slider-track {
|
|
8
|
+
@apply relative grow rounded-full bg-gray-100-800;
|
|
9
|
+
@apply data-[orientation='horizontal']:h-[3px];
|
|
10
|
+
@apply data-[orientation='vertical']:w-[3px];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.c-slider-range {
|
|
14
|
+
@apply absolute rounded-full bg-gray-600-300;
|
|
15
|
+
@apply data-[orientation="horizontal"]:h-full;
|
|
16
|
+
@apply data-[orientation="vertical"]:w-full;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.c-slider-range-transparent {
|
|
20
|
+
@apply bg-transparent;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.c-slider-thumb {
|
|
24
|
+
@apply block h-5 w-5 rounded-xl bg-gray-600-300 shadow;
|
|
25
|
+
@apply hover:bg-gray-700-200;
|
|
26
|
+
@apply focus:shadow-lg focus:outline-none;
|
|
27
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as SliderPrimitive from '@radix-ui/react-slider';
|
|
2
|
+
import { cx } from 'class-variance-authority';
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
|
|
5
|
+
import './slider.css';
|
|
6
|
+
|
|
7
|
+
type SliderProps = SliderPrimitive.SliderProps & {
|
|
8
|
+
transparentRange?: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const Slider = forwardRef<HTMLSpanElement, SliderProps>(({ className, transparentRange, ...delegated }, ref) => {
|
|
12
|
+
return (
|
|
13
|
+
<SliderPrimitive.Root className={cx('c-slider-root', className)} ref={ref} {...delegated}>
|
|
14
|
+
<SliderPrimitive.Track className="c-slider-track">
|
|
15
|
+
<SliderPrimitive.Range className={`c-slider-range ${transparentRange ? 'c-slider-range-transparent' : ''}`} />
|
|
16
|
+
</SliderPrimitive.Track>
|
|
17
|
+
<SliderPrimitive.Thumb className="c-slider-thumb" />
|
|
18
|
+
</SliderPrimitive.Root>
|
|
19
|
+
);
|
|
20
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
+
import { Spinner } from '.';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Spinner> = {
|
|
5
|
+
title: 'Components/Spinner',
|
|
6
|
+
component: Spinner,
|
|
7
|
+
argTypes: {
|
|
8
|
+
size: {
|
|
9
|
+
defaultValue: 30,
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof Spinner>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
args: {},
|
|
19
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { cx } from 'class-variance-authority';
|
|
2
|
+
import { ComponentPropsWithRef, forwardRef, ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import './spinner.css';
|
|
5
|
+
|
|
6
|
+
const realSize = 40;
|
|
7
|
+
|
|
8
|
+
type SpinnerProps = ComponentPropsWithRef<'div'> & {
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
color?: string;
|
|
12
|
+
size?: number;
|
|
13
|
+
strokeSize?: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const Spinner = forwardRef<HTMLDivElement, SpinnerProps>(
|
|
17
|
+
({ children, className, color = 'currentColor', size = 30, strokeSize, ...delegated }, ref) => {
|
|
18
|
+
const viewSize = size || realSize;
|
|
19
|
+
const sizeHalf = realSize / 2;
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div ref={ref} className={cx('c-spinner', className)} data-testid="loading-spinner" {...delegated}>
|
|
23
|
+
<svg viewBox={`0 0 ${realSize} ${realSize}`} x="0px" y="0px" style={{ width: viewSize, height: viewSize }}>
|
|
24
|
+
<circle
|
|
25
|
+
cx="20"
|
|
26
|
+
cy="20"
|
|
27
|
+
r="18"
|
|
28
|
+
style={{
|
|
29
|
+
stroke: color,
|
|
30
|
+
strokeWidth: strokeSize ? strokeSize : viewSize / 10,
|
|
31
|
+
strokeLinecap: 'round',
|
|
32
|
+
strokeDasharray: size < 16 ? size * 6 : size * 3.5,
|
|
33
|
+
transformOrigin: `${sizeHalf}px ${sizeHalf}px 0`,
|
|
34
|
+
}}
|
|
35
|
+
className="c-spinner-artifact"
|
|
36
|
+
/>
|
|
37
|
+
</svg>
|
|
38
|
+
{children && (
|
|
39
|
+
<span className="c-spinner-children" style={{ fontSize: size ? `${size * 0.75}px` : '1em' }}>
|
|
40
|
+
{children}
|
|
41
|
+
</span>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
Spinner.displayName = 'Spinner';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
+
import { Tag } from '.';
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof Tag> = {
|
|
5
|
+
title: 'Components/Tag',
|
|
6
|
+
component: Tag,
|
|
7
|
+
argTypes: {},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default meta;
|
|
11
|
+
type Story = StoryObj<typeof Tag>;
|
|
12
|
+
|
|
13
|
+
export const Default: Story = {
|
|
14
|
+
args: {
|
|
15
|
+
children: 'EUR',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Elevate: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
children: 'EUR',
|
|
22
|
+
variant: 'elevate',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const DarkMode: Story = {
|
|
27
|
+
args: {
|
|
28
|
+
children: '%',
|
|
29
|
+
variant: 'elevate',
|
|
30
|
+
className: 'c-dark',
|
|
31
|
+
},
|
|
32
|
+
};
|
package/src/tag/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Tag } from './tag';
|
package/src/tag/tag.css
ADDED
package/src/tag/tag.tsx
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { cva, VariantProps } from 'class-variance-authority';
|
|
2
|
+
import type { ComponentProps } from 'react';
|
|
3
|
+
|
|
4
|
+
import './tag.css';
|
|
5
|
+
|
|
6
|
+
type TagStylesProps = VariantProps<typeof tagStyles>;
|
|
7
|
+
const tagStyles = cva('c-tag', {
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: '',
|
|
11
|
+
elevate: 'c-tag-elevate',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
defaultVariants: {
|
|
15
|
+
variant: 'default',
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export type TagProps = ComponentProps<'span'> & TagStylesProps;
|
|
20
|
+
|
|
21
|
+
export function Tag({ children, className, variant, ...delegated }: TagProps) {
|
|
22
|
+
return (
|
|
23
|
+
<span className={tagStyles({ className, variant })} {...delegated}>
|
|
24
|
+
{children}
|
|
25
|
+
</span>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
2
|
+
const defaultTheme = require('tailwindcss/defaultTheme');
|
|
3
|
+
const colorsPlugin = require('./plugins/colors');
|
|
4
|
+
|
|
5
|
+
/** @type {import("tailwindcss").Config} */
|
|
6
|
+
module.exports = {
|
|
7
|
+
content: ['./src/**/*.tsx'],
|
|
8
|
+
safelist: ['c-dark'],
|
|
9
|
+
experimental: {
|
|
10
|
+
optimizeUniversalDefaults: true,
|
|
11
|
+
},
|
|
12
|
+
corePlugins: {
|
|
13
|
+
preflight: false,
|
|
14
|
+
},
|
|
15
|
+
theme: {
|
|
16
|
+
extend: {
|
|
17
|
+
fontFamily: {
|
|
18
|
+
sans: ['Roboto', ...defaultTheme.fontFamily.sans],
|
|
19
|
+
serif: ["'Roboto Slab'", ...defaultTheme.fontFamily.serif],
|
|
20
|
+
},
|
|
21
|
+
colors: {
|
|
22
|
+
// Some nice-to-have colors
|
|
23
|
+
transparent: 'transparent',
|
|
24
|
+
inherit: 'inherit',
|
|
25
|
+
},
|
|
26
|
+
keyframes: {
|
|
27
|
+
spin: {
|
|
28
|
+
'0%': {
|
|
29
|
+
transform: 'rotate(0deg)',
|
|
30
|
+
strokeDashoffset: 26.4, // 40 * 0.66
|
|
31
|
+
},
|
|
32
|
+
'50%': {
|
|
33
|
+
transform: 'rotate(720deg)',
|
|
34
|
+
strokeDashoffset: 125.6, // 40 * 3.14
|
|
35
|
+
},
|
|
36
|
+
'100%': {
|
|
37
|
+
transform: 'rotate(1080deg)',
|
|
38
|
+
strokeDashoffset: 26.4, // 40 * 0.66
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
animation: {
|
|
43
|
+
spin: 'spin 2s linear infinite',
|
|
44
|
+
},
|
|
45
|
+
boxShadow: {
|
|
46
|
+
DEFAULT: '0 2px 4px rgba(130,138,144,0.15)',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
plugins: [colorsPlugin],
|
|
51
|
+
};
|