@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,119 @@
1
+ 'use client';
2
+
3
+ import { memo, useId, useMemo, useCallback, useState } from 'react';
4
+ import { motion } from 'framer-motion';
5
+ import type { DigitProps, DigitResolverProps } from './DigitResolver.types';
6
+ import { useColumnTransition } from './hooks/useColumnTransition';
7
+
8
+ const NUMBER_REGEX = /^-?\d*\.?\d+$/;
9
+
10
+ function Digit({
11
+ digit,
12
+ tickerMotionProps,
13
+ transition,
14
+ updateTransition,
15
+ }: DigitProps) {
16
+ const [position, setPosition] = useState(0);
17
+
18
+ const updatePosition = useCallback(
19
+ (node: HTMLDivElement) => {
20
+ if (node !== null) {
21
+ setPosition(node.clientHeight * parseInt(digit, 10));
22
+ }
23
+ },
24
+ [digit]
25
+ );
26
+
27
+ return (
28
+ <span className="relative h-auto block" ref={updatePosition} aria-hidden>
29
+ <motion.span
30
+ className="absolute block bottom-0 h-[1000%]"
31
+ initial={{ x: 0, y: position }}
32
+ animate={{ x: 0, y: position }}
33
+ transition={{ ...transition }}
34
+ onAnimationComplete={updateTransition}
35
+ style={{ fontFeatureSettings: 'tnum' }}
36
+ >
37
+ {[9, 8, 7, 6, 5, 4, 3, 2, 1, 0].map((i) => (
38
+ <motion.span
39
+ className="block text-[inherit] leading-[inherit] tabular-nums"
40
+ key={i}
41
+ // eslint-disable-next-line react/jsx-props-no-spreading
42
+ {...tickerMotionProps}
43
+ >
44
+ {i}
45
+ </motion.span>
46
+ ))}
47
+ </motion.span>
48
+ <motion.span
49
+ className="block text-[inherit] leading-[inherit] invisible"
50
+ aria-hidden
51
+ >
52
+ 0
53
+ </motion.span>
54
+ </span>
55
+ );
56
+ }
57
+
58
+ const DigitMemo = memo(Digit);
59
+
60
+ export function DigitResolver({
61
+ delta,
62
+ digits,
63
+ isNegative,
64
+ tickerMotionProps,
65
+ ...transitionConfig
66
+ }: DigitResolverProps) {
67
+ const id = useId();
68
+ const motionProps = useMemo(
69
+ () =>
70
+ typeof tickerMotionProps === 'function'
71
+ ? tickerMotionProps({ delta })
72
+ : tickerMotionProps,
73
+ [delta, tickerMotionProps]
74
+ );
75
+
76
+ const columnTransition = useColumnTransition({
77
+ ...transitionConfig,
78
+ });
79
+
80
+ return (
81
+ <>
82
+ {isNegative && (
83
+ <motion.span
84
+ className="block text-[inherit] leading-[inherit] tabular-nums"
85
+ aria-hidden
86
+ // eslint-disable-next-line react/jsx-props-no-spreading
87
+ {...motionProps}
88
+ >
89
+ -
90
+ </motion.span>
91
+ )}
92
+ {digits.map((digit, idx) =>
93
+ NUMBER_REGEX.test(digit) ? (
94
+ <DigitMemo
95
+ // eslint-disable-next-line react/no-array-index-key
96
+ key={`${id}_${idx}`}
97
+ digit={digit}
98
+ tickerMotionProps={motionProps}
99
+ // eslint-disable-next-line react/jsx-props-no-spreading
100
+ {...columnTransition}
101
+ />
102
+ ) : (
103
+ <motion.span
104
+ className="block text-[inherit] leading-[inherit] tabular-nums"
105
+ // eslint-disable-next-line react/no-array-index-key
106
+ key={`${id}_${idx}`}
107
+ aria-hidden
108
+ // eslint-disable-next-line react/jsx-props-no-spreading
109
+ {...motionProps}
110
+ >
111
+ {digit}
112
+ </motion.span>
113
+ )
114
+ )}
115
+ </>
116
+ );
117
+ }
118
+
119
+ export default DigitResolver;
@@ -0,0 +1,18 @@
1
+ import type { MotionProps, Transition } from 'framer-motion';
2
+ import { NumberTickerProps, TickerMotionProps } from './NumberTicker.types';
3
+
4
+ export type DigitResolverProps = Pick<
5
+ NumberTickerProps,
6
+ 'tickerMotionProps' | 'skipFirstAnimation' | 'transition'
7
+ > &
8
+ TickerMotionProps & {
9
+ digits: string[];
10
+ isNegative: boolean;
11
+ };
12
+
13
+ export type DigitProps = Pick<NumberTickerProps, 'tickerMotionProps'> & {
14
+ digit: string;
15
+ tickerMotionProps: MotionProps | undefined;
16
+ transition: Transition;
17
+ updateTransition: () => void;
18
+ };
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import { motion } from 'framer-motion';
4
+ import { cn } from '../../utils/cn';
5
+ import type { NumberTickerProps } from './NumberTicker.types';
6
+ import { useNumberDelta } from './hooks/useNumberDelta';
7
+ import { useNumberTicker } from './hooks/useNumberTicker';
8
+ import { DigitResolver } from './DigitResolver';
9
+
10
+ export function NumberTicker({
11
+ value,
12
+ asLocal,
13
+ localeConfig,
14
+ precision,
15
+ slots,
16
+ skipFirstAnimation,
17
+ transition,
18
+ tickerMotionProps,
19
+ className,
20
+ ...props
21
+ }: NumberTickerProps) {
22
+ const { digits, isNegative } = useNumberTicker({
23
+ value,
24
+ asLocal,
25
+ localeConfig,
26
+ precision,
27
+ });
28
+ const delta = useNumberDelta(value);
29
+
30
+ return (
31
+ <motion.span
32
+ className={cn(
33
+ 'flex h-auto flex-row flex-nowrap overflow-hidden relative text-[inherit]',
34
+ className
35
+ )}
36
+ aria-valuenow={value}
37
+ layout
38
+ layoutRoot
39
+ // eslint-disable-next-line react/jsx-props-no-spreading
40
+ {...props}
41
+ >
42
+ {slots?.startContent}
43
+ <DigitResolver
44
+ isNegative={isNegative}
45
+ digits={digits}
46
+ tickerMotionProps={tickerMotionProps}
47
+ skipFirstAnimation={skipFirstAnimation}
48
+ transition={transition}
49
+ delta={delta}
50
+ />
51
+ {slots?.endContent}
52
+ </motion.span>
53
+ );
54
+ }
55
+
56
+ export default NumberTicker;
@@ -0,0 +1,96 @@
1
+ import type { MotionProps, Transition } from 'framer-motion';
2
+ import type { CSSProperties, ReactNode } from 'react';
3
+
4
+ export type TickerMotionProps = {
5
+ delta: 'increase' | 'decrease' | 'same';
6
+ };
7
+
8
+ export type TransitionConfig = {
9
+ /**
10
+ * Whether the NumberTicker animation on render
11
+ * @default true
12
+ */
13
+ skipFirstAnimation?: boolean;
14
+ /**
15
+ * The transition props to modify the NumberTicker animation.
16
+ * Use the framer motion transition API to create your own transition.
17
+ */
18
+ transition?: Transition;
19
+ };
20
+
21
+ export interface NumberTickerConfig {
22
+ value: number;
23
+ /**
24
+ * Number of digits after the decimal point. Must be in the range 0 - 20, inclusive.
25
+ * @default 2
26
+ */
27
+ precision?: number;
28
+ /**
29
+ * Whether the NumberTicker value as Intl.NumberFormat
30
+ * @default false
31
+ */
32
+ asLocal?: boolean;
33
+ /**
34
+ * The configuration for the NumberTicker value as Intl.NumberFormat
35
+ * By default the object {
36
+ locale: 'en-US',
37
+ options: {
38
+ style: 'currency',
39
+ currency: 'USD',
40
+ minimumFractionDigits: 2,
41
+ },
42
+ }
43
+ */
44
+ localeConfig?: {
45
+ locale?: string;
46
+ options?: Intl.NumberFormatOptions | undefined;
47
+ };
48
+ }
49
+
50
+ export type NumberTickerProps = NumberTickerConfig &
51
+ TransitionConfig & {
52
+ style?: CSSProperties;
53
+ className?: string;
54
+ slots?: {
55
+ /**
56
+ * Element to be rendered in the left side of the NumberTicker.
57
+ */
58
+ startContent?: ReactNode;
59
+ /**
60
+ * Element to be rendered in the right side of the NumberTicker.
61
+ */
62
+ endContent?: ReactNode;
63
+ };
64
+
65
+ /**
66
+ * The motion props to modify the each Ticker animation.
67
+ * Use the framer motion API to create your own animation. With the possible to use the delta value
68
+ * Example:
69
+ *
70
+ * const getColor = (delta: TickerMotionProps) => {
71
+ switch (d) {
72
+ case 'increase':
73
+ return '#48ff0b';
74
+ case 'decrease':
75
+ return '#F22613';
76
+ default:
77
+ return '#fff';
78
+ }
79
+ };
80
+
81
+ <NumberTicker
82
+ tickerMotionProps={({ delta }) => ({
83
+ animate: {
84
+ color: [getColor(delta), '#fff'],
85
+ transition: {
86
+ duration: 2,
87
+ },
88
+ },
89
+ })}
90
+ />
91
+ *
92
+ */
93
+ tickerMotionProps?:
94
+ | MotionProps
95
+ | ((props: TickerMotionProps) => MotionProps);
96
+ };
@@ -0,0 +1,36 @@
1
+ import { Transition } from 'framer-motion';
2
+ import { useState, useMemo, useCallback } from 'react';
3
+ import { TransitionConfig } from '../NumberTicker.types';
4
+
5
+ export const useColumnTransition = ({
6
+ skipFirstAnimation = true,
7
+ transition: transitionProps,
8
+ }: TransitionConfig) => {
9
+ const [firstAnimation, setFirstAnimation] = useState(skipFirstAnimation);
10
+
11
+ const transition = useMemo<Transition>(() => {
12
+ return firstAnimation
13
+ ? {
14
+ duration: 0.1,
15
+ }
16
+ : {
17
+ ...(transitionProps || {
18
+ type: 'spring',
19
+ stiffness: 50,
20
+ }),
21
+ };
22
+ }, [firstAnimation, transitionProps]);
23
+
24
+ const updateTransition = useCallback(() => {
25
+ if (skipFirstAnimation) {
26
+ setFirstAnimation(false);
27
+ }
28
+ }, [skipFirstAnimation]);
29
+
30
+ return {
31
+ transition,
32
+ updateTransition,
33
+ };
34
+ };
35
+
36
+ export default useColumnTransition;
@@ -0,0 +1,19 @@
1
+ import { useRef, useEffect } from 'react';
2
+
3
+ export const useNumberDelta = (value = 0) => {
4
+ const ref = useRef(value);
5
+ useEffect(() => {
6
+ ref.current = value;
7
+ }, [value]);
8
+
9
+ switch (true) {
10
+ case value > ref.current:
11
+ return 'increase';
12
+ case value < ref.current:
13
+ return 'decrease';
14
+ default:
15
+ return 'same';
16
+ }
17
+ };
18
+
19
+ export default useNumberDelta;
@@ -0,0 +1,36 @@
1
+ import { useMemo } from 'react';
2
+ import { NumberTickerConfig } from '../NumberTicker.types';
3
+
4
+ export const useNumberTicker = ({
5
+ value = 0,
6
+ asLocal = false,
7
+ localeConfig = {
8
+ locale: 'en-US',
9
+ options: {
10
+ style: 'currency',
11
+ currency: 'USD',
12
+ minimumFractionDigits: 2,
13
+ },
14
+ },
15
+ precision = 2,
16
+ }: NumberTickerConfig) => {
17
+ const parsed = parseFloat(`${Math.max(Math.abs(value), 0)}`).toFixed(
18
+ precision ?? 0
19
+ );
20
+
21
+ const number = asLocal
22
+ ? new Intl.NumberFormat(localeConfig?.locale, {
23
+ ...localeConfig?.options,
24
+ }).format(parseFloat(parsed))
25
+ : parsed;
26
+
27
+ return useMemo(
28
+ () => ({
29
+ digits: number.split(''),
30
+ isNegative: value < 0,
31
+ }),
32
+ [number, value]
33
+ );
34
+ };
35
+
36
+ export default useNumberTicker;
@@ -0,0 +1,10 @@
1
+ export { DigitResolver } from './DigitResolver';
2
+ export { NumberTicker } from './NumberTicker';
3
+
4
+ export type { DigitProps, DigitResolverProps } from './DigitResolver.types';
5
+ export type {
6
+ NumberTickerConfig,
7
+ NumberTickerProps,
8
+ TickerMotionProps,
9
+ TransitionConfig,
10
+ } from './NumberTicker.types';
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+
3
+ import { Pagination as UiPagination } from '@nextui-org/pagination';
4
+ import type { PaginationProps } from '@nextui-org/pagination';
5
+ import { cn } from '../../utils/cn';
6
+
7
+ const controlClassNames = cn(
8
+ 'w-8 h-8 flex justify-center items-center cursor-pointer shadow-none',
9
+ 'border border-slate-200 data-[disabled=true]:border-0',
10
+ 'rounded transition-colors duration-300 data-[focus-visible="true"]:outline-white data-[focus-visible="true"]:outline-offset-4',
11
+ 'hover:bg-slate-50 data-[disabled=true]:bg-slate-100 data-[disabled=true]:text-slate-400',
12
+ '[&>svg]:w-4.5 [&>svg]:h-auto'
13
+ );
14
+
15
+ export function Pagination({
16
+ showControls = true,
17
+ className,
18
+ classNames,
19
+ ...rest
20
+ }: PaginationProps) {
21
+ return (
22
+ <UiPagination
23
+ showControls={showControls}
24
+ className={cn('text-slate-600', className)}
25
+ classNames={{
26
+ wrapper: cn('flex flex-nowrap gap-2 lg:gap-3', classNames?.wrapper),
27
+ item: cn(
28
+ 'w-8 h-8 flex text-sm justify-center items-center cursor-pointer rounded shadow-none',
29
+ 'border-solid border border-slate-100 bg-transparent transition-colors duration-300',
30
+ 'data-[active=true]:bg-slate-500 data-[active=true]:text-white data-[focus-visible="true"]:outline-white data-[focus-visible="true"]:outline-offset-4',
31
+ '[&[data-hover=true]:not([data-active=true])]:border-slate-200',
32
+ classNames?.item
33
+ ),
34
+ prev: cn(controlClassNames, classNames?.prev),
35
+ next: cn(controlClassNames, classNames?.next),
36
+ ellipsis: cn('w-4 h-4.5 scale-110 translate-y-1', classNames?.ellipsis),
37
+ }}
38
+ // eslint-disable-next-line react/jsx-props-no-spreading
39
+ {...rest}
40
+ />
41
+ );
42
+ }
43
+
44
+ export default Pagination;
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export { Pagination } from './Pagination';
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+
3
+ import { cn } from '../../utils/cn';
4
+ import type { PasswordCheckProps } from './PasswordCheck.types';
5
+ import { checkStrength, getProgressText } from './PasswordCheck.utils';
6
+
7
+ export function PasswordCheck({
8
+ value,
9
+ variant = 'default',
10
+ }: PasswordCheckProps) {
11
+ const strength = checkStrength(value);
12
+
13
+ return (
14
+ <div>
15
+ <div
16
+ className={cn(
17
+ 'relative w-full flex gap-x-2',
18
+ variant === 'default' && 'mb-8 -mt-1'
19
+ )}
20
+ >
21
+ {Array.from({ length: 5 }, (_, idx) => idx).map((v, idx) => (
22
+ <div
23
+ className={cn(
24
+ 'grow shrink basis-1/5 h-1 rounded-full transition-colors duration-700 ease bg-slate-200',
25
+ strength <= idx && 'bg-slate-600',
26
+ (strength === 1 || strength === 2) && 'bg-red-600',
27
+ strength === 3 && 'bg-yellow-600',
28
+ strength === 4 && 'bg-green-600',
29
+ strength === 5 && 'bg-blue-600'
30
+ )}
31
+ key={v}
32
+ />
33
+ ))}
34
+ {variant === 'default' && (
35
+ <div
36
+ className={cn(
37
+ 'inline-flex gap-x-1 absolute top-0 left-0 text-xs translate-y-2/4 text-slate-950',
38
+ strength ? 'opacity-100' : 'opacity-0'
39
+ )}
40
+ >
41
+ <span>Password Strength:</span>
42
+ <span
43
+ className={cn(
44
+ (strength === 1 || strength === 2) && 'text-red-600',
45
+ strength === 3 && 'text-yellow-600',
46
+ strength === 4 && 'text-green-600',
47
+ strength === 5 && 'text-blue-600'
48
+ )}
49
+ >
50
+ {getProgressText(strength)}
51
+ </span>
52
+ </div>
53
+ )}
54
+ </div>
55
+ </div>
56
+ );
57
+ }
58
+
59
+ export default PasswordCheck;
@@ -0,0 +1,4 @@
1
+ export type PasswordCheckProps = {
2
+ value: string;
3
+ variant?: 'default' | 'short';
4
+ };
@@ -0,0 +1,47 @@
1
+ /** @todo these functions should probably be passed as props to be able to extend */
2
+ export const checkStrength = (value: string) => {
3
+ const isMinLength = value.length >= 8;
4
+ let strength = 0;
5
+ if (/^(?=.*[a-z])(?=.*[A-Z])/.test(value) && isMinLength) {
6
+ strength += 1;
7
+ }
8
+ if (/\d/.test(value) && isMinLength) {
9
+ strength += 1;
10
+ }
11
+ if (value.length >= 8) {
12
+ strength += 1;
13
+ }
14
+ if (value.length >= 11) {
15
+ strength += 1;
16
+ }
17
+ if (/[ `!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~]/.test(value) && isMinLength) {
18
+ strength += 1;
19
+ }
20
+ return strength;
21
+ };
22
+
23
+ export const getProgressText = (strength: number) => {
24
+ switch (strength) {
25
+ case 5:
26
+ return 'Very Strong';
27
+ case 4:
28
+ return 'Strong';
29
+ case 3:
30
+ return 'Good';
31
+ case 2:
32
+ return 'Weak';
33
+ case 1:
34
+ return 'Very Weak';
35
+ default:
36
+ return '';
37
+ }
38
+ };
39
+
40
+ /** @todo this doesn't look like it is used...remove? */
41
+ export const getPasswordRequirements = (value = '') => {
42
+ return {
43
+ eightСharacters: value.length >= 8,
44
+ upLowCaseLetters: /^(?=.*[a-z])(?=.*[A-Z])/.test(value),
45
+ oneNumber: /\d/.test(value),
46
+ };
47
+ };
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line import/prefer-default-export
2
+ export { PasswordCheck } from './PasswordCheck';