@clicktap/ui 0.14.11 → 0.14.13

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 (191) hide show
  1. package/components/Accordion/Accordion.tsx +82 -0
  2. package/components/Accordion/index.ts +3 -0
  3. package/components/Avatar/Avatar.stories.tsx +99 -0
  4. package/components/Avatar/Avatar.tsx +120 -0
  5. package/components/Avatar/Avatar.types.ts +3 -0
  6. package/components/Avatar/AvatarGroup/AvatarGroup.tsx +32 -0
  7. package/components/Avatar/AvatarGroup/AvatarGroup.types.ts +8 -0
  8. package/components/Avatar/index.ts +4 -0
  9. package/components/Badge/Badge.stories.tsx +72 -0
  10. package/components/Badge/Badge.tsx +169 -0
  11. package/components/Badge/Badge.types.ts +3 -0
  12. package/components/Badge/index.ts +2 -0
  13. package/components/Breadcrumbs/BreadcrumbEllipsis.tsx +47 -0
  14. package/components/Breadcrumbs/BreadcrumbEllipsis.types.ts +5 -0
  15. package/components/Breadcrumbs/BreadcrumbItem.tsx +23 -0
  16. package/components/Breadcrumbs/BreadcrumbItem.types.ts +3 -0
  17. package/components/Breadcrumbs/BreadcrumbLink.tsx +30 -0
  18. package/components/Breadcrumbs/BreadcrumbLink.types.ts +3 -0
  19. package/components/Breadcrumbs/BreadcrumbSeparator.tsx +41 -0
  20. package/components/Breadcrumbs/BreadcrumbSeparator.types.ts +9 -0
  21. package/components/Breadcrumbs/Breadcrumbs.tsx +28 -0
  22. package/components/Breadcrumbs/Breadcrumbs.types.ts +6 -0
  23. package/components/Breadcrumbs/index.ts +10 -0
  24. package/components/Button/Button.tsx +72 -0
  25. package/components/Button/Button.types.ts +7 -0
  26. package/components/Button/index.ts +2 -0
  27. package/components/Card/Card.tsx +15 -0
  28. package/components/Card/Card.types.ts +3 -0
  29. package/components/Card/index.ts +2 -0
  30. package/components/Checkbox/Checkbox.tsx +122 -0
  31. package/components/Checkbox/Checkbox.types.ts +15 -0
  32. package/components/Checkbox/index.ts +2 -0
  33. package/components/Collapsible/Collapsible.tsx +34 -0
  34. package/components/Collapsible/Collapsible.types.ts +5 -0
  35. package/components/Collapsible/CollapsibleTrigger.tsx +57 -0
  36. package/components/Collapsible/CollapsibleTrigger.types.ts +14 -0
  37. package/components/Collapsible/index.ts +10 -0
  38. package/components/Container/Container.tsx +26 -0
  39. package/components/Container/Container.types.ts +3 -0
  40. package/components/Container/index.ts +2 -0
  41. package/components/ContextMenu/ContextMenu.tsx +74 -0
  42. package/components/ContextMenu/ContextMenu.types.ts +17 -0
  43. package/components/ContextMenu/index.ts +2 -0
  44. package/components/CreditCardExpirationInput/CreditCardExpirationInput.tsx +115 -0
  45. package/components/CreditCardExpirationInput/CreditCardExpirationInput.types.ts +10 -0
  46. package/components/CreditCardExpirationInput/index.ts +2 -0
  47. package/components/CreditCardInput/CreditCardInput.tsx +147 -0
  48. package/components/CreditCardInput/CreditCardInput.types.ts +12 -0
  49. package/components/CreditCardInput/index.ts +2 -0
  50. package/components/DateInput/DateInput.tsx +81 -0
  51. package/components/DateInput/DateInput.types.ts +15 -0
  52. package/components/DateInput/index.ts +2 -0
  53. package/components/DateTimeFormat/DateTimeFormat.tsx +16 -0
  54. package/components/DateTimeFormat/DateTimeFormat.types.ts +7 -0
  55. package/components/DateTimeFormat/index.ts +2 -0
  56. package/components/Dialog/Dialog.tsx +65 -0
  57. package/components/Dialog/Dialog.types.ts +9 -0
  58. package/components/Dialog/index.ts +2 -0
  59. package/components/DialogTrigger/DialogTrigger.tsx +45 -0
  60. package/components/DialogTrigger/DialogTrigger.types.ts +6 -0
  61. package/components/DialogTrigger/index.ts +5 -0
  62. package/components/Divider/Divider.stories.tsx +37 -0
  63. package/components/Divider/Divider.tsx +34 -0
  64. package/components/Divider/Divider.types.ts +5 -0
  65. package/components/Divider/index.ts +2 -0
  66. package/components/DobInput/DobInput.tsx +120 -0
  67. package/components/DobInput/index.ts +2 -0
  68. package/components/Drawer/Drawer.tsx +126 -0
  69. package/components/Drawer/Drawer.types.ts +11 -0
  70. package/components/Drawer/index.ts +2 -0
  71. package/components/Icon/Account.tsx +50 -0
  72. package/components/Icon/Cart.tsx +43 -0
  73. package/components/Icon/Checkmark.tsx +34 -0
  74. package/components/Icon/Cross.tsx +36 -0
  75. package/components/Icon/DownArrow.tsx +23 -0
  76. package/components/Icon/Hamburger.tsx +23 -0
  77. package/components/Icon/Icon.types.ts +8 -0
  78. package/components/Icon/LinkArrow.tsx +32 -0
  79. package/components/Icon/Minus.tsx +20 -0
  80. package/components/Icon/Plus.tsx +20 -0
  81. package/components/Icon/Search.tsx +36 -0
  82. package/components/Icon/Trash.tsx +27 -0
  83. package/components/Icon/Verified.tsx +20 -0
  84. package/components/Icon/index.ts +14 -0
  85. package/components/Image/Image.tsx +32 -0
  86. package/components/Image/index.ts +2 -0
  87. package/components/Input/Input.tsx +109 -0
  88. package/components/Input/Input.types.ts +17 -0
  89. package/components/Input/index.ts +2 -0
  90. package/components/Link/Link.stories.tsx +96 -0
  91. package/components/Link/Link.tsx +34 -0
  92. package/components/Link/Link.types.ts +3 -0
  93. package/components/Link/index.ts +2 -0
  94. package/components/Loader/CircularEasing.tsx +66 -0
  95. package/components/Loader/CircularEasing.types.ts +8 -0
  96. package/components/Loader/Pulse.tsx +45 -0
  97. package/components/Loader/Pulse.types.ts +5 -0
  98. package/components/Loader/index.ts +4 -0
  99. package/components/Menu/ContextMenu.tsx +83 -0
  100. package/components/Menu/Menu.tsx +143 -0
  101. package/components/Menu/Menu.types.ts +44 -0
  102. package/components/Menu/index.ts +4 -0
  103. package/components/Meter/Meter.stories.tsx +111 -0
  104. package/components/Meter/Meter.tsx +68 -0
  105. package/components/Meter/Meter.types.ts +10 -0
  106. package/components/Meter/index.ts +2 -0
  107. package/components/Modal/Modal.tsx +16 -0
  108. package/components/Modal/Modal.types.ts +6 -0
  109. package/components/Modal/index.ts +2 -0
  110. package/components/ModalOverlay/ModalOverlay.tsx +121 -0
  111. package/components/ModalOverlay/ModalOverlay.types.ts +18 -0
  112. package/components/ModalOverlay/index.ts +2 -0
  113. package/components/NumberFormat/NumberFormat.tsx +19 -0
  114. package/components/NumberFormat/NumberFormat.types.ts +8 -0
  115. package/components/NumberFormat/index.ts +2 -0
  116. package/components/NumberInput/NumberInput.tsx +164 -0
  117. package/components/NumberInput/NumberInput.types.ts +22 -0
  118. package/components/NumberInput/index.ts +2 -0
  119. package/components/NumberTicker/DigitResolver.tsx +119 -0
  120. package/components/NumberTicker/DigitResolver.types.ts +18 -0
  121. package/components/NumberTicker/NumberTicker.tsx +56 -0
  122. package/components/NumberTicker/NumberTicker.types.ts +96 -0
  123. package/components/NumberTicker/hooks/useColumnTransition.ts +36 -0
  124. package/components/NumberTicker/hooks/useNumberDelta.ts +19 -0
  125. package/components/NumberTicker/hooks/useNumberTicker.ts +36 -0
  126. package/components/NumberTicker/index.ts +10 -0
  127. package/components/Pagination/Pagination.tsx +44 -0
  128. package/components/Pagination/index.ts +2 -0
  129. package/components/PasswordCheck/PasswordCheck.tsx +59 -0
  130. package/components/PasswordCheck/PasswordCheck.types.ts +4 -0
  131. package/components/PasswordCheck/PasswordCheck.utils.ts +47 -0
  132. package/components/PasswordCheck/index.ts +2 -0
  133. package/components/PhoneInput/PhoneInput.tsx +191 -0
  134. package/components/PhoneInput/index.ts +2 -0
  135. package/components/PinInput/PinInput.tsx +314 -0
  136. package/components/PinInput/PinInput.types.ts +21 -0
  137. package/components/PinInput/index.ts +2 -0
  138. package/components/Progressbar/CircularProgressbar.tsx +71 -0
  139. package/components/Progressbar/CircularProgressbar.types.ts +10 -0
  140. package/components/Progressbar/LinearProgressbar.tsx +75 -0
  141. package/components/Progressbar/LinearProgressbar.types.ts +11 -0
  142. package/components/Progressbar/index.ts +4 -0
  143. package/components/Radio/Radio.tsx +88 -0
  144. package/components/Radio/Radio.types.ts +16 -0
  145. package/components/Radio/index.ts +2 -0
  146. package/components/RadioGroup/RadioGroup.tsx +49 -0
  147. package/components/RadioGroup/RadioGroup.types.ts +7 -0
  148. package/components/RadioGroup/index.ts +2 -0
  149. package/components/Select/Option.tsx +32 -0
  150. package/components/Select/Option.types.ts +3 -0
  151. package/components/Select/Select.tsx +253 -0
  152. package/components/Select/Select.types.ts +42 -0
  153. package/components/Select/index.ts +8 -0
  154. package/components/Skeleton/Skeleton.tsx +15 -0
  155. package/components/Skeleton/Skeleton.types.ts +3 -0
  156. package/components/Skeleton/index.ts +2 -0
  157. package/components/Slider/Slider.tsx +110 -0
  158. package/components/Slider/Slider.types.ts +11 -0
  159. package/components/Slider/index.ts +2 -0
  160. package/components/Switch/Switch.tsx +63 -0
  161. package/components/Switch/Switch.types.ts +8 -0
  162. package/components/Switch/index.ts +2 -0
  163. package/components/Table/Table.tsx +52 -0
  164. package/components/Table/Table.types.ts +22 -0
  165. package/components/Table/index.ts +2 -0
  166. package/components/Tabs/Tab.tsx +118 -0
  167. package/components/Tabs/Tab.types.ts +10 -0
  168. package/components/Tabs/TabList.tsx +51 -0
  169. package/components/Tabs/TabList.types.ts +12 -0
  170. package/components/Tabs/TabPanel.tsx +19 -0
  171. package/components/Tabs/TabPanel.types.ts +3 -0
  172. package/components/Tabs/Tabs.context.tsx +9 -0
  173. package/components/Tabs/Tabs.tsx +39 -0
  174. package/components/Tabs/Tabs.types.ts +3 -0
  175. package/components/Tabs/index.ts +9 -0
  176. package/components/TimeInput/TimeInput.stories.tsx +125 -0
  177. package/components/TimeInput/TimeInput.tsx +81 -0
  178. package/components/TimeInput/TimeInput.types.ts +15 -0
  179. package/components/TimeInput/index.ts +2 -0
  180. package/components/ToggleButton/ToggleButton.stories.tsx +89 -0
  181. package/components/ToggleButton/ToggleButton.tsx +69 -0
  182. package/components/ToggleButton/ToggleButton.types.ts +6 -0
  183. package/components/ToggleButton/index.ts +2 -0
  184. package/components/Tooltip/Tooltip.tsx +59 -0
  185. package/components/Tooltip/Tooltip.types.ts +3 -0
  186. package/components/Tooltip/index.ts +2 -0
  187. package/components/UploadImage/UploadImage.tsx +206 -0
  188. package/components/UploadImage/UploadImage.types.ts +15 -0
  189. package/components/UploadImage/index.ts +2 -0
  190. package/package.json +3 -2
  191. package/tailwind.config.js +6 -0
@@ -0,0 +1,82 @@
1
+ 'use client';
2
+
3
+ import { Accordion as NextUiAccordion } from '@nextui-org/accordion';
4
+ import type { AccordionProps } from '@nextui-org/accordion';
5
+ import { cn } from '../../utils/cn';
6
+ import { DownArrow } from '../Icon/DownArrow';
7
+
8
+ export function Accordion({
9
+ children,
10
+ variant,
11
+ isCompact,
12
+ className,
13
+ itemClasses,
14
+ ...props
15
+ }: AccordionProps) {
16
+ return (
17
+ <NextUiAccordion
18
+ variant={variant}
19
+ isCompact={isCompact}
20
+ dividerProps={{
21
+ className: cn(
22
+ 'my-2 border-solid border-slate-200',
23
+ variant === 'shadow' && 'border-slate-300'
24
+ ),
25
+ }}
26
+ className={cn(
27
+ 'px-0',
28
+ variant === 'bordered' && [
29
+ 'px-4 py-4 rounded-xl border-2 border-slate-200',
30
+ ],
31
+ variant === 'shadow' && [
32
+ 'px-4 py-4 rounded-xl bg-slate-100 shadow-slate-200 border border-slate-200',
33
+ ],
34
+ className
35
+ )}
36
+ itemClasses={{
37
+ base: cn(
38
+ 'w-full py-2',
39
+ 'data-[disabled="true"]:pointer-events-none data-[disabled="true"]:opacity-50',
40
+ variant === 'bordered' && ['rounded-xl py-0'],
41
+ variant === 'splitted' && [
42
+ 'flex flex-col bg-slate-100 rounded-xl border border-slate-200',
43
+ ],
44
+ isCompact && 'py-0',
45
+ itemClasses?.base
46
+ ),
47
+ trigger: cn(
48
+ 'w-full h-full flex items-center gap-3 py-0 appearance-none cursor-pointer select-none',
49
+ 'data-[focus-visible="true"]:outline-2 data-[focus-visible="true"]:outline data-[focus-visible="true"]:outline-slate-100',
50
+ 'bg-transparent text-inherit',
51
+ isCompact && ['py-2'],
52
+ itemClasses?.trigger
53
+ ),
54
+ title: cn(
55
+ 'text-xl font-semibold',
56
+ isCompact && 'text-base',
57
+ itemClasses?.title
58
+ ),
59
+ subtitle: cn(
60
+ 'text-base',
61
+ isCompact && 'text-sm',
62
+ itemClasses?.subtitle
63
+ ),
64
+ titleWrapper: cn('text-left', itemClasses?.titleWrapper),
65
+ startContent: cn('shrink-0', itemClasses?.startContent),
66
+ content: cn([isCompact ? 'py-1' : 'py-2'], itemClasses?.content),
67
+ indicator: itemClasses?.indicator,
68
+ heading: itemClasses?.heading,
69
+ }}
70
+ // eslint-disable-next-line react/jsx-props-no-spreading
71
+ {...props}
72
+ >
73
+ {children}
74
+ </NextUiAccordion>
75
+ );
76
+ }
77
+
78
+ export default Accordion;
79
+
80
+ export function AccordionItemArrow() {
81
+ return <DownArrow className="w-4 h-4" />;
82
+ }
@@ -0,0 +1,3 @@
1
+ export { Accordion, AccordionItemArrow } from './Accordion';
2
+ export { AccordionItem } from '@nextui-org/accordion';
3
+ export type { AccordionProps } from '@nextui-org/accordion';
@@ -0,0 +1,99 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { Avatar } from './Avatar';
4
+ import type { AvatarProps } from './Avatar.types';
5
+ import { AvatarGroup } from './AvatarGroup/AvatarGroup';
6
+ import type { AvatarGroupProps } from './AvatarGroup/AvatarGroup.types';
7
+
8
+ function Layout({ children }: { children: ReactNode }) {
9
+ return children;
10
+ }
11
+
12
+ function AvatarExample(props: AvatarProps) {
13
+ return (
14
+ <Layout>
15
+ {/* eslint-disable-next-line react/jsx-props-no-spreading */}
16
+ <Avatar {...props} />
17
+ </Layout>
18
+ );
19
+ }
20
+
21
+ function AvatarGroupExample(props: AvatarGroupProps) {
22
+ return (
23
+ <Layout>
24
+ {/* eslint-disable-next-line react/jsx-props-no-spreading */}
25
+ <AvatarGroup {...props}>
26
+ <Avatar src="https://letsenhance.io/static/8f5e523ee6b2479e26ecc91b9c25261e/1015f/MainAfter.jpg" />
27
+ <Avatar src="https://i.pravatar.cc/150?u=a042581f4e29026704d" />
28
+ <Avatar src="https://i.pravatar.cc/150?u=a04258114e29026702d" />
29
+ <Avatar src="https://letsenhance.io/static/8f5e523ee6b2479e26ecc91b9c25261e/1015f/MainAfter.jpg" />
30
+ <Avatar src="https://i.pravatar.cc/150?u=a042581f4e29026704d" />
31
+ <Avatar src="https://i.pravatar.cc/150?u=a04258114e29026702d" />
32
+ </AvatarGroup>
33
+ </Layout>
34
+ );
35
+ }
36
+
37
+ type Story = StoryObj<typeof Avatar>;
38
+ type StoryGroup = StoryObj<typeof AvatarGroup>;
39
+
40
+ const meta: Meta<typeof Layout> = {
41
+ component: Layout,
42
+ };
43
+
44
+ export default meta;
45
+
46
+ export const AvatarComponent: Story = {
47
+ name: 'Avatar',
48
+ render: AvatarExample,
49
+ argTypes: {
50
+ src: {
51
+ control: 'text',
52
+ },
53
+ name: {
54
+ control: 'text',
55
+ },
56
+ size: {
57
+ options: ['sm', 'md', 'lg'],
58
+ control: 'radio',
59
+ },
60
+ showFallback: {
61
+ control: 'boolean',
62
+ },
63
+ radius: {
64
+ options: ['sm', 'md', 'lg', 'none', 'full'],
65
+ control: 'radio',
66
+ },
67
+ isBordered: {
68
+ control: 'boolean',
69
+ },
70
+ isDisabled: {
71
+ control: 'boolean',
72
+ },
73
+ isFocusable: {
74
+ control: 'boolean',
75
+ },
76
+ },
77
+ args: {
78
+ src: 'https://letsenhance.io/static/8f5e523ee6b2479e26ecc91b9c25261e/1015f/MainAfter.jpg',
79
+ name: 'Avatar',
80
+ size: 'md',
81
+ showFallback: false,
82
+ radius: 'full',
83
+ isBordered: false,
84
+ isDisabled: false,
85
+ isFocusable: false,
86
+ },
87
+ };
88
+ export const AvatarGroupComponent: StoryGroup = {
89
+ name: 'Avatar Group',
90
+ render: AvatarGroupExample,
91
+ argTypes: {
92
+ isGrid: {
93
+ control: 'boolean',
94
+ },
95
+ },
96
+ args: {
97
+ isGrid: false,
98
+ },
99
+ };
@@ -0,0 +1,120 @@
1
+ 'use client';
2
+
3
+ import { useAvatarGroupContext, Avatar as UiAvatar } from '@nextui-org/avatar';
4
+ import { cn } from '../../utils/cn';
5
+ import type { AvatarProps } from './Avatar.types';
6
+
7
+ export function Avatar({
8
+ icon,
9
+ className,
10
+ isDisabled,
11
+ size,
12
+ classNames,
13
+ isBordered,
14
+ radius,
15
+ ...props
16
+ }: AvatarProps) {
17
+ const avatarGroupContext = useAvatarGroupContext();
18
+ return (
19
+ <div
20
+ className={cn(
21
+ 'group',
22
+ 'z-10',
23
+ 'first:ms-0',
24
+ !avatarGroupContext?.isGrid && !!avatarGroupContext && '-ms-2',
25
+ className
26
+ )}
27
+ >
28
+ <UiAvatar
29
+ // eslint-disable-next-line react/jsx-props-no-spreading
30
+ {...props}
31
+ isDisabled={isDisabled}
32
+ size={size}
33
+ radius={radius}
34
+ isBordered={isBordered}
35
+ className={cn(
36
+ !avatarGroupContext?.isGrid &&
37
+ !!avatarGroupContext &&
38
+ 'group-hover:-translate-y-3.5',
39
+ 'transition-transform duration-300 ease-in-out',
40
+ 'bg-slate-100',
41
+ 'flex items-center justify-center',
42
+ 'relative',
43
+ 'z-10',
44
+ 'overflow-hidden',
45
+ isDisabled ? 'opacity-50' : 'opacity-100',
46
+ [
47
+ size === 'sm' && 'h-8',
48
+ size === 'md' && 'h-10',
49
+ size === 'lg' && 'h-12',
50
+ size === 'sm' && 'w-8',
51
+ size === 'md' && 'w-10',
52
+ size === 'lg' && 'w-12',
53
+ ],
54
+ [
55
+ radius === 'full' && 'rounded-full',
56
+ radius === 'lg' && 'rounded-2xl',
57
+ radius === 'md' && 'rounded-xl',
58
+ radius === 'sm' && 'rounded-lg',
59
+ radius === 'none' && 'rounded-none',
60
+ ],
61
+ isBordered &&
62
+ 'shadow-[#fff_0px_0px_0px_2px,_#f1f5f9_0px_0px_0px_4px,_#00000000_0px_0px_0px_0px]',
63
+ classNames?.base
64
+ )}
65
+ classNames={{
66
+ icon: cn(
67
+ 'data-[loaded=true]:opacity-100 opacity-0',
68
+ 'absolute',
69
+ 'w-full',
70
+ 'h-full',
71
+ 'overflow-hidden',
72
+ 'object-cover',
73
+ 'object-center',
74
+ 'transition-opacity ease-in-out duration-500',
75
+ classNames?.icon
76
+ ),
77
+ name: cn(
78
+ 'flex items-center justify-center',
79
+ 'absolute top-1/2 left-1/2',
80
+ '-translate-x-1/2 -translate-y-1/2',
81
+ 'text-xs text-center',
82
+ 'max-w-full',
83
+ 'overflow-hidden',
84
+ classNames?.name
85
+ ),
86
+ fallback: cn(
87
+ 'flex items-center justify-center',
88
+ 'absolute top-1/2 left-1/2',
89
+ '-translate-x-1/2 -translate-y-1/2',
90
+ 'text-xs text-center',
91
+ 'max-w-full',
92
+ 'overflow-hidden',
93
+ classNames?.fallback
94
+ ),
95
+ }}
96
+ icon={
97
+ icon || (
98
+ <svg
99
+ width="24"
100
+ height="24"
101
+ viewBox="0 0 24 24"
102
+ fill="none"
103
+ xmlns="http://www.w3.org/2000/svg"
104
+ >
105
+ <path
106
+ d="M20 21C20 19.6044 20 18.9067 19.8278 18.3389C19.44 17.0605 18.4395 16.06 17.1611 15.6722C16.5933 15.5 15.8956 15.5 14.5 15.5H9.5C8.10444 15.5 7.40665 15.5 6.83886 15.6722C5.56045 16.06 4.56004 17.0605 4.17224 18.3389C4 18.9067 4 19.6044 4 21M16.5 7.5C16.5 9.98528 14.4853 12 12 12C9.51472 12 7.5 9.98528 7.5 7.5C7.5 5.01472 9.51472 3 12 3C14.4853 3 16.5 5.01472 16.5 7.5Z"
107
+ stroke="black"
108
+ strokeWidth="2"
109
+ strokeLinecap="round"
110
+ strokeLinejoin="round"
111
+ />
112
+ </svg>
113
+ )
114
+ }
115
+ />
116
+ </div>
117
+ );
118
+ }
119
+
120
+ export default Avatar;
@@ -0,0 +1,3 @@
1
+ import type { AvatarProps as NextAvatarProps } from '@nextui-org/avatar';
2
+
3
+ export type AvatarProps = Omit<NextAvatarProps, 'color'>;
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+
3
+ import { AvatarGroup as UIAvatarGroup } from '@nextui-org/avatar';
4
+ import type { PropsWithChildren } from 'react';
5
+ import { cn } from '../../../utils/cn';
6
+ import type { AvatarGroupProps } from './AvatarGroup.types';
7
+
8
+ export function AvatarGroup({
9
+ children,
10
+ isGrid,
11
+ renderCount,
12
+ className,
13
+ }: PropsWithChildren<AvatarGroupProps>) {
14
+ return (
15
+ <UIAvatarGroup
16
+ isGrid={isGrid}
17
+ max={0}
18
+ renderCount={renderCount ?? undefined}
19
+ className={cn(
20
+ isGrid ? 'inline-grid' : 'flex',
21
+ isGrid ? 'gap-3' : 'gap-0',
22
+ 'grid-cols-4',
23
+ 'items-center',
24
+ className
25
+ )}
26
+ >
27
+ {children}
28
+ </UIAvatarGroup>
29
+ );
30
+ }
31
+
32
+ export default AvatarGroup;
@@ -0,0 +1,8 @@
1
+ import type { AvatarGroupProps as NextAvatarGroupProps } from '@nextui-org/avatar';
2
+
3
+ export type AvatarGroupProps = Pick<
4
+ NextAvatarGroupProps,
5
+ 'isGrid' | 'renderCount'
6
+ > & {
7
+ className?: string;
8
+ };
@@ -0,0 +1,4 @@
1
+ export { Avatar } from './Avatar';
2
+ export { AvatarGroup } from './AvatarGroup/AvatarGroup';
3
+ export type { AvatarProps } from './Avatar.types';
4
+ export type { AvatarGroupProps } from './AvatarGroup/AvatarGroup.types';
@@ -0,0 +1,72 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Badge } from './Badge';
3
+ import type { BadgeProps } from './Badge.types';
4
+ import { Avatar } from '../Avatar/Avatar';
5
+
6
+ type Story = StoryObj<typeof Badge>;
7
+
8
+ function Component(props: BadgeProps) {
9
+ return (
10
+ <Badge {...props}>
11
+ <Avatar name="Regular" radius="md" />
12
+ </Badge>
13
+ );
14
+ }
15
+
16
+ const meta: Meta<typeof Component> = {
17
+ component: Component,
18
+ };
19
+
20
+ export default meta;
21
+
22
+ export const Example: Story = {
23
+ render: Component,
24
+ argTypes: {
25
+ content: {
26
+ control: 'text',
27
+ },
28
+ variant: {
29
+ options: ['shadow', 'flat', 'solid', 'faded'],
30
+ control: 'radio',
31
+ },
32
+ size: {
33
+ options: ['sm', 'md', 'lg'],
34
+ control: 'radio',
35
+ },
36
+ placement: {
37
+ options: ['top-right', 'bottom-right', 'bottom-left', 'top-left'],
38
+ control: 'radio',
39
+ },
40
+ shape: {
41
+ options: ['circle', 'rectangle'],
42
+ control: 'radio',
43
+ },
44
+ isInvisible: {
45
+ control: 'boolean',
46
+ },
47
+ isOneChar: {
48
+ control: 'boolean',
49
+ },
50
+ isDot: {
51
+ control: 'boolean',
52
+ },
53
+ disableAnimation: {
54
+ control: 'boolean',
55
+ },
56
+ showOutline: {
57
+ control: 'boolean',
58
+ },
59
+ },
60
+ args: {
61
+ content: '5',
62
+ variant: 'solid',
63
+ size: 'md',
64
+ placement: 'top-right',
65
+ shape: 'rectangle',
66
+ isInvisible: false,
67
+ isOneChar: false,
68
+ isDot: false,
69
+ disableAnimation: false,
70
+ showOutline: true,
71
+ },
72
+ };
@@ -0,0 +1,169 @@
1
+ 'use client';
2
+
3
+ import { useId } from 'react';
4
+ import { AnimatePresence, motion } from 'framer-motion';
5
+ import { Badge as NextUIBadge } from '@nextui-org/badge';
6
+ import { cn } from '../../utils/cn';
7
+ import type { BadgeProps } from './Badge.types';
8
+
9
+ const animationVariants = {
10
+ hidden: {
11
+ opacity: 0,
12
+ transform: 'scale(0)',
13
+ },
14
+ show: {
15
+ opacity: 1,
16
+ transform: 'scale(1)',
17
+ },
18
+ };
19
+
20
+ export function Badge({
21
+ children,
22
+ isInvisible,
23
+ disableAnimation,
24
+ placement = 'top-right',
25
+ shape = 'rectangle',
26
+ className,
27
+ classNames,
28
+ showOutline = false,
29
+ content,
30
+ isDot,
31
+ isOneChar,
32
+ size = 'md',
33
+ variant = 'solid',
34
+ ...props
35
+ }: BadgeProps) {
36
+ const id = useId();
37
+ const transition = disableAnimation
38
+ ? { duration: 0 }
39
+ : { type: 'spring', bounce: 0.3 };
40
+
41
+ const isOneCharContent = String(content)?.length === 1 || isOneChar;
42
+
43
+ const textVariants = {
44
+ sm: 'text-xs',
45
+ md: 'text-sm',
46
+ lg: 'text-sm',
47
+ };
48
+
49
+ const oneCharSizeVariants = {
50
+ sm: 'w-4 h-4',
51
+ md: 'w-5 h-5',
52
+ lg: 'w-6 h-6',
53
+ };
54
+
55
+ const sizeVariants = {
56
+ sm: 'min-w-4 h-4',
57
+ md: 'min-w-5 h-5',
58
+ lg: 'min-w-6 h-6',
59
+ };
60
+
61
+ const sizeVariant = isOneCharContent
62
+ ? oneCharSizeVariants[size]
63
+ : sizeVariants[size];
64
+
65
+ return (
66
+ <NextUIBadge
67
+ // eslint-disable-next-line react/jsx-props-no-spreading
68
+ {...props}
69
+ size={size}
70
+ variant={variant}
71
+ isInvisible={isInvisible}
72
+ isDot={isDot}
73
+ classNames={{
74
+ base: cn('relative', 'inline-flex shrink-0', classNames?.base),
75
+ badge: cn(
76
+ 'p-0',
77
+ 'border-0',
78
+ 'absolute z-10',
79
+ [
80
+ placement === 'top-right' &&
81
+ shape === 'rectangle' &&
82
+ 'top-0.5 right-px',
83
+ placement === 'top-right' && shape === 'circle' && 'top-1 right-1',
84
+
85
+ placement === 'bottom-right' &&
86
+ shape === 'rectangle' &&
87
+ 'bottom-0.5 right-px',
88
+ placement === 'bottom-right' &&
89
+ shape === 'circle' &&
90
+ 'bottom-1 right-1',
91
+
92
+ placement === 'top-left' &&
93
+ shape === 'rectangle' &&
94
+ 'top-0.5 left-px',
95
+ placement === 'top-left' && shape === 'circle' && 'top-1 left-1',
96
+
97
+ placement === 'bottom-left' &&
98
+ shape === 'rectangle' &&
99
+ 'bottom-0.5 left-px',
100
+ placement === 'bottom-left' &&
101
+ shape === 'circle' &&
102
+ 'bottom-1 left-1',
103
+ ],
104
+ [
105
+ placement === 'top-right' && 'translate-x-1/2 -translate-y-1/2',
106
+ placement === 'bottom-right' && 'translate-x-1/2 translate-y-1/2',
107
+ placement === 'bottom-left' && '-translate-x-1/2 translate-y-1/2',
108
+ placement === 'top-left' && '-translate-x-1/2 -translate-y-1/2',
109
+ ],
110
+ classNames?.badge
111
+ ),
112
+ }}
113
+ content={
114
+ <AnimatePresence>
115
+ {!isInvisible && (
116
+ <motion.div
117
+ layout
118
+ key={`badge-${id}`}
119
+ variants={animationVariants}
120
+ initial={disableAnimation ? 'show' : 'hidden'}
121
+ transition={transition}
122
+ animate="show"
123
+ exit="hidden"
124
+ className={cn(
125
+ 'flex flex-wrap',
126
+ 'place-content-center',
127
+ 'z-10',
128
+ 'box-border',
129
+ 'rounded-full',
130
+ 'py-0 px-1',
131
+ 'font-normal text-slate-900',
132
+ 'select-none',
133
+ // 'transition-transform transition-opacity duration-300 ease-in-out',
134
+ 'whitespace-normal',
135
+ variant === 'faded' ? 'text-slate-800' : 'text-white',
136
+ !content || isDot ? 'w-3.5 h-3.5' : sizeVariant,
137
+ (typeof content === 'string' && content.length > 1) || isDot
138
+ ? 'text-xs'
139
+ : textVariants[size],
140
+ [
141
+ variant === 'solid' && 'bg-slate-800',
142
+ variant === 'shadow' && 'bg-slate-800',
143
+ variant === 'flat' && 'bg-slate-800/55',
144
+ variant === 'faded' && 'bg-white',
145
+ ],
146
+ [
147
+ variant === 'faded' &&
148
+ 'border-2 border-solid border-slate-800',
149
+ showOutline &&
150
+ variant !== 'faded' &&
151
+ 'border-2 border-solid border-white',
152
+ ],
153
+ variant === 'shadow' &&
154
+ 'shadow-[0_0_0_0_rgba(0,0,0,0),_0_0_0_0_rgba(0,0,0,0),_0_10px_15px_-3px_rgba(30,41,59,0.3),_0_4px_6px_-4px_rgba(30,41,59,0.3)]',
155
+ className
156
+ )}
157
+ >
158
+ {content}
159
+ </motion.div>
160
+ )}
161
+ </AnimatePresence>
162
+ }
163
+ >
164
+ {children}
165
+ </NextUIBadge>
166
+ );
167
+ }
168
+
169
+ export default Badge;
@@ -0,0 +1,3 @@
1
+ import type { BadgeProps as NextBadgeProps } from '@nextui-org/badge';
2
+
3
+ export type BadgeProps = Omit<NextBadgeProps, 'color | disableOutline'>;
@@ -0,0 +1,2 @@
1
+ export { Badge } from './Badge';
2
+ export type { BadgeProps } from './Badge.types';
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+
3
+ import type { BreadcrumbEllipsisProps } from './BreadcrumbEllipsis.types';
4
+
5
+ export function BreadcrumbEllipsis({
6
+ children,
7
+ ...props
8
+ }: BreadcrumbEllipsisProps) {
9
+ return (
10
+ // eslint-disable-next-line react/jsx-props-no-spreading
11
+ <span {...props} aria-hidden="true">
12
+ {children ?? (
13
+ <svg
14
+ width="16"
15
+ height="16"
16
+ viewBox="0 0 24 24"
17
+ fill="none"
18
+ xmlns="http://www.w3.org/2000/svg"
19
+ >
20
+ <path
21
+ d="M12 13C12.5523 13 13 12.5523 13 12C13 11.4477 12.5523 11 12 11C11.4477 11 11 11.4477 11 12C11 12.5523 11.4477 13 12 13Z"
22
+ stroke="black"
23
+ strokeWidth="2"
24
+ strokeLinecap="round"
25
+ strokeLinejoin="round"
26
+ />
27
+ <path
28
+ d="M19 13C19.5523 13 20 12.5523 20 12C20 11.4477 19.5523 11 19 11C18.4477 11 18 11.4477 18 12C18 12.5523 18.4477 13 19 13Z"
29
+ stroke="black"
30
+ strokeWidth="2"
31
+ strokeLinecap="round"
32
+ strokeLinejoin="round"
33
+ />
34
+ <path
35
+ d="M5 13C5.55228 13 6 12.5523 6 12C6 11.4477 5.55228 11 5 11C4.44772 11 4 11.4477 4 12C4 12.5523 4.44772 13 5 13Z"
36
+ stroke="black"
37
+ strokeWidth="2"
38
+ strokeLinecap="round"
39
+ strokeLinejoin="round"
40
+ />
41
+ </svg>
42
+ )}
43
+ </span>
44
+ );
45
+ }
46
+
47
+ export default BreadcrumbEllipsis;
@@ -0,0 +1,5 @@
1
+ import type { HTMLAttributes, PropsWithChildren } from 'react';
2
+
3
+ export type BreadcrumbEllipsisProps = PropsWithChildren<
4
+ HTMLAttributes<HTMLSpanElement>
5
+ >;
@@ -0,0 +1,23 @@
1
+ 'use client';
2
+
3
+ import { Breadcrumb } from 'react-aria-components';
4
+ import { cn } from '../../utils/cn';
5
+ import type { BreadcrumbItemProps } from './BreadcrumbItem.types';
6
+
7
+ export function BreadcrumbItem({
8
+ children,
9
+ className,
10
+ ...props
11
+ }: BreadcrumbItemProps) {
12
+ return (
13
+ <Breadcrumb
14
+ className={cn('flex items-center', className)}
15
+ // eslint-disable-next-line react/jsx-props-no-spreading
16
+ {...props}
17
+ >
18
+ {children}
19
+ </Breadcrumb>
20
+ );
21
+ }
22
+
23
+ export default BreadcrumbItem;