@clicktap/ui 0.14.12 → 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 +1 -1
  191. package/tailwind.config.js +3 -1
@@ -0,0 +1,89 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { action } from '@storybook/addon-actions';
3
+ import { ToggleButtonProps } from 'react-aria-components';
4
+ import { ToggleButton } from './ToggleButton';
5
+
6
+ type Story = StoryObj<typeof ToggleButton>;
7
+
8
+ function Component({ children, ...props }: ToggleButtonProps) {
9
+ return <ToggleButton {...props}>{children}</ToggleButton>;
10
+ }
11
+
12
+ const meta: Meta<typeof ToggleButton> = {
13
+ component: Component,
14
+ };
15
+
16
+ export default meta;
17
+
18
+ export const Example: Story = {
19
+ argTypes: {
20
+ variant: {
21
+ options: ['solid', 'outline', 'ghost'],
22
+ control: 'select',
23
+ },
24
+ size: {
25
+ options: ['sm', 'md', 'lg'],
26
+ control: 'select',
27
+ },
28
+ isSelected: {
29
+ control: 'boolean',
30
+ },
31
+ isDisabled: {
32
+ control: 'boolean',
33
+ },
34
+ defaultSelected: {
35
+ control: 'boolean',
36
+ },
37
+ autoFocus: {
38
+ control: 'boolean',
39
+ },
40
+ type: {
41
+ options: ['button', 'submit', 'reset'],
42
+ control: { type: 'radio' },
43
+ },
44
+ excludeFromTabOrder: {
45
+ control: 'boolean',
46
+ },
47
+ children: {
48
+ control: 'text',
49
+ },
50
+ className: {
51
+ control: 'object',
52
+ },
53
+ style: {
54
+ control: 'object',
55
+ },
56
+ onChange: {},
57
+ onPress: {},
58
+ onPressStart: {},
59
+ onPressEnd: {},
60
+ onPressChange: {},
61
+ onPressUp: {},
62
+ onFocus: {},
63
+ onBlur: {},
64
+ onFocusChange: {},
65
+ onKeyDown: {},
66
+ onKeyUp: {},
67
+ },
68
+ args: {
69
+ variant: 'solid',
70
+ size: 'md',
71
+ isSelected: false,
72
+ isDisabled: false,
73
+ autoFocus: false,
74
+ defaultSelected: false,
75
+ excludeFromTabOrder: false,
76
+ type: 'button',
77
+ children: 'Press me',
78
+ onPress: action('onPress'),
79
+ onPressStart: action('onPressStart'),
80
+ onPressEnd: action('onPressEnd'),
81
+ onPressChange: action('onPressChange'),
82
+ onPressUp: action('onPressUp'),
83
+ onFocus: action('onFocus'),
84
+ onBlur: action('onBlur'),
85
+ onFocusChange: action('onFocusChange'),
86
+ onKeyDown: action('onKeyDown'),
87
+ onKeyUp: action('onKeyUp'),
88
+ },
89
+ };
@@ -0,0 +1,69 @@
1
+ 'use client';
2
+
3
+ import { ToggleButton as AriaToggleButton } from 'react-aria-components';
4
+ import { cn } from '../../utils/cn';
5
+ import { ToggleButtonProps } from './ToggleButton.types';
6
+
7
+ export function ToggleButton({
8
+ children,
9
+ size = 'md',
10
+ variant = 'solid',
11
+ className,
12
+ ...props
13
+ }: ToggleButtonProps) {
14
+ return (
15
+ <AriaToggleButton
16
+ className={(renderProps) => {
17
+ const { isDisabled } = renderProps;
18
+ return cn(
19
+ 'flex items-center justify-center',
20
+ 'font-semibold text-sm',
21
+ 'rounded-md border-solid border',
22
+ 'px-4',
23
+ 'transition-all duration-200 ease-in-out',
24
+ 'focus:outline-2 focus:outline focus:outline-slate-200 pressed:scale-95',
25
+ {
26
+ 'h-8': size === 'sm',
27
+ 'h-10': size === 'md',
28
+ 'h-12': size === 'lg',
29
+ },
30
+ [
31
+ variant === 'ghost' && [
32
+ 'bg-transparent hover:bg-transparent focus:bg-transparent disabled:bg-transparent',
33
+ 'border-transparent hover:border-transparent focus:border-transparent disabled:border-transparent',
34
+ 'text-slate-900 disabled:text-slate-400',
35
+ isDisabled && ['disabled:text-slate-900', 'opacity-75'],
36
+ ],
37
+ variant === 'outline' && [
38
+ 'bg-transparent hover:bg-transparent focus:bg-transparent disabled:bg-transparent',
39
+ 'border-slate-300 hover:border-slate-400 focus:border-slate-400 disabled:border-slate-200',
40
+ 'text-slate-900 disabled:text-slate-500',
41
+ isDisabled && [
42
+ 'disabled:border-slate-300',
43
+ 'disabled:text-slate-900',
44
+ 'opacity-75',
45
+ ],
46
+ ],
47
+ variant === 'solid' && [
48
+ 'bg-slate-800 hover:bg-slate-900 focus:bg-slate-900 disabled:bg-slate-900',
49
+ 'border-slate-800 hover:border-slate-900 focus:border-slate-900 disabled:border-slate-200',
50
+ 'text-white disabled:text-slate-400',
51
+ isDisabled && [
52
+ 'disabled:border-slate-900',
53
+ 'disabled:text-white',
54
+ 'opacity-75',
55
+ ],
56
+ ],
57
+ ],
58
+ typeof className === 'function' ? className(renderProps) : className
59
+ );
60
+ }}
61
+ // eslint-disable-next-line react/jsx-props-no-spreading
62
+ {...props}
63
+ >
64
+ {children}
65
+ </AriaToggleButton>
66
+ );
67
+ }
68
+
69
+ export default ToggleButton;
@@ -0,0 +1,6 @@
1
+ import { ToggleButtonProps as AriaToggleButtonProps } from 'react-aria-components';
2
+
3
+ export type ToggleButtonProps = AriaToggleButtonProps & {
4
+ variant?: 'solid' | 'outline' | 'ghost';
5
+ size?: 'sm' | 'md' | 'lg';
6
+ };
@@ -0,0 +1,2 @@
1
+ export { ToggleButton } from './ToggleButton';
2
+ export type { ToggleButtonProps } from './ToggleButton.types';
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+
3
+ import { forwardRef } from 'react';
4
+ import { Tooltip as UiTooltip } from '@nextui-org/tooltip';
5
+ import { cn } from '../../utils/cn';
6
+ import type { TooltipProps } from './Tooltip.types';
7
+
8
+ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
9
+ function Tooltip(
10
+ { classNames, placement, showArrow = false, ...props },
11
+ ref
12
+ ) {
13
+ return (
14
+ <UiTooltip
15
+ classNames={{
16
+ base: [
17
+ cn([
18
+ 'z-0 relative bg-transparent outline-none',
19
+ 'focus-visible:z-10 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-500',
20
+
21
+ // arrow styles
22
+ 'before:absolute before:rotate-45 before:w-2.5 before:h-2.5 before:rounded-sm before:bg-slate-500 before:shadow-sm',
23
+ 'before:hidden data-[arrow=true]:before:block',
24
+ 'data-[placement=bottom]:before:-top-1 data-[placement=bottom]:before:left-1/2 data-[placement=bottom]:before:rotate-45 data-[placement=bottom]:before:-translate-x-1/2',
25
+ 'data-[placement=bottom-end]:before:-top-1 data-[placement=bottom-end]:before:left-1/2 data-[placement=bottom-end]:before:rotate-45 data-[placement=bottom-end]:before:-translate-x-1/2',
26
+ 'data-[placement=bottom-start]:before:-top-1 data-[placement=bottom-start]:before:left-1/2 data-[placement=bottom-start]:before:rotate-45 data-[placement=bottom-start]:before:-translate-x-1/2',
27
+ 'data-[placement=left]:before:-right-1 data-[placement=left]:before:top-1/2 data-[placement=left]:before:-translate-y-1/2',
28
+ 'data-[placement=left-end]:before:-right-1 data-[placement=left-end]:before:top-1/2 data-[placement=left-end]:before:-translate-y-1/2',
29
+ 'data-[placement=left-start]:before:-right-1 data-[placement=left-start]:before:top-1/2 data-[placement=left-start]:before:-translate-y-1/2',
30
+ 'data-[placement=right]:before:-left-1 data-[placement=right]:before:top-1/2 data-[placement=right]:before:-translate-y-1/2',
31
+ 'data-[placement=right-end]:before:-left-1 data-[placement=right-end]:before:top-1/2 data-[placement=right-end]:before:-translate-y-1/2',
32
+ 'data-[placement=right-start]:before:-left-1 data-[placement=right-start]:before:top-1/2 data-[placement=right-start]:before:-translate-y-1/2',
33
+ 'data-[placement=top]:before:-bottom-1 data-[placement=top]:before:left-1/2 data-[placement=top]:before:rotate-45 data-[placement=top]:before:-translate-x-1/2',
34
+ 'data-[placement=top-end]:before:-bottom-1 data-[placement=top-end]:before:left-1/2 data-[placement=top-end]:before:rotate-45 data-[placement=top-end]:before:-translate-x-1/2',
35
+ 'data-[placement=top-start]:before:-bottom-1 data-[placement=top-start]:before:left-1/2 data-[placement=top-start]:before:rotate-45 data-[placement=top-start]:before:-translate-x-1/2',
36
+
37
+ classNames?.base,
38
+ ]),
39
+ ],
40
+ content: [
41
+ cn([
42
+ 'inline-flex flex-col items-center justify-center outline-none',
43
+ 'w-full py-1 px-2.5 z-10 box-border bg-slate-500 rounded-md shadow-sm',
44
+ 'text-sm text-white subpixel-antialiased',
45
+ classNames?.content,
46
+ ]),
47
+ ],
48
+ }}
49
+ placement={placement}
50
+ showArrow={showArrow}
51
+ // eslint-disable-next-line react/jsx-props-no-spreading
52
+ {...props}
53
+ ref={ref}
54
+ />
55
+ );
56
+ }
57
+ );
58
+
59
+ export default Tooltip;
@@ -0,0 +1,3 @@
1
+ import type { TooltipProps as UITooltipProps } from '@nextui-org/tooltip';
2
+
3
+ export type TooltipProps = UITooltipProps;
@@ -0,0 +1,2 @@
1
+ export { Tooltip } from './Tooltip';
2
+ export type { TooltipProps } from './Tooltip.types';
@@ -0,0 +1,206 @@
1
+ 'use client';
2
+
3
+ import { forwardRef, useState } from 'react';
4
+ import type { ChangeEvent } from 'react';
5
+ import { motion } from 'framer-motion';
6
+ import Image from 'next/image';
7
+
8
+ import { FieldError } from 'react-aria-components';
9
+ import { cn } from '../../utils/cn';
10
+ import type { UploadImageProps } from './UploadImage.types';
11
+ import { useIsClient } from '../../hooks/useIsClient';
12
+ import { Skeleton } from '../Skeleton';
13
+
14
+ function UploadImageLoader({
15
+ hasTitle,
16
+ className,
17
+ }: {
18
+ hasTitle: boolean;
19
+ className: NonNullable<UploadImageProps['classNames']>['skeleton'];
20
+ }) {
21
+ return (
22
+ <div className="w-full h-full flex flex-col gap-4">
23
+ {hasTitle && <Skeleton className="w-1/2 h-8 mx-auto rounded-md z-20" />}
24
+ <Skeleton
25
+ className={cn('w-full h-56 rounded-md z-20 relative', className)}
26
+ />
27
+ </div>
28
+ );
29
+ }
30
+
31
+ export const UploadImage = forwardRef<HTMLInputElement, UploadImageProps>(
32
+ (
33
+ {
34
+ title,
35
+ description = 'Preview will display here.',
36
+ fileExtension,
37
+ actionTitle = 'select file',
38
+ variant,
39
+ errorMessage,
40
+ defaultImagePath,
41
+ classNames,
42
+ ...props
43
+ },
44
+ ref
45
+ ) => {
46
+ const isClient = useIsClient();
47
+ const [image, setImage] = useState<{
48
+ src: string | null;
49
+ alt: string | null;
50
+ }>({
51
+ src: null,
52
+ alt: null,
53
+ });
54
+
55
+ const invalid = !!errorMessage;
56
+
57
+ const accept = fileExtension
58
+ ? fileExtension
59
+ .split(',')
60
+ .map((val) => `image/${val.trim()}`)
61
+ .join(', ')
62
+ : 'image/*';
63
+
64
+ return (
65
+ <div className={cn('w-full h-full', 'flex flex-col gap-4')}>
66
+ {isClient ? (
67
+ <>
68
+ {title && (
69
+ <h6 className={cn('text-center', 'text-2xl', 'm-0 mb-4')}>
70
+ {title}
71
+ </h6>
72
+ )}
73
+ <div
74
+ className={cn(
75
+ 'w-full h-full',
76
+ 'flex flex-col justify-between gap-5 items-center',
77
+ ['bg-slate-100', variant === 'base' && 'bg-transparent'],
78
+ 'rounded-md',
79
+ [variant === 'base' && 'rounded-none'],
80
+ ['p-6 lg:p-7', variant === 'base' && 'p-0 lg:p-0']
81
+ )}
82
+ >
83
+ <label
84
+ htmlFor={`${props?.name}-upload-file`}
85
+ aria-label="image upload"
86
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
87
+ // @ts-ignore
88
+ onChange={(e: ChangeEvent<HTMLInputElement>) => {
89
+ const {
90
+ target: { files },
91
+ } = e;
92
+ if (files) {
93
+ setImage({
94
+ src: URL.createObjectURL(files[0]),
95
+ alt: files[0].name,
96
+ });
97
+ }
98
+ }}
99
+ className={cn(
100
+ 'inline-flex justify-center items-center',
101
+ 'uppercase text-base border-slate-200',
102
+ 'bg-transparent',
103
+ 'border-1 border-solid',
104
+ 'px-4 py-0',
105
+ 'rounded-2xl',
106
+ 'cursor-pointer',
107
+ 'w-full h-9',
108
+ ['max-w-48', variant === 'base' && 'max-w-none'],
109
+ 'my-0 mx-auto',
110
+ 'has-[:disabled]:bg-transparent has-[:disabled]:text-slate-950',
111
+ 'hover:bg-slate-100s hover:text-black',
112
+ classNames?.label
113
+ )}
114
+ >
115
+ {actionTitle}
116
+ <input
117
+ id={`${props?.name}-upload-file`}
118
+ accept={accept}
119
+ type="file"
120
+ hidden
121
+ // eslint-disable-next-line react/jsx-props-no-spreading
122
+ {...props}
123
+ ref={ref}
124
+ className="hidden"
125
+ />
126
+ </label>
127
+
128
+ {defaultImagePath && !image.src ? (
129
+ <div className="flex justify-center items-center w-60">
130
+ <a href={defaultImagePath} target="_blank" rel="noreferrer">
131
+ <img
132
+ src={defaultImagePath}
133
+ alt=""
134
+ className="w-full h-auto"
135
+ />
136
+ </a>
137
+ </div>
138
+ ) : (
139
+ <>
140
+ <motion.div
141
+ initial={{ opacity: 0 }}
142
+ animate={{ opacity: 1 }}
143
+ transition={{ type: 'spring', duration: 3, bounce: 0 }}
144
+ key={image.src}
145
+ className="flex justify-center items-center w-52 h-auto"
146
+ >
147
+ {image.src ? (
148
+ <Image
149
+ src={image.src}
150
+ height={96}
151
+ width={200}
152
+ alt={image.alt || ''}
153
+ className="max-h-full object-contain"
154
+ />
155
+ ) : (
156
+ <svg
157
+ xmlns="http://www.w3.org/2000/svg"
158
+ width="31"
159
+ height="55"
160
+ viewBox="0 0 31 55"
161
+ fill="none"
162
+ >
163
+ <g clipPath="url(#clip0_15607_32844)">
164
+ <path
165
+ d="M15.9521 0.721924C24.2431 0.721924 30.9521 7.36392 30.9521 15.5719V43.9219C30.9521 49.8889 26.0703 54.7219 20.0431 54.7219C14.0158 54.7219 9.13397 49.8889 9.13397 43.9219V20.9719C9.13397 17.2459 12.1885 14.2219 15.9521 14.2219C19.7158 14.2219 22.7703 17.2459 22.7703 20.9719V41.2219H17.3158V20.7289C17.3158 19.2439 14.5885 19.2439 14.5885 20.7289V43.9219C14.5885 46.8919 17.0431 49.3219 20.0431 49.3219C23.0431 49.3219 25.4976 46.8919 25.4976 43.9219V15.5719C25.4976 10.3609 21.2158 6.12192 15.9521 6.12192C10.6885 6.12192 6.40669 10.3609 6.40669 15.5719V41.2219H0.952148V15.5719C0.952148 7.36392 7.66124 0.721924 15.9521 0.721924Z"
166
+ fill="#646464"
167
+ />
168
+ </g>
169
+ <defs>
170
+ <clipPath id="clip0_15607_32844">
171
+ <rect
172
+ width="30"
173
+ height="54"
174
+ fill="white"
175
+ transform="translate(0.952148 0.721924)"
176
+ />
177
+ </clipPath>
178
+ </defs>
179
+ </svg>
180
+ )}
181
+ </motion.div>
182
+ <p className="m-0 text-slate-950 text-center">
183
+ {image.alt || description}
184
+ </p>
185
+ </>
186
+ )}
187
+ </div>
188
+ </>
189
+ ) : (
190
+ <UploadImageLoader
191
+ hasTitle={Boolean(title)}
192
+ className={classNames?.skeleton}
193
+ />
194
+ )}
195
+
196
+ {invalid && (
197
+ <FieldError className={cn('-mt-2', 'self-start')}>
198
+ {errorMessage}
199
+ </FieldError>
200
+ )}
201
+ </div>
202
+ );
203
+ }
204
+ );
205
+
206
+ export default UploadImage;
@@ -0,0 +1,15 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { UseFormRegisterReturn } from 'react-hook-form';
3
+ import type { SlotsToClasses } from '../../types/SlotsToClasses';
4
+
5
+ export type UploadImageProps = UseFormRegisterReturn & {
6
+ title?: string;
7
+ description?: ReactNode;
8
+ name?: string;
9
+ fileExtension?: string;
10
+ actionTitle?: string;
11
+ errorMessage?: string;
12
+ defaultImagePath?: string;
13
+ variant?: 'default' | 'base';
14
+ classNames?: SlotsToClasses<'label' | 'skeleton'>;
15
+ };
@@ -0,0 +1,2 @@
1
+ export { UploadImage } from './UploadImage';
2
+ export type { UploadImageProps } from './UploadImage.types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clicktap/ui",
3
- "version": "0.14.12",
3
+ "version": "0.14.13",
4
4
  "private": false,
5
5
  "author": "Clicktap",
6
6
  "description": "A library of React UI components and low-level hooks.",
@@ -1,4 +1,6 @@
1
+ const path = require('path');
2
+
1
3
  /** @type {import('tailwindcss').Config} */
2
4
  module.exports = {
3
- content: ['./src/components/**/*.{js,jsx,ts,tsx}'],
5
+ content: [path.resolve(__dirname, './components/**/*.{js,jsx,ts,tsx}')],
4
6
  };