@crystallize/design-system 0.0.2 → 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.
Files changed (112) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/index.css +1362 -633
  3. package/dist/index.d.ts +171 -25
  4. package/dist/index.js +1124 -390
  5. package/dist/index.mjs +1108 -389
  6. package/package.json +47 -27
  7. package/readme.md +9 -0
  8. package/src/Tokens.stories.tsx +18 -0
  9. package/src/action-menu/ActionMenu.stories.tsx +3 -1
  10. package/src/action-menu/action-item.tsx +2 -10
  11. package/src/action-menu/action-menu.css +38 -0
  12. package/src/action-menu/action-menu.tsx +4 -13
  13. package/src/action-menu/index.tsx +2 -0
  14. package/src/avatar/Avatar.stories.tsx +20 -0
  15. package/src/avatar/avatar.css +23 -0
  16. package/src/avatar/avatar.tsx +34 -0
  17. package/src/avatar/get-initials.ts +5 -0
  18. package/src/avatar/index.ts +1 -0
  19. package/src/button/Button.stories.tsx +64 -22
  20. package/src/button/button.css +116 -0
  21. package/src/button/button.tsx +119 -33
  22. package/src/button/index.ts +1 -1
  23. package/src/card/card.css +7 -0
  24. package/src/card/card.stories.tsx +2 -2
  25. package/src/card/card.tsx +6 -4
  26. package/src/card/index.ts +2 -0
  27. package/src/checkbox/checkbox.css +30 -0
  28. package/src/checkbox/checkbox.stories.tsx +62 -0
  29. package/src/checkbox/checkbox.tsx +28 -0
  30. package/src/checkbox/index.ts +1 -0
  31. package/src/colors/Colors.stories.tsx +127 -0
  32. package/src/colors/color-defaults.json +15 -0
  33. package/src/colors/color-pairing.json +12 -0
  34. package/src/colors/colors.json +158 -0
  35. package/src/colors/index.ts +1 -0
  36. package/src/colors/old-to-new.txt +19 -0
  37. package/src/colors/types.ts +29 -0
  38. package/src/dialog/Dialog.stories.tsx +9 -6
  39. package/src/dialog/confirm-dialog.tsx +5 -2
  40. package/src/dialog/dialog.css +27 -0
  41. package/src/dialog/dialog.tsx +23 -25
  42. package/src/dialog/types.ts +4 -1
  43. package/src/dropdown-menu/DropdownMenu.stories.tsx +6 -15
  44. package/src/dropdown-menu/dropdown-menu-item.tsx +3 -12
  45. package/src/dropdown-menu/dropdown-menu-label.tsx +2 -9
  46. package/src/dropdown-menu/dropdown-menu-root.tsx +9 -5
  47. package/src/dropdown-menu/dropdown-menu.css +20 -0
  48. package/src/dropdown-menu/index.ts +2 -0
  49. package/src/icon-button/IconButton.stories.tsx +9 -6
  50. package/src/icon-button/icon-button.css +40 -0
  51. package/src/icon-button/icon-button.tsx +14 -22
  52. package/src/iconography/Icon.stories.tsx +47 -0
  53. package/src/{icons → iconography}/arrow.tsx +0 -0
  54. package/src/iconography/atom.tsx +59 -0
  55. package/src/{icons → iconography}/cancel.tsx +0 -0
  56. package/src/iconography/copy.tsx +24 -0
  57. package/src/iconography/crystal.tsx +93 -0
  58. package/src/iconography/edit.tsx +30 -0
  59. package/src/iconography/error.tsx +40 -0
  60. package/src/{icons → iconography}/glasses.tsx +0 -0
  61. package/src/{icons → iconography}/graphQL.tsx +0 -0
  62. package/src/{icons → iconography}/index.ts +10 -2
  63. package/src/iconography/info.tsx +41 -0
  64. package/src/{icons → iconography}/nail-polish.tsx +0 -0
  65. package/src/iconography/particle.tsx +88 -0
  66. package/src/iconography/triangle.tsx +27 -0
  67. package/src/iconography/warning.tsx +51 -0
  68. package/src/index.css +11 -0
  69. package/src/index.ts +23 -1
  70. package/src/inline-radio/index.ts +1 -0
  71. package/src/inline-radio/inline-radio.css +20 -0
  72. package/src/inline-radio/inline-radio.stories.tsx +62 -0
  73. package/src/inline-radio/inline-radio.tsx +26 -0
  74. package/src/input/Input.stories.tsx +26 -0
  75. package/src/input/index.ts +1 -0
  76. package/src/input/input.css +7 -0
  77. package/src/input/input.tsx +20 -0
  78. package/src/input-with-label/InputWithLabel.stories.tsx +98 -0
  79. package/src/input-with-label/index.ts +3 -0
  80. package/src/input-with-label/input-with-label.css +35 -0
  81. package/src/input-with-label/input-with-label.tsx +59 -0
  82. package/src/label/index.ts +1 -0
  83. package/src/label/label.css +3 -0
  84. package/src/label/label.stories.tsx +19 -0
  85. package/src/label/label.tsx +13 -0
  86. package/src/progress/Progress.stories.tsx +26 -0
  87. package/src/progress/index.ts +1 -0
  88. package/src/progress/progress.css +7 -0
  89. package/src/progress/progress.tsx +17 -0
  90. package/src/radio/index.ts +1 -0
  91. package/src/radio/radio.css +20 -0
  92. package/src/radio/radio.stories.tsx +142 -0
  93. package/src/radio/radio.tsx +19 -0
  94. package/src/select/index.ts +1 -0
  95. package/src/select/select-item.tsx +18 -0
  96. package/src/select/select-root.tsx +34 -0
  97. package/src/select/select.css +28 -0
  98. package/src/select/select.stories.tsx +74 -0
  99. package/src/select/select.ts +9 -0
  100. package/src/spinner/Spinner.stories.tsx +19 -0
  101. package/src/spinner/index.tsx +48 -0
  102. package/src/spinner/spinner.css +11 -0
  103. package/tailwind.config.cjs +51 -0
  104. package/src/button copy/ButtonCopy.stories.tsx +0 -86
  105. package/src/button copy/button.tsx +0 -61
  106. package/src/button copy/index.ts +0 -3
  107. package/src/colors/Colors.stories.mdx +0 -33
  108. package/src/icons/Iconography.stories.mdx +0 -45
  109. package/src/icons/dots.tsx +0 -24
  110. package/src/icons/error.tsx +0 -50
  111. package/src/icons/info.tsx +0 -53
  112. package/src/icons/warning.tsx +0 -62
@@ -0,0 +1,29 @@
1
+ export type Color = {
2
+ 50: string;
3
+ 100: string;
4
+ 200: string;
5
+ 300: string;
6
+ 400: string;
7
+ 500: string;
8
+ 600: string;
9
+ 700: string;
10
+ 800: string;
11
+ 900: string;
12
+ };
13
+
14
+ export type ColorName =
15
+ | 'cyan'
16
+ | 'pink'
17
+ | 'gray'
18
+ | 'purple'
19
+ | 'green'
20
+ | 'orange'
21
+ | 's-red'
22
+ | 's-orange'
23
+ | 's-yellow'
24
+ | 's-green'
25
+ | 's-blue'
26
+ | 's-purple'
27
+ | 's-pink';
28
+
29
+ export type Colors = Record<ColorName, Color>;
@@ -15,9 +15,9 @@ export default meta;
15
15
  type Story = StoryObj<typeof Dialog>;
16
16
 
17
17
  const Lorem = () => (
18
- <p className="py-6">
18
+ <p className="leading-6">
19
19
  Lorem ipsum, dolor sit amet consectetur adipisicing elit. Reiciendis neque id, blanditiis exercitationem doloremque
20
- quam ab minima architecto culpa, nam nobis labore quibusdam veniam maiores. Veritatis non maxime ut magnam?
20
+ quam ab minima architecto culpa.
21
21
  </p>
22
22
  );
23
23
 
@@ -54,10 +54,13 @@ export const ComponentWithDangerAction: Story = {
54
54
  <Dialog.Content>
55
55
  <Dialog.Title>A Dialog</Dialog.Title>
56
56
  <div>
57
- <Lorem />
58
- <div className="flex gap-4 justify-end">
59
- <Button variant="secondary-dark">Cancel</Button>
60
- <Button variant="danger">Delete</Button>
57
+ <Dialog.Description>
58
+ <Lorem />
59
+ </Dialog.Description>
60
+
61
+ <div className="mt-8 flex justify-end gap-4">
62
+ <Button>Cancel</Button>
63
+ <Button intent="danger">Delete</Button>
61
64
  </div>
62
65
  </div>
63
66
  </Dialog.Content>
@@ -11,6 +11,7 @@ export function ConfirmDialog({
11
11
  content,
12
12
  okCancel,
13
13
  okText = 'OK',
14
+ okButtonIntent = 'default',
14
15
  onOk,
15
16
  onCancel,
16
17
  cancelText = 'Cancel',
@@ -18,10 +19,10 @@ export function ConfirmDialog({
18
19
  onInteractOutside,
19
20
  onPointerDownOutside,
20
21
  type,
22
+ closable,
21
23
  }: ConfirmDialogProps) {
22
24
  const cancelButton = okCancel && (
23
25
  <Button
24
- variant="secondary"
25
26
  onClick={() => {
26
27
  onCancel?.();
27
28
  close();
@@ -38,13 +39,15 @@ export function ConfirmDialog({
38
39
  onInteractOutside={onInteractOutside}
39
40
  onPointerDownOutside={onPointerDownOutside}
40
41
  type={type}
42
+ closable={closable}
41
43
  >
42
44
  {title && <Dialog.Title>{title}</Dialog.Title>}
43
45
  {description && <Dialog.Description>{description}</Dialog.Description>}
44
46
  {content}
45
- <div className="flex items-center gap-4 mt-4 justify-end">
47
+ <div className="mt-4 flex items-center justify-end gap-4">
46
48
  {cancelButton}
47
49
  <Button
50
+ intent={okButtonIntent}
48
51
  onClick={() => {
49
52
  onOk?.();
50
53
  close();
@@ -0,0 +1,27 @@
1
+ .c-dialog {
2
+ @apply fixed top-1/2 left-1/2 z-20 w-auto min-w-[25%] max-w-xl rounded-lg bg-elevate p-14 leading-6 text-gray-500-400 shadow;
3
+ transform: translate(-50%, -50%);
4
+ &-overlay {
5
+ @apply fixed inset-0 z-10 bg-overlay;
6
+ }
7
+
8
+ &-icon {
9
+ @apply my-1 shrink-0;
10
+ }
11
+
12
+ &-title {
13
+ @apply m-0 font-serif text-xl font-bold text-gray;
14
+ }
15
+
16
+ &-description {
17
+ @apply mt-1 mb-5 font-medium;
18
+ }
19
+
20
+ &-close-button {
21
+ @apply absolute top-0 right-0 inline-flex h-12 w-12 items-center justify-center rounded-none rounded-tr-lg border !bg-transparent !p-0 !drop-shadow-none hover:!bg-gray-50-900 focus:!bg-gray-50-900;
22
+ }
23
+
24
+ &-with-icon {
25
+ @apply flex items-start gap-6 pl-6;
26
+ }
27
+ }
@@ -1,12 +1,13 @@
1
1
  import type { ReactNode, RefAttributes } from 'react';
2
- import clsx from 'clsx';
3
2
  import * as DialogPrimitive from '@radix-ui/react-dialog';
4
- import { cva, VariantProps } from 'class-variance-authority';
3
+ import { cva, cx, VariantProps } from 'class-variance-authority';
5
4
 
6
5
  import { Button } from '../button';
7
- import { Icon } from '../icons';
6
+ import { Icon } from '../iconography';
8
7
  import type { DialogFuncProps } from './types';
9
8
 
9
+ import './dialog.css';
10
+
10
11
  const IconMap = {
11
12
  error: Icon.Error,
12
13
  info: Icon.Info,
@@ -14,16 +15,13 @@ const IconMap = {
14
15
  };
15
16
 
16
17
  type DialogContentStylesProps = VariantProps<typeof dialogContentStyles>;
17
- const dialogContentStyles = cva(
18
- 'bg-white rounded shadow fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 max-w-xl w-auto p-6',
19
- {
20
- variants: {
21
- withIcon: {
22
- true: 'flex gap-4 items-start',
23
- },
18
+ const dialogContentStyles = cva('c-dialog', {
19
+ variants: {
20
+ withIcon: {
21
+ true: 'c-dialog-with-icon',
24
22
  },
25
23
  },
26
- );
24
+ });
27
25
 
28
26
  type DialogContentProps = DialogContentStylesProps & {
29
27
  children: ReactNode;
@@ -31,22 +29,27 @@ type DialogContentProps = DialogContentStylesProps & {
31
29
  DialogFuncProps,
32
30
  'onEscapeKeyDown' | 'onInteractOutside' | 'onPointerDownOutside' | 'closable' | 'type' | 'className'
33
31
  > &
34
- DialogPrimitive.DialogContentProps;
32
+ DialogPrimitive.DialogContentProps &
33
+ Pick<DialogPrimitive.PortalProps, 'container'>;
35
34
 
36
- function DialogContent({ children, closable = true, type, className, ...delegated }: DialogContentProps) {
35
+ function DialogContent({ children, closable = true, type, className, container, ...delegated }: DialogContentProps) {
37
36
  const withIcon = typeof type !== 'undefined';
38
37
 
39
38
  const IconComponent = type && IconMap[type];
40
39
 
41
40
  return (
42
- <DialogPrimitive.Portal>
43
- <DialogPrimitive.Overlay className="bg-black/30 fixed inset-0" />
41
+ <DialogPrimitive.Portal container={container}>
42
+ <DialogPrimitive.Overlay className="c-dialog-overlay" />
44
43
  <DialogPrimitive.Content className={dialogContentStyles({ withIcon, class: className })} {...delegated}>
45
- {IconComponent && <IconComponent className="my-1 shrink-0" width={32} height={32} />}
44
+ {IconComponent && (
45
+ <div className="flex h-[44px] w-[44px] min-w-[44px] items-center justify-center rounded-lg bg-gray-50-900 p-[5px]">
46
+ <IconComponent className="c-dialog-icon" width={34} height={34} />
47
+ </div>
48
+ )}
46
49
  {closable && (
47
50
  <DialogClose asChild>
48
- <Button className="absolute top-2.5 right-2.5 !rounded-full !p-0 h-6 w-6 inline-flex items-center justify-center !bg-transparent hover:!bg-gray-200 focus:!bg-gray-200 !drop-shadow-none">
49
- <Icon.Cancel color="density" aria-label="Close" height={18} width={18} />
51
+ <Button className="c-dialog-close-button">
52
+ <Icon.Cancel color="density" aria-label="Close" height={16} width={16} />
50
53
  </Button>
51
54
  </DialogClose>
52
55
  )}
@@ -59,12 +62,7 @@ function DialogContent({ children, closable = true, type, className, ...delegate
59
62
  type DialogTitleProps = JSX.IntrinsicAttributes & DialogPrimitive.DialogTitleProps & RefAttributes<HTMLHeadingElement>;
60
63
 
61
64
  function DialogTitle({ className, ...delegated }: DialogTitleProps) {
62
- return (
63
- <DialogPrimitive.Title
64
- className={clsx('m-0 font-semibold text-2xl font-sans text-black-text', className)}
65
- {...delegated}
66
- />
67
- );
65
+ return <DialogPrimitive.Title className={cx('c-dialog-title', className)} {...delegated} />;
68
66
  }
69
67
 
70
68
  type DialogDescriptionProps = JSX.IntrinsicAttributes &
@@ -72,7 +70,7 @@ type DialogDescriptionProps = JSX.IntrinsicAttributes &
72
70
  RefAttributes<HTMLParagraphElement>;
73
71
 
74
72
  function DialogDescription(delegated: DialogDescriptionProps) {
75
- return <DialogPrimitive.Description className="mt-2 mb-5 text-gray-600" {...delegated} />;
73
+ return <DialogPrimitive.Description className="c-dialog-description" {...delegated} />;
76
74
  }
77
75
 
78
76
  const DialogTrigger = DialogPrimitive.Trigger;
@@ -1,4 +1,6 @@
1
- import type { ReactNode } from 'react';
1
+ import type { ReactNode, ComponentProps } from 'react';
2
+
3
+ import type { Button } from '../button';
2
4
 
3
5
  export type DialogFuncProps = {
4
6
  afterClose?: () => void;
@@ -9,6 +11,7 @@ export type DialogFuncProps = {
9
11
  description?: ReactNode;
10
12
  okCancel?: boolean;
11
13
  okText?: ReactNode;
14
+ okButtonIntent?: ComponentProps<typeof Button>['intent'];
12
15
  onCancel?: (...args: unknown[]) => void;
13
16
  onEscapeKeyDown?: (event: Event) => void;
14
17
  onInteractOutside?: (event: Event) => void;
@@ -1,10 +1,8 @@
1
1
  import type { Meta } from '@storybook/react';
2
- import clsx from 'clsx';
3
- import { useState } from 'react';
4
2
 
5
3
  import { DropdownMenu } from '.';
6
4
  import { Button } from '../button';
7
- import { Icon } from '../icons';
5
+ import { Icon } from '../iconography';
8
6
 
9
7
  export default {
10
8
  title: 'Components/DropdownMenu',
@@ -16,15 +14,15 @@ function ContentWithIcon() {
16
14
  <>
17
15
  <DropdownMenu.Label>View</DropdownMenu.Label>
18
16
  <DropdownMenu.Item>
19
- <div className="flex items-center">
17
+ <div className="flex items-center font-sans">
20
18
  <Icon.Glasses width={24} height={24} />
21
- <span className="px-4">Nerdy</span>
19
+ <span className="px-3">Nerdy</span>
22
20
  </div>
23
21
  </DropdownMenu.Item>
24
22
  <DropdownMenu.Item>
25
23
  <div className="flex items-center">
26
24
  <Icon.GraphQL width={24} height={24} />
27
- <span className="px-4">Developer</span>
25
+ <span className="px-3 font-sans">Developer</span>
28
26
  </div>
29
27
  </DropdownMenu.Item>
30
28
  </>
@@ -32,16 +30,9 @@ function ContentWithIcon() {
32
30
  }
33
31
 
34
32
  export const WithOpenState = () => {
35
- const [isOpen, setIsOpen] = useState(false);
36
-
37
33
  return (
38
- <DropdownMenu.Root content={<ContentWithIcon />} onOpenChange={setIsOpen}>
39
- <Button>
40
- <div className="flex items-center">
41
- <Icon.NailPolish width={20} height={20} /> <span className="pl-4 pr-8">Pretty</span>
42
- <Icon.Arrow className={clsx({ 'rotate-180': isOpen })} />
43
- </div>
44
- </Button>
34
+ <DropdownMenu.Root content={<ContentWithIcon />}>
35
+ <Button prepend={<Icon.NailPolish width={20} height={20} />}>Pretty</Button>
45
36
  </DropdownMenu.Root>
46
37
  );
47
38
  };
@@ -1,6 +1,6 @@
1
- import type { ReactNode } from 'react';
2
1
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3
- import clsx from 'clsx';
2
+ import { cx } from 'class-variance-authority';
3
+ import type { ReactNode } from 'react';
4
4
 
5
5
  type DropdownMenuItemProps = DropdownMenuPrimitive.MenuItemProps & {
6
6
  children: ReactNode;
@@ -8,16 +8,7 @@ type DropdownMenuItemProps = DropdownMenuPrimitive.MenuItemProps & {
8
8
 
9
9
  export function DropdownMenuItem({ children, className, ...delegated }: DropdownMenuItemProps) {
10
10
  return (
11
- <DropdownMenuPrimitive.Item
12
- {...delegated}
13
- className={clsx(
14
- 'text-xs font-medium text-black-text',
15
- 'flex h-10 cursor-pointer items-center bg-white px-4 outline-asteroid',
16
- 'hover:bg-[#F8F8F9] hover:outline-none hover:focus-visible:outline-none',
17
- 'first:rounded-tr first:rounded-tl last:rounded-br last:rounded-bl',
18
- className,
19
- )}
20
- >
11
+ <DropdownMenuPrimitive.Item {...delegated} className={cx('c-dropdown-menu-item', className)}>
21
12
  {children}
22
13
  </DropdownMenuPrimitive.Item>
23
14
  );
@@ -1,17 +1,10 @@
1
- import type { ReactNode } from 'react';
2
- import clsx from 'clsx';
3
1
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
2
+ import type { ReactNode } from 'react';
4
3
 
5
4
  type DropdownMenuLabelProps = {
6
5
  children: ReactNode;
7
6
  };
8
7
 
9
8
  export function DropdownMenuLabel({ children }: DropdownMenuLabelProps) {
10
- return (
11
- <DropdownMenuPrimitive.Label
12
- className={clsx('bg-white px-4 py-2 text-xs text-label', 'first:rounded-tl first:rounded-tr')}
13
- >
14
- {children}
15
- </DropdownMenuPrimitive.Label>
16
- );
9
+ return <DropdownMenuPrimitive.Label className="c-dropdown-menu-label">{children}</DropdownMenuPrimitive.Label>;
17
10
  }
@@ -1,18 +1,22 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3
3
 
4
- type DropdownMenuRootProps = {
4
+ type DropdownMenuRootProps = DropdownMenuPrimitive.MenuContentProps & {
5
5
  children: ReactNode;
6
6
  content: ReactNode;
7
7
  alignContent?: 'start' | 'center' | 'end';
8
- onOpenChange?: (isOpen: boolean) => void;
9
8
  };
10
9
 
11
- export function DropdownMenuRoot({ children, content, onOpenChange, alignContent = 'start' }: DropdownMenuRootProps) {
10
+ export function DropdownMenuRoot({ children, content, alignContent = 'start', ...delegated }: DropdownMenuRootProps) {
12
11
  return (
13
- <DropdownMenuPrimitive.Root onOpenChange={onOpenChange}>
12
+ <DropdownMenuPrimitive.Root>
14
13
  <DropdownMenuPrimitive.Trigger asChild>{children}</DropdownMenuPrimitive.Trigger>
15
- <DropdownMenuPrimitive.Content align={alignContent} sideOffset={5} className="shadow">
14
+ <DropdownMenuPrimitive.Content
15
+ align={alignContent}
16
+ sideOffset={5}
17
+ className="c-dropdown-menu-content"
18
+ {...delegated}
19
+ >
16
20
  {content}
17
21
  </DropdownMenuPrimitive.Content>
18
22
  </DropdownMenuPrimitive.Root>
@@ -0,0 +1,20 @@
1
+ .c-dropdown-menu-content {
2
+ @apply shadow;
3
+ }
4
+
5
+ .c-dropdown-menu-label {
6
+ @apply bg-elevate px-4 pt-2 font-sans text-xs font-bold text-gray-500-400;
7
+ @apply first:rounded-tl first:rounded-tr;
8
+ }
9
+
10
+ .c-dropdown-menu-item {
11
+ @apply flex h-10 cursor-pointer items-center bg-elevate px-3 font-sans text-xs font-medium text-gray-700-200;
12
+
13
+ &:hover,
14
+ &:focus,
15
+ &:focus-visible {
16
+ @apply bg-gray-50-900 outline-none;
17
+ }
18
+
19
+ @apply first:rounded-tr first:rounded-tl last:rounded-br last:rounded-bl;
20
+ }
@@ -2,6 +2,8 @@ import { DropdownMenuRoot } from './dropdown-menu-root';
2
2
  import { DropdownMenuItem } from './dropdown-menu-item';
3
3
  import { DropdownMenuLabel } from './dropdown-menu-label';
4
4
 
5
+ import './dropdown-menu.css';
6
+
5
7
  export const DropdownMenu = {
6
8
  Root: DropdownMenuRoot,
7
9
  Item: DropdownMenuItem,
@@ -1,6 +1,7 @@
1
1
  import type { StoryObj, Meta } from '@storybook/react';
2
2
  import { IconButton } from '.';
3
- import { Icon } from '../icons';
3
+ import { Card } from '../card';
4
+ import { Icon } from '../iconography';
4
5
 
5
6
  const meta: Meta<typeof IconButton> = {
6
7
  title: 'Components/IconButton',
@@ -11,17 +12,19 @@ const meta: Meta<typeof IconButton> = {
11
12
  export default meta;
12
13
  type Story = StoryObj<typeof IconButton>;
13
14
 
14
- const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
15
+ const sizes = ['xxs', 'xs', 'sm', 'md', 'lg'] as const;
15
16
 
16
17
  export const AllButton: Story = {
17
18
  name: 'All Buttons',
18
19
  render: () => {
19
20
  return (
20
- <div className="grid grid-cols-5 gap-6 justify-items-center">
21
+ <div className="grid grid-cols-5 justify-items-center gap-6">
21
22
  {sizes.map(size => (
22
- <IconButton size={size}>
23
- <Icon.Cancel width={16} height={16} />
24
- </IconButton>
23
+ <Card>
24
+ <IconButton size={size}>
25
+ <Icon.Cancel width={16} height={16} />
26
+ </IconButton>
27
+ </Card>
25
28
  ))}
26
29
  </div>
27
30
  );
@@ -0,0 +1,40 @@
1
+ .c-icon-button {
2
+ @apply flex cursor-pointer appearance-none items-center justify-center rounded-md border-none bg-transparent font-medium;
3
+
4
+ &:not(:disabled):active {
5
+ transform: scale(0.95);
6
+ }
7
+
8
+ &:disabled {
9
+ @apply scale-100 cursor-default shadow-none;
10
+ }
11
+
12
+ &:focus,
13
+ &:hover {
14
+ @apply bg-elevate shadow;
15
+ }
16
+
17
+ &:focus-visible {
18
+ @apply outline outline-1 outline-offset-1 outline-inherit;
19
+ }
20
+
21
+ &-xxs {
22
+ @apply h-5 w-5;
23
+ }
24
+
25
+ &-xs {
26
+ @apply h-6 w-6;
27
+ }
28
+
29
+ &-sm {
30
+ @apply h-9 w-9;
31
+ }
32
+
33
+ &-md {
34
+ @apply h-11 w-11;
35
+ }
36
+
37
+ &-lg {
38
+ @apply h-14 w-14;
39
+ }
40
+ }
@@ -1,31 +1,23 @@
1
1
  import { ComponentPropsWithRef, forwardRef } from 'react';
2
2
  import { cva, VariantProps } from 'class-variance-authority';
3
3
 
4
+ import './icon-button.css';
5
+
4
6
  type IconButtonStylesProps = VariantProps<typeof buttonStyles>;
5
- const buttonStyles = cva(
6
- [
7
- 'flex items-center justify-center rounded-full font-medium cursor-pointer',
8
- 'disabled:cursor-default disabled:scale-100 disabled:shadow-none',
9
- 'active:scale-95',
10
- 'focus:shadow focus:bg-slate-200',
11
- 'hover:shadow hover:bg-slate-200',
12
- 'focus-visible:outline-inherit focus-visible:outline-offset-1 focus-visible:outline focus-visible:outline-1',
13
- ],
14
- {
15
- variants: {
16
- size: {
17
- xs: 'h-8 w-8',
18
- sm: 'h-9 w-9',
19
- md: 'h-10 w-10',
20
- lg: 'h-10 w-10',
21
- xl: 'h-11 w-11',
22
- },
23
- },
24
- defaultVariants: {
25
- size: 'sm',
7
+ const buttonStyles = cva(['c-icon-button'], {
8
+ variants: {
9
+ size: {
10
+ xxs: 'c-icon-button-xxs',
11
+ xs: 'c-icon-button-xs',
12
+ sm: 'c-icon-button-sm',
13
+ md: 'c-icon-button-md',
14
+ lg: 'c-icon-button-lg',
26
15
  },
27
16
  },
28
- );
17
+ defaultVariants: {
18
+ size: 'sm',
19
+ },
20
+ });
29
21
 
30
22
  export type IconButtonProps = ComponentPropsWithRef<'button'> & IconButtonStylesProps;
31
23
 
@@ -0,0 +1,47 @@
1
+ import type { StoryObj, Meta } from '@storybook/react';
2
+ import { Icon } from '.';
3
+ import { Card } from '../card';
4
+
5
+ function Dummy() {
6
+ return <div>🤓</div>;
7
+ }
8
+
9
+ const meta: Meta<typeof Dummy> = {
10
+ title: 'Components/Icon',
11
+ component: Dummy,
12
+ };
13
+
14
+ export default meta;
15
+ type Story = StoryObj<typeof Icon>;
16
+
17
+ export const AllIcons: Story = {
18
+ name: 'All icons',
19
+ render: () => {
20
+ return (
21
+ <div>
22
+ <div className="grid grid-cols-6 justify-items-center gap-6">
23
+ {Object.keys(Icon).map(iconName => {
24
+ // @ts-expect-error
25
+ const Cmp = Icon[iconName];
26
+ const cmpString = `<Icon.${iconName} />`;
27
+ return (
28
+ <div
29
+ className="cursor-pointer text-center active:scale-95"
30
+ onClick={() => {
31
+ const type = 'text/plain';
32
+ const blob = new Blob([cmpString], { type });
33
+ navigator.clipboard.write([new ClipboardItem({ [type]: blob })]);
34
+ }}
35
+ >
36
+ <Card title={cmpString}>
37
+ <Cmp width={25} height={25} />
38
+ </Card>
39
+ <div className="mt-2 whitespace-nowrap text-xs text-gray-700-200">{cmpString}</div>
40
+ </div>
41
+ );
42
+ })}
43
+ </div>
44
+ </div>
45
+ );
46
+ },
47
+ };
File without changes
@@ -0,0 +1,59 @@
1
+ import { forwardRef, SVGProps } from 'react';
2
+
3
+ type AtomProps = SVGProps<SVGSVGElement>;
4
+
5
+ type AtomRef = SVGSVGElement;
6
+
7
+ export const Atom = forwardRef<AtomRef, AtomProps>((delegated, ref) => {
8
+ return (
9
+ <svg
10
+ ref={ref}
11
+ width="24"
12
+ height="27"
13
+ viewBox="0 0 24 27"
14
+ fill="none"
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ {...delegated}
17
+ >
18
+ <path
19
+ fill="#528693"
20
+ d="M18.068 3.103c.935 0 .938-1.5 0-1.5s-.938 1.5 0 1.5ZM5.911 2.928c.641 0 .643-1.027 0-1.027-.642 0-.643 1.027 0 1.027ZM4.294 8.862c.577 0 .578-.925 0-.925s-.578.925 0 .925ZM6.03 23.058a.39.39 0 0 0 .265-.126.413.413 0 0 0 0-.558.39.39 0 0 0-.264-.126.39.39 0 0 0-.264.126.413.413 0 0 0 0 .558.39.39 0 0 0 .264.126ZM16.93 23.13c.674 0 .675-1.078 0-1.078s-.675 1.078 0 1.078ZM18.966 17.685c.885 0 .887-1.418 0-1.418-.886 0-.886 1.418 0 1.418ZM11.6 23.619a.217.217 0 0 0 .15-.069.23.23 0 0 0 0-.315.216.216 0 0 0-.15-.068.216.216 0 0 0-.15.068.23.23 0 0 0 0 .315c.039.042.093.067.15.069ZM22.291 13.446l.043.031a.903.903 0 0 0 1.263-.344.972.972 0 0 0 0-.952.936.936 0 0 0-.34-.348.902.902 0 0 0-.924.004l-.042.03a.905.905 0 0 0-.319.33.937.937 0 0 0 0 .922c.077.136.187.25.319.329v-.002ZM11.496 26.097c3.17 0 5.738-.359 5.738-.8 0-.443-2.569-.802-5.738-.802-3.17 0-5.738.359-5.738.801 0 .442 2.569.8 5.738.8Z"
21
+ opacity=".05"
22
+ />
23
+ <path
24
+ fill="#FF99DB"
25
+ d="M11.496 16.417c1.95 0 3.531-1.629 3.531-3.638 0-2.01-1.581-3.638-3.531-3.638-1.95 0-3.531 1.629-3.531 3.638 0 2.01 1.58 3.638 3.53 3.638Z"
26
+ />
27
+ <path
28
+ fill="#528693"
29
+ d="M8.252 12.78c0-.689.207-1.36.591-1.923.385-.563.929-.99 1.557-1.222a3.153 3.153 0 0 1 1.956-.076 3.236 3.236 0 0 1 1.642 1.096 3.424 3.424 0 0 1 .285 3.834 3.278 3.278 0 0 1-1.46 1.341 3.156 3.156 0 0 1-1.945.232A3.259 3.259 0 0 1 9 14.9a3.437 3.437 0 0 1-.748-2.122.3.3 0 0 0-.088-.202.283.283 0 0 0-.398 0 .3.3 0 0 0-.088.202c0 .81.243 1.602.695 2.265a3.834 3.834 0 0 0 1.834 1.439c.74.273 1.545.305 2.304.09a3.81 3.81 0 0 0 1.934-1.293 4.03 4.03 0 0 0 .33-4.516 3.859 3.859 0 0 0-1.723-1.577 3.715 3.715 0 0 0-2.29-.268 3.85 3.85 0 0 0-2.203 1.37 4.059 4.059 0 0 0-.881 2.49.3.3 0 0 0 .088.202.283.283 0 0 0 .398 0 .3.3 0 0 0 .088-.202Z"
30
+ />
31
+ <path
32
+ fill="#528693"
33
+ d="M9.025 12.946a2.787 2.787 0 0 1 .78-1.91 2.626 2.626 0 0 1 1.854-.803.157.157 0 0 0 .113-.048.167.167 0 0 0 0-.232.157.157 0 0 0-.113-.048c-.783 0-1.533.32-2.087.891a3.093 3.093 0 0 0-.866 2.15c0 .044.017.086.047.116a.157.157 0 0 0 .225 0 .167.167 0 0 0 .047-.116ZM8.972 13.854c.033 0 .066-.01.094-.029a.17.17 0 0 0 .062-.079.137.137 0 0 0 .014-.068l-.006-.046a.176.176 0 0 0-.044-.078l-.034-.027a.167.167 0 0 0-.086-.025.174.174 0 0 0-.12.053.183.183 0 0 0-.05.123l.005.046c.008.03.024.056.044.078l.035.028a.166.166 0 0 0 .086.023v.001ZM12.136 10.204v.004a.112.112 0 0 0 .026.051c.01.016.024.03.04.039l.036.015a.145.145 0 0 0 .077 0l.034-.015a.112.112 0 0 0 .041-.039.076.076 0 0 0 .019-.033.118.118 0 0 0 .012-.057l-.005-.04-.014-.035a.113.113 0 0 0-.038-.042.107.107 0 0 0-.05-.027.109.109 0 0 0-.057-.003.104.104 0 0 0-.054.018l-.03.024a.148.148 0 0 0-.037.065v.004a.136.136 0 0 0 0 .07Z"
34
+ />
35
+ <path
36
+ fill="#528693"
37
+ d="M6.023 12.779a23.383 23.383 0 0 1 1.024-7.096c.517-1.608 1.283-3.336 2.601-4.417.989-.81 2.233-.962 3.322-.27 1.369.87 2.196 2.529 2.747 4.027a21.916 21.916 0 0 1 1.234 6.778 24.482 24.482 0 0 1-.779 7.302c-.471 1.725-1.178 3.543-2.437 4.827-.881.898-2.097 1.4-3.294.86-1.407-.632-2.294-2.18-2.89-3.56-.883-2.039-1.303-4.3-1.46-6.515a27.856 27.856 0 0 1-.068-1.936.278.278 0 0 0-.082-.187.262.262 0 0 0-.369 0 .278.278 0 0 0-.081.187c.004 2.518.314 5.078 1.117 7.465.567 1.685 1.403 3.46 2.818 4.559a3.229 3.229 0 0 0 3.73.283c1.471-.883 2.37-2.582 2.98-4.158.88-2.267 1.261-4.74 1.347-7.17a24.885 24.885 0 0 0-.84-7.606c-.509-1.799-1.28-3.699-2.628-5.008C12.998.158 11.617-.328 10.28.247 8.781.892 7.8 2.46 7.15 3.92c-.951 2.138-1.408 4.494-1.582 6.829-.05.675-.074 1.352-.075 2.03.002.07.032.138.081.187a.262.262 0 0 0 .369 0 .278.278 0 0 0 .081-.187Z"
38
+ />
39
+ <path
40
+ fill="#528693"
41
+ d="M8.64 7.969c2.066-1.293 4.315-2.336 6.686-2.86 1.61-.357 3.548-.57 5.086.197.576.27 1.048.73 1.34 1.309.24.543.327 1.145.25 1.737-.164 1.605-1.1 3.108-2.06 4.333a21.318 21.318 0 0 1-4.85 4.42 22.562 22.562 0 0 1-6.661 3.155c-1.718.468-3.69.777-5.416.176-1.207-.422-2.038-1.42-2.049-2.758-.012-1.547.808-3.03 1.665-4.243a19.773 19.773 0 0 1 4.556-4.482c.474-.345.958-.673 1.454-.984.29-.184.024-.657-.269-.473a22.835 22.835 0 0 0-5.39 4.61C1.87 13.438.81 15.035.512 16.801c-.235 1.395.136 2.779 1.293 3.62 1.41 1.023 3.364.982 4.994.743 2.442-.36 4.8-1.342 6.944-2.575a23.78 23.78 0 0 0 5.757-4.55c1.223-1.345 2.372-2.932 2.86-4.732.359-1.328.254-2.821-.758-3.823-1.204-1.192-3.091-1.326-4.666-1.182-2.378.218-4.688 1.076-6.806 2.183-.599.313-1.183.651-1.757 1.01-.293.183-.026.657.268.473Z"
42
+ />
43
+ <path
44
+ fill="#528693"
45
+ d="M14.62 7.496c-2.17-1.357-4.551-2.454-7.05-2.966-1.725-.353-3.736-.512-5.352.35a3.343 3.343 0 0 0-1.39 1.404 3.481 3.481 0 0 0-.38 1.967c.135 1.715 1.061 3.29 2.067 4.615a21.487 21.487 0 0 0 5.078 4.687 22.835 22.835 0 0 0 7.03 3.29c1.783.463 3.854.752 5.624.074 1.321-.507 2.24-1.618 2.306-3.095.074-1.64-.756-3.25-1.652-4.546-1.285-1.86-2.956-3.421-4.755-4.742a24.734 24.734 0 0 0-1.526-1.037c-.293-.185-.56.289-.269.473a22.565 22.565 0 0 1 5.134 4.347c1.078 1.26 2.095 2.754 2.443 4.424.258 1.237-.018 2.535-1.092 3.266-1.361.927-3.228.846-4.768.588-2.321-.389-4.55-1.322-6.593-2.502a23.435 23.435 0 0 1-5.472-4.295c-1.187-1.278-2.314-2.784-2.819-4.501-.351-1.197-.326-2.555.618-3.46C2.94 4.75 4.755 4.716 6.204 4.867c2.261.235 4.469 1.078 6.48 2.139.567.3 1.123.623 1.668.964.06.032.131.04.197.02a.267.267 0 0 0 .155-.126.282.282 0 0 0-.084-.367Z"
46
+ />
47
+ <path
48
+ fill="#fff"
49
+ d="M11.963 14.285h.003c.2-.04.384-.14.53-.287.175-.111.317-.27.41-.46l.159-.388c.065-.21.075-.434.028-.649a1.234 1.234 0 0 0-.188-.604l-.246-.329-.32-.254a1.152 1.152 0 0 0-.585-.193 1.164 1.164 0 0 0-.63.03l-.377.163c-.343.228-.6.571-.725.971l-.056.433c-.01.217.037.433.136.626.036.136.106.26.203.359.11.176.263.32.442.418l.377.164c.275.078.564.078.84 0h-.001Z"
50
+ />
51
+ <path
52
+ fill="#FF99DB"
53
+ d="m11.172 13.1.017.019.105.083c.057.038.124.06.192.063a.253.253 0 0 0 .138 0 .379.379 0 0 0 .191-.063l.105-.083.08-.108a.403.403 0 0 0 .062-.199.414.414 0 0 0-.009-.212l-.002-.026a.548.548 0 0 0-.135-.24.524.524 0 0 0-.232-.139l-.14-.019a.513.513 0 0 0-.265.074.605.605 0 0 0-.243.324.562.562 0 0 0 .136.527Z"
54
+ />
55
+ </svg>
56
+ );
57
+ });
58
+
59
+ Atom.displayName = 'AtomIcon';
File without changes
@@ -0,0 +1,24 @@
1
+ import { forwardRef, SVGProps } from 'react';
2
+
3
+ type CopyProps = SVGProps<SVGSVGElement>;
4
+
5
+ type CopyRef = SVGSVGElement;
6
+
7
+ export const Copy = forwardRef<CopyRef, CopyProps>((delegated, ref) => {
8
+ return (
9
+ <svg
10
+ ref={ref}
11
+ width="14"
12
+ height="16"
13
+ viewBox="0 0 14 16"
14
+ fill="none"
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ {...delegated}
17
+ >
18
+ <rect x=".5" y="3.5" width="9" height="12" rx="2.5" fill="#EAEBEE" stroke="#80878D" strokeDasharray="3 2" />
19
+ <rect x="4.5" y=".5" width="9" height="12" rx="2.5" fill="#EAEBEE" stroke="#80878D" />
20
+ </svg>
21
+ );
22
+ });
23
+
24
+ Copy.displayName = 'CopyIcon';