@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.
- package/components/Accordion/Accordion.tsx +82 -0
- package/components/Accordion/index.ts +3 -0
- package/components/Avatar/Avatar.stories.tsx +99 -0
- package/components/Avatar/Avatar.tsx +120 -0
- package/components/Avatar/Avatar.types.ts +3 -0
- package/components/Avatar/AvatarGroup/AvatarGroup.tsx +32 -0
- package/components/Avatar/AvatarGroup/AvatarGroup.types.ts +8 -0
- package/components/Avatar/index.ts +4 -0
- package/components/Badge/Badge.stories.tsx +72 -0
- package/components/Badge/Badge.tsx +169 -0
- package/components/Badge/Badge.types.ts +3 -0
- package/components/Badge/index.ts +2 -0
- package/components/Breadcrumbs/BreadcrumbEllipsis.tsx +47 -0
- package/components/Breadcrumbs/BreadcrumbEllipsis.types.ts +5 -0
- package/components/Breadcrumbs/BreadcrumbItem.tsx +23 -0
- package/components/Breadcrumbs/BreadcrumbItem.types.ts +3 -0
- package/components/Breadcrumbs/BreadcrumbLink.tsx +30 -0
- package/components/Breadcrumbs/BreadcrumbLink.types.ts +3 -0
- package/components/Breadcrumbs/BreadcrumbSeparator.tsx +41 -0
- package/components/Breadcrumbs/BreadcrumbSeparator.types.ts +9 -0
- package/components/Breadcrumbs/Breadcrumbs.tsx +28 -0
- package/components/Breadcrumbs/Breadcrumbs.types.ts +6 -0
- package/components/Breadcrumbs/index.ts +10 -0
- package/components/Button/Button.tsx +72 -0
- package/components/Button/Button.types.ts +7 -0
- package/components/Button/index.ts +2 -0
- package/components/Card/Card.tsx +15 -0
- package/components/Card/Card.types.ts +3 -0
- package/components/Card/index.ts +2 -0
- package/components/Checkbox/Checkbox.tsx +122 -0
- package/components/Checkbox/Checkbox.types.ts +15 -0
- package/components/Checkbox/index.ts +2 -0
- package/components/Collapsible/Collapsible.tsx +34 -0
- package/components/Collapsible/Collapsible.types.ts +5 -0
- package/components/Collapsible/CollapsibleTrigger.tsx +57 -0
- package/components/Collapsible/CollapsibleTrigger.types.ts +14 -0
- package/components/Collapsible/index.ts +10 -0
- package/components/Container/Container.tsx +26 -0
- package/components/Container/Container.types.ts +3 -0
- package/components/Container/index.ts +2 -0
- package/components/ContextMenu/ContextMenu.tsx +74 -0
- package/components/ContextMenu/ContextMenu.types.ts +17 -0
- package/components/ContextMenu/index.ts +2 -0
- package/components/CreditCardExpirationInput/CreditCardExpirationInput.tsx +115 -0
- package/components/CreditCardExpirationInput/CreditCardExpirationInput.types.ts +10 -0
- package/components/CreditCardExpirationInput/index.ts +2 -0
- package/components/CreditCardInput/CreditCardInput.tsx +147 -0
- package/components/CreditCardInput/CreditCardInput.types.ts +12 -0
- package/components/CreditCardInput/index.ts +2 -0
- package/components/DateInput/DateInput.tsx +81 -0
- package/components/DateInput/DateInput.types.ts +15 -0
- package/components/DateInput/index.ts +2 -0
- package/components/DateTimeFormat/DateTimeFormat.tsx +16 -0
- package/components/DateTimeFormat/DateTimeFormat.types.ts +7 -0
- package/components/DateTimeFormat/index.ts +2 -0
- package/components/Dialog/Dialog.tsx +65 -0
- package/components/Dialog/Dialog.types.ts +9 -0
- package/components/Dialog/index.ts +2 -0
- package/components/DialogTrigger/DialogTrigger.tsx +45 -0
- package/components/DialogTrigger/DialogTrigger.types.ts +6 -0
- package/components/DialogTrigger/index.ts +5 -0
- package/components/Divider/Divider.stories.tsx +37 -0
- package/components/Divider/Divider.tsx +34 -0
- package/components/Divider/Divider.types.ts +5 -0
- package/components/Divider/index.ts +2 -0
- package/components/DobInput/DobInput.tsx +120 -0
- package/components/DobInput/index.ts +2 -0
- package/components/Drawer/Drawer.tsx +126 -0
- package/components/Drawer/Drawer.types.ts +11 -0
- package/components/Drawer/index.ts +2 -0
- package/components/Icon/Account.tsx +50 -0
- package/components/Icon/Cart.tsx +43 -0
- package/components/Icon/Checkmark.tsx +34 -0
- package/components/Icon/Cross.tsx +36 -0
- package/components/Icon/DownArrow.tsx +23 -0
- package/components/Icon/Hamburger.tsx +23 -0
- package/components/Icon/Icon.types.ts +8 -0
- package/components/Icon/LinkArrow.tsx +32 -0
- package/components/Icon/Minus.tsx +20 -0
- package/components/Icon/Plus.tsx +20 -0
- package/components/Icon/Search.tsx +36 -0
- package/components/Icon/Trash.tsx +27 -0
- package/components/Icon/Verified.tsx +20 -0
- package/components/Icon/index.ts +14 -0
- package/components/Image/Image.tsx +32 -0
- package/components/Image/index.ts +2 -0
- package/components/Input/Input.tsx +109 -0
- package/components/Input/Input.types.ts +17 -0
- package/components/Input/index.ts +2 -0
- package/components/Link/Link.stories.tsx +96 -0
- package/components/Link/Link.tsx +34 -0
- package/components/Link/Link.types.ts +3 -0
- package/components/Link/index.ts +2 -0
- package/components/Loader/CircularEasing.tsx +66 -0
- package/components/Loader/CircularEasing.types.ts +8 -0
- package/components/Loader/Pulse.tsx +45 -0
- package/components/Loader/Pulse.types.ts +5 -0
- package/components/Loader/index.ts +4 -0
- package/components/Menu/ContextMenu.tsx +83 -0
- package/components/Menu/Menu.tsx +143 -0
- package/components/Menu/Menu.types.ts +44 -0
- package/components/Menu/index.ts +4 -0
- package/components/Meter/Meter.stories.tsx +111 -0
- package/components/Meter/Meter.tsx +68 -0
- package/components/Meter/Meter.types.ts +10 -0
- package/components/Meter/index.ts +2 -0
- package/components/Modal/Modal.tsx +16 -0
- package/components/Modal/Modal.types.ts +6 -0
- package/components/Modal/index.ts +2 -0
- package/components/ModalOverlay/ModalOverlay.tsx +121 -0
- package/components/ModalOverlay/ModalOverlay.types.ts +18 -0
- package/components/ModalOverlay/index.ts +2 -0
- package/components/NumberFormat/NumberFormat.tsx +19 -0
- package/components/NumberFormat/NumberFormat.types.ts +8 -0
- package/components/NumberFormat/index.ts +2 -0
- package/components/NumberInput/NumberInput.tsx +164 -0
- package/components/NumberInput/NumberInput.types.ts +22 -0
- package/components/NumberInput/index.ts +2 -0
- package/components/NumberTicker/DigitResolver.tsx +119 -0
- package/components/NumberTicker/DigitResolver.types.ts +18 -0
- package/components/NumberTicker/NumberTicker.tsx +56 -0
- package/components/NumberTicker/NumberTicker.types.ts +96 -0
- package/components/NumberTicker/hooks/useColumnTransition.ts +36 -0
- package/components/NumberTicker/hooks/useNumberDelta.ts +19 -0
- package/components/NumberTicker/hooks/useNumberTicker.ts +36 -0
- package/components/NumberTicker/index.ts +10 -0
- package/components/Pagination/Pagination.tsx +44 -0
- package/components/Pagination/index.ts +2 -0
- package/components/PasswordCheck/PasswordCheck.tsx +59 -0
- package/components/PasswordCheck/PasswordCheck.types.ts +4 -0
- package/components/PasswordCheck/PasswordCheck.utils.ts +47 -0
- package/components/PasswordCheck/index.ts +2 -0
- package/components/PhoneInput/PhoneInput.tsx +191 -0
- package/components/PhoneInput/index.ts +2 -0
- package/components/PinInput/PinInput.tsx +314 -0
- package/components/PinInput/PinInput.types.ts +21 -0
- package/components/PinInput/index.ts +2 -0
- package/components/Progressbar/CircularProgressbar.tsx +71 -0
- package/components/Progressbar/CircularProgressbar.types.ts +10 -0
- package/components/Progressbar/LinearProgressbar.tsx +75 -0
- package/components/Progressbar/LinearProgressbar.types.ts +11 -0
- package/components/Progressbar/index.ts +4 -0
- package/components/Radio/Radio.tsx +88 -0
- package/components/Radio/Radio.types.ts +16 -0
- package/components/Radio/index.ts +2 -0
- package/components/RadioGroup/RadioGroup.tsx +49 -0
- package/components/RadioGroup/RadioGroup.types.ts +7 -0
- package/components/RadioGroup/index.ts +2 -0
- package/components/Select/Option.tsx +32 -0
- package/components/Select/Option.types.ts +3 -0
- package/components/Select/Select.tsx +253 -0
- package/components/Select/Select.types.ts +42 -0
- package/components/Select/index.ts +8 -0
- package/components/Skeleton/Skeleton.tsx +15 -0
- package/components/Skeleton/Skeleton.types.ts +3 -0
- package/components/Skeleton/index.ts +2 -0
- package/components/Slider/Slider.tsx +110 -0
- package/components/Slider/Slider.types.ts +11 -0
- package/components/Slider/index.ts +2 -0
- package/components/Switch/Switch.tsx +63 -0
- package/components/Switch/Switch.types.ts +8 -0
- package/components/Switch/index.ts +2 -0
- package/components/Table/Table.tsx +52 -0
- package/components/Table/Table.types.ts +22 -0
- package/components/Table/index.ts +2 -0
- package/components/Tabs/Tab.tsx +118 -0
- package/components/Tabs/Tab.types.ts +10 -0
- package/components/Tabs/TabList.tsx +51 -0
- package/components/Tabs/TabList.types.ts +12 -0
- package/components/Tabs/TabPanel.tsx +19 -0
- package/components/Tabs/TabPanel.types.ts +3 -0
- package/components/Tabs/Tabs.context.tsx +9 -0
- package/components/Tabs/Tabs.tsx +39 -0
- package/components/Tabs/Tabs.types.ts +3 -0
- package/components/Tabs/index.ts +9 -0
- package/components/TimeInput/TimeInput.stories.tsx +125 -0
- package/components/TimeInput/TimeInput.tsx +81 -0
- package/components/TimeInput/TimeInput.types.ts +15 -0
- package/components/TimeInput/index.ts +2 -0
- package/components/ToggleButton/ToggleButton.stories.tsx +89 -0
- package/components/ToggleButton/ToggleButton.tsx +69 -0
- package/components/ToggleButton/ToggleButton.types.ts +6 -0
- package/components/ToggleButton/index.ts +2 -0
- package/components/Tooltip/Tooltip.tsx +59 -0
- package/components/Tooltip/Tooltip.types.ts +3 -0
- package/components/Tooltip/index.ts +2 -0
- package/components/UploadImage/UploadImage.tsx +206 -0
- package/components/UploadImage/UploadImage.types.ts +15 -0
- package/components/UploadImage/index.ts +2 -0
- package/package.json +1 -1
- 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,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,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
|
+
};
|