@crystallize/design-system 0.2.0 → 1.0.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 +10 -0
- package/dist/index.css +1319 -827
- package/dist/index.d.ts +98 -43
- package/dist/index.js +982 -578
- package/dist/index.mjs +973 -573
- package/package.json +40 -23
- package/readme.md +9 -0
- package/src/Tokens.stories.tsx +18 -0
- package/src/action-menu/ActionMenu.stories.tsx +3 -1
- package/src/action-menu/action-item.tsx +1 -9
- package/src/action-menu/action-menu.css +38 -0
- package/src/action-menu/action-menu.tsx +4 -13
- package/src/action-menu/index.tsx +2 -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 +64 -22
- package/src/button/button.css +116 -0
- package/src/button/button.tsx +119 -33
- package/src/button/index.ts +1 -1
- package/src/card/card.css +7 -0
- package/src/card/card.stories.tsx +2 -2
- package/src/card/card.tsx +6 -4
- package/src/card/index.ts +2 -0
- package/src/checkbox/checkbox.css +30 -0
- package/src/checkbox/checkbox.tsx +6 -14
- 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 +9 -6
- package/src/dialog/confirm-dialog.tsx +5 -2
- package/src/dialog/dialog.css +27 -0
- package/src/dialog/dialog.tsx +18 -20
- package/src/dialog/types.ts +4 -1
- package/src/dropdown-menu/DropdownMenu.stories.tsx +6 -14
- package/src/dropdown-menu/dropdown-menu-item.tsx +1 -10
- package/src/dropdown-menu/dropdown-menu-label.tsx +1 -8
- package/src/dropdown-menu/dropdown-menu-root.tsx +9 -5
- package/src/dropdown-menu/dropdown-menu.css +20 -0
- package/src/dropdown-menu/index.ts +2 -0
- package/src/icon-button/IconButton.stories.tsx +9 -6
- package/src/icon-button/icon-button.css +40 -0
- package/src/icon-button/icon-button.tsx +14 -22
- package/src/iconography/Icon.stories.tsx +47 -0
- package/src/{icons → iconography}/arrow.tsx +0 -0
- package/src/iconography/atom.tsx +59 -0
- package/src/{icons → iconography}/cancel.tsx +0 -0
- package/src/iconography/copy.tsx +24 -0
- package/src/iconography/crystal.tsx +93 -0
- package/src/iconography/edit.tsx +30 -0
- package/src/iconography/error.tsx +40 -0
- package/src/{icons → iconography}/glasses.tsx +0 -0
- package/src/{icons → iconography}/graphQL.tsx +0 -0
- package/src/{icons → iconography}/index.ts +10 -2
- package/src/iconography/info.tsx +41 -0
- package/src/{icons → iconography}/nail-polish.tsx +0 -0
- package/src/iconography/particle.tsx +88 -0
- package/src/iconography/triangle.tsx +27 -0
- package/src/iconography/warning.tsx +51 -0
- package/src/index.css +11 -0
- package/src/index.ts +12 -2
- package/src/inline-radio/inline-radio.css +20 -0
- package/src/inline-radio/inline-radio.stories.tsx +1 -1
- package/src/inline-radio/inline-radio.tsx +4 -14
- package/src/input/Input.stories.tsx +8 -1
- package/src/input/input.css +7 -0
- package/src/input/input.tsx +8 -21
- 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/label.css +3 -0
- package/src/label/label.tsx +3 -1
- package/src/progress/progress.css +7 -0
- package/src/progress/progress.tsx +8 -7
- package/src/radio/radio.css +20 -0
- package/src/radio/radio.tsx +4 -11
- package/src/select/select-item.tsx +1 -10
- package/src/select/select-root.tsx +5 -12
- package/src/select/select.css +28 -0
- package/src/select/select.stories.tsx +12 -0
- package/src/select/select.ts +2 -0
- package/src/spinner/Spinner.stories.tsx +19 -0
- package/src/spinner/index.tsx +48 -0
- package/src/spinner/spinner.css +11 -0
- package/tailwind.config.cjs +51 -0
- package/src/button copy/ButtonCopy.stories.tsx +0 -86
- package/src/button copy/button.tsx +0 -61
- package/src/button copy/index.ts +0 -3
- package/src/colors/Colors.stories.mdx +0 -33
- package/src/icons/Iconography.stories.mdx +0 -45
- package/src/icons/dots.tsx +0 -24
- package/src/icons/error.tsx +0 -43
- package/src/icons/info.tsx +0 -46
- package/src/icons/warning.tsx +0 -55
- package/src/text-field/TextField.stories.tsx +0 -20
- package/src/text-field/index.ts +0 -1
- package/src/text-field/text-field.tsx +0 -60
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { InputWithLabel } from '.';
|
|
4
|
+
|
|
5
|
+
const meta: Meta<typeof InputWithLabel> = {
|
|
6
|
+
title: 'Components/InputWithLabel',
|
|
7
|
+
component: InputWithLabel,
|
|
8
|
+
argTypes: {
|
|
9
|
+
variant: {
|
|
10
|
+
defaultValue: '',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default meta;
|
|
16
|
+
|
|
17
|
+
type Story = StoryObj<typeof InputWithLabel>;
|
|
18
|
+
|
|
19
|
+
export const Default: Story = {
|
|
20
|
+
args: {
|
|
21
|
+
placeholder: 'Luke Skywalker',
|
|
22
|
+
label: 'Name',
|
|
23
|
+
value: 'Luke Skywalker',
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Error: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
placeholder: 'Luke Skywalker',
|
|
30
|
+
label: 'Name',
|
|
31
|
+
status: 'error',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const ErrorWithMessage: Story = {
|
|
36
|
+
args: {
|
|
37
|
+
placeholder: 'Luke Skywalker',
|
|
38
|
+
label: 'Name',
|
|
39
|
+
status: 'error',
|
|
40
|
+
errorMessage: 'You are not my father',
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const Elevated: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
placeholder: 'Luke Skywalker',
|
|
47
|
+
label: 'Name',
|
|
48
|
+
variant: 'elevated',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const ElevatedError: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
placeholder: 'Luke Skywalker',
|
|
55
|
+
label: 'Name',
|
|
56
|
+
variant: 'elevated',
|
|
57
|
+
status: 'error',
|
|
58
|
+
errorMessage: 'Something went no no',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const WithAppend: Story = {
|
|
63
|
+
args: {
|
|
64
|
+
placeholder: 'Luke Skywalker',
|
|
65
|
+
label: 'Name',
|
|
66
|
+
variant: 'elevated',
|
|
67
|
+
append: <div className="self-end">🍩</div>,
|
|
68
|
+
id: 'my-id',
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const Disabled: Story = {
|
|
73
|
+
args: {
|
|
74
|
+
placeholder: 'Luke Skywalker',
|
|
75
|
+
label: 'Name',
|
|
76
|
+
disabled: true,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const Readonly: Story = {
|
|
81
|
+
args: {
|
|
82
|
+
placeholder: 'Luke Skywalker',
|
|
83
|
+
label: 'Name',
|
|
84
|
+
readOnly: true,
|
|
85
|
+
value: 'Darth Vader',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const PassingPropsToLabel: Story = {
|
|
90
|
+
args: {
|
|
91
|
+
placeholder: 'Luke Skywalker',
|
|
92
|
+
label: 'Name',
|
|
93
|
+
value: 'Darth Vader',
|
|
94
|
+
labelProps: {
|
|
95
|
+
className: 'bg-elevated',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
.c-input-with-label {
|
|
2
|
+
@apply relative block rounded border border-solid border-transparent p-3;
|
|
3
|
+
|
|
4
|
+
&-input-wrap {
|
|
5
|
+
@apply mt-3 flex;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
&-input {
|
|
9
|
+
@apply flex-1 overflow-hidden text-ellipsis text-base;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&-append {
|
|
13
|
+
@apply -mr-3 flex flex-shrink-0 items-center px-3;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&-elevated {
|
|
17
|
+
@apply bg-elevate shadow;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&.c-input-with-label--error {
|
|
21
|
+
@apply text-error;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&-error {
|
|
25
|
+
@apply !mt-1 text-xs text-error;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&-sm {
|
|
29
|
+
@apply text-sm;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&-lg {
|
|
33
|
+
@apply text-lg;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, ComponentPropsWithRef, forwardRef, ReactNode } from 'react';
|
|
2
|
+
import { cva, cx, VariantProps } from 'class-variance-authority';
|
|
3
|
+
|
|
4
|
+
import { Input } from '../input';
|
|
5
|
+
import { Label } from '../label';
|
|
6
|
+
import { Triangle } from '../iconography/triangle';
|
|
7
|
+
|
|
8
|
+
const inputWithLabelStyles = cva(['c-input-with-label'], {
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: '',
|
|
12
|
+
elevated: 'c-input-with-label-elevated',
|
|
13
|
+
outlined: 'c-input-with-label-outlined',
|
|
14
|
+
},
|
|
15
|
+
status: {
|
|
16
|
+
error: 'c-input-with-label--error',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
type InputWithLabelStylesProps = VariantProps<typeof inputWithLabelStyles>;
|
|
23
|
+
|
|
24
|
+
export type InputWithLabelProps = InputWithLabelStylesProps & {
|
|
25
|
+
label: string;
|
|
26
|
+
append?: ReactNode;
|
|
27
|
+
errorMessage?: string;
|
|
28
|
+
labelProps?: ComponentPropsWithoutRef<'label'>;
|
|
29
|
+
} & ComponentPropsWithRef<'input'>;
|
|
30
|
+
|
|
31
|
+
export type InputWithLabelRef = HTMLInputElement;
|
|
32
|
+
|
|
33
|
+
export const InputWithLabel = forwardRef<InputWithLabelRef, InputWithLabelProps>(
|
|
34
|
+
({ className, label, append, errorMessage, status, variant, id, labelProps, ...delegated }, ref) => {
|
|
35
|
+
const { className: labelClassName, ...labelPropsRest } = labelProps ?? {};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<>
|
|
39
|
+
<Label
|
|
40
|
+
className={inputWithLabelStyles({ status, variant, className: labelClassName })}
|
|
41
|
+
htmlFor={id}
|
|
42
|
+
{...labelPropsRest}
|
|
43
|
+
>
|
|
44
|
+
{label}
|
|
45
|
+
<span className="c-input-with-label-input-wrap">
|
|
46
|
+
<Input className={cx('c-input-with-label-input', className)} ref={ref} id={id} {...delegated} />
|
|
47
|
+
{!append && !errorMessage ? null : (
|
|
48
|
+
<div className="c-input-with-label-append" title={errorMessage}>
|
|
49
|
+
{errorMessage ? <Triangle /> : append}
|
|
50
|
+
</div>
|
|
51
|
+
)}
|
|
52
|
+
</span>
|
|
53
|
+
</Label>
|
|
54
|
+
</>
|
|
55
|
+
);
|
|
56
|
+
},
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
InputWithLabel.displayName = 'InputWithLabel';
|
package/src/label/label.tsx
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { forwardRef, LabelHTMLAttributes } from 'react';
|
|
2
2
|
import { cx } from 'class-variance-authority';
|
|
3
3
|
|
|
4
|
+
import './label.css';
|
|
5
|
+
|
|
4
6
|
type LabelRef = HTMLLabelElement;
|
|
5
7
|
type LabelProps = LabelHTMLAttributes<LabelRef>;
|
|
6
8
|
|
|
7
9
|
export const Label = forwardRef<LabelRef, LabelProps>(({ className, ...delegated }, ref) => {
|
|
8
|
-
return <label ref={ref} className={cx('
|
|
10
|
+
return <label ref={ref} className={cx('c-label', className)} {...delegated} />;
|
|
9
11
|
});
|
|
10
12
|
|
|
11
13
|
Label.displayName = 'Label';
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import * as ProgressPrimitives from '@radix-ui/react-progress';
|
|
2
|
+
import { cx } from 'class-variance-authority';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
value: number;
|
|
5
|
-
};
|
|
4
|
+
import './progress.css';
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
type ProgressProps = ProgressPrimitives.ProgressProps;
|
|
7
|
+
|
|
8
|
+
export function Progress({ className, value }: ProgressProps) {
|
|
8
9
|
return (
|
|
9
|
-
<ProgressPrimitives.Root className=
|
|
10
|
+
<ProgressPrimitives.Root className={cx(className, 'c-progress-root')} value={value}>
|
|
10
11
|
<ProgressPrimitives.Indicator
|
|
11
|
-
className="
|
|
12
|
-
style={{ transform: `translateX(-${100 - value}%)` }}
|
|
12
|
+
className="c-progress-indicator"
|
|
13
|
+
style={{ transform: `translateX(-${100 - (value ?? 0)}%)` }}
|
|
13
14
|
/>
|
|
14
15
|
</ProgressPrimitives.Root>
|
|
15
16
|
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.c-radio-item {
|
|
2
|
+
@apply flex h-3 w-3 flex-shrink-0 items-center justify-center rounded-full border border-solid border-gray-200-700 bg-gray-50-900 p-0;
|
|
3
|
+
|
|
4
|
+
&:focus,
|
|
5
|
+
&:focus-visible {
|
|
6
|
+
@apply outline-none;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
&:disabled {
|
|
10
|
+
@apply bg-gray-100-800 opacity-40;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
&[aria-checked='true'] {
|
|
14
|
+
@apply border-cyan-700-200 bg-cyan-200-700;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.c-radio-indicator {
|
|
19
|
+
@apply block h-[6px] w-[6px] rounded-full bg-cyan-700-200;
|
|
20
|
+
}
|
package/src/radio/radio.tsx
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
2
|
-
import { cx } from 'class-variance-authority';
|
|
3
2
|
import type { ComponentProps } from 'react';
|
|
4
3
|
|
|
4
|
+
import './radio.css';
|
|
5
|
+
|
|
5
6
|
type RadioGroupItemProps = ComponentProps<typeof RadioGroupPrimitive.Item>;
|
|
6
7
|
|
|
7
8
|
function RadioGroupItem(props: RadioGroupItemProps) {
|
|
8
9
|
return (
|
|
9
|
-
<RadioGroupPrimitive.Item
|
|
10
|
-
|
|
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]')} />
|
|
10
|
+
<RadioGroupPrimitive.Item {...props} className="c-radio-item">
|
|
11
|
+
<RadioGroupPrimitive.Indicator className="c-radio-indicator" />
|
|
19
12
|
</RadioGroupPrimitive.Item>
|
|
20
13
|
);
|
|
21
14
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ComponentProps, forwardRef } from 'react';
|
|
2
2
|
import * as SelectPrimitives from '@radix-ui/react-select';
|
|
3
|
-
import { cx } from 'class-variance-authority';
|
|
4
3
|
|
|
5
4
|
export type SelectItemRef = HTMLDivElement;
|
|
6
5
|
export type SelectItemProps = ComponentProps<typeof SelectPrimitives.Item>;
|
|
@@ -9,15 +8,7 @@ export const SelectItem = forwardRef<SelectItemRef, SelectItemProps>((props, ref
|
|
|
9
8
|
const { children, ...delegated } = props;
|
|
10
9
|
|
|
11
10
|
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
|
-
>
|
|
11
|
+
<SelectPrimitives.Item className="c-select-item" ref={ref} {...delegated}>
|
|
21
12
|
<SelectPrimitives.ItemText>{children}</SelectPrimitives.ItemText>
|
|
22
13
|
<SelectPrimitives.ItemIndicator />
|
|
23
14
|
</SelectPrimitives.Item>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ComponentProps, forwardRef } from 'react';
|
|
2
2
|
import * as SelectPrimitives from '@radix-ui/react-select';
|
|
3
3
|
|
|
4
|
-
import { Icon } from '../
|
|
4
|
+
import { Icon } from '../iconography';
|
|
5
5
|
|
|
6
6
|
export type SelectRef = HTMLButtonElement;
|
|
7
7
|
export type SelectProps = ComponentProps<typeof SelectPrimitives.Root> & {
|
|
@@ -14,22 +14,15 @@ export const SelectContainer = forwardRef<SelectRef, SelectProps>(
|
|
|
14
14
|
({ children, id, placeholder, disabled, ...delegated }, ref) => {
|
|
15
15
|
return (
|
|
16
16
|
<SelectPrimitives.Root {...delegated}>
|
|
17
|
-
<SelectPrimitives.Trigger
|
|
18
|
-
|
|
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
|
-
/>
|
|
17
|
+
<SelectPrimitives.Trigger ref={ref} className="c-select-trigger" disabled={disabled} id={id}>
|
|
18
|
+
<SelectPrimitives.Value placeholder={<span className="c-select-value">{placeholder ?? 'Select...'}</span>} />
|
|
26
19
|
<Icon.Arrow />
|
|
27
20
|
</SelectPrimitives.Trigger>
|
|
28
21
|
|
|
29
22
|
<SelectPrimitives.Portal>
|
|
30
|
-
<SelectPrimitives.Content className="
|
|
23
|
+
<SelectPrimitives.Content className="c-select-content">
|
|
31
24
|
<SelectPrimitives.ScrollUpButton />
|
|
32
|
-
<SelectPrimitives.Viewport className="
|
|
25
|
+
<SelectPrimitives.Viewport className="c-select-viewport">{children}</SelectPrimitives.Viewport>
|
|
33
26
|
<SelectPrimitives.ScrollDownButton />
|
|
34
27
|
</SelectPrimitives.Content>
|
|
35
28
|
</SelectPrimitives.Portal>
|
|
@@ -0,0 +1,28 @@
|
|
|
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 py-3 text-sm font-medium text-gray shadow;
|
|
3
|
+
|
|
4
|
+
&:disabled {
|
|
5
|
+
@apply cursor-default opacity-50;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.c-select-value {
|
|
10
|
+
@apply italic text-gray-500-400;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.c-select-content {
|
|
14
|
+
@apply overflow-hidden rounded bg-elevate text-gray shadow;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.c-select-viewport {
|
|
18
|
+
@apply py-2;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.c-select-item {
|
|
22
|
+
@apply flex cursor-pointer items-center whitespace-nowrap px-6 py-2 font-medium text-gray;
|
|
23
|
+
|
|
24
|
+
&:hover,
|
|
25
|
+
&:focus {
|
|
26
|
+
@apply bg-gray-50-900 outline-none;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
import type { Meta } from '@storybook/react';
|
|
3
|
+
|
|
3
4
|
import { Select } from './select';
|
|
4
5
|
import { Label } from '../label';
|
|
5
6
|
|
|
@@ -60,3 +61,14 @@ export const WithLabel = () => {
|
|
|
60
61
|
</div>
|
|
61
62
|
);
|
|
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
|
+
};
|
package/src/select/select.ts
CHANGED
|
@@ -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,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
|
+
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { StoryObj, Meta } from '@storybook/react';
|
|
2
|
-
import { Button } from '.';
|
|
3
|
-
|
|
4
|
-
const meta: Meta<typeof Button> = {
|
|
5
|
-
title: 'Components/ButtonCopy',
|
|
6
|
-
component: Button,
|
|
7
|
-
argTypes: {},
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export default meta;
|
|
11
|
-
type Story = StoryObj<typeof Button>;
|
|
12
|
-
|
|
13
|
-
const variants = ['contained', 'outline', 'link', 'text'] as const;
|
|
14
|
-
const intent = ['default', 'primary', 'success', 'danger'] as const;
|
|
15
|
-
const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
|
|
16
|
-
|
|
17
|
-
export const AllButton: Story = {
|
|
18
|
-
name: 'All Buttons',
|
|
19
|
-
render: () => {
|
|
20
|
-
return (
|
|
21
|
-
<div className="grid grid-cols-4 gap-6 justify-items-center">
|
|
22
|
-
{sizes.map(size =>
|
|
23
|
-
variants.map(variant =>
|
|
24
|
-
intent.map(intent => (
|
|
25
|
-
<Button variant={variant} size={size} intent={intent}>
|
|
26
|
-
Click me
|
|
27
|
-
</Button>
|
|
28
|
-
)),
|
|
29
|
-
),
|
|
30
|
-
)}
|
|
31
|
-
</div>
|
|
32
|
-
);
|
|
33
|
-
},
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const Contained: Story = {
|
|
37
|
-
args: {
|
|
38
|
-
variant: 'contained',
|
|
39
|
-
children: 'Button',
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const Outline: Story = {
|
|
44
|
-
args: {
|
|
45
|
-
variant: 'outline',
|
|
46
|
-
children: 'Button',
|
|
47
|
-
},
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export const Link: Story = {
|
|
51
|
-
args: {
|
|
52
|
-
variant: 'link',
|
|
53
|
-
children: 'Button',
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export const Text: Story = {
|
|
58
|
-
args: {
|
|
59
|
-
variant: 'text',
|
|
60
|
-
children: 'Button',
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export const Primary: Story = {
|
|
65
|
-
args: {
|
|
66
|
-
variant: 'contained',
|
|
67
|
-
children: 'Button',
|
|
68
|
-
intent: 'primary',
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export const Success: Story = {
|
|
73
|
-
args: {
|
|
74
|
-
variant: 'contained',
|
|
75
|
-
children: 'Button',
|
|
76
|
-
intent: 'success',
|
|
77
|
-
},
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
export const Danger: Story = {
|
|
81
|
-
args: {
|
|
82
|
-
variant: 'contained',
|
|
83
|
-
children: 'Button',
|
|
84
|
-
intent: 'danger',
|
|
85
|
-
},
|
|
86
|
-
};
|