@udixio/ui-react 2.9.5 → 2.9.7
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/CHANGELOG.md +38 -0
- package/dist/index.cjs +3 -3
- package/dist/index.js +3436 -2702
- package/dist/lib/components/Chip.d.ts.map +1 -1
- package/dist/lib/components/Chips.d.ts.map +1 -1
- package/dist/lib/components/Tab.d.ts +1 -1
- package/dist/lib/components/Tab.d.ts.map +1 -1
- package/dist/lib/components/TabGroup.d.ts +9 -0
- package/dist/lib/components/TabGroup.d.ts.map +1 -0
- package/dist/lib/components/TabGroupContext.d.ts +10 -0
- package/dist/lib/components/TabGroupContext.d.ts.map +1 -0
- package/dist/lib/components/TabPanel.d.ts +10 -0
- package/dist/lib/components/TabPanel.d.ts.map +1 -0
- package/dist/lib/components/TabPanels.d.ts +10 -0
- package/dist/lib/components/TabPanels.d.ts.map +1 -0
- package/dist/lib/components/Tabs.d.ts.map +1 -1
- package/dist/lib/components/index.d.ts +3 -0
- package/dist/lib/components/index.d.ts.map +1 -1
- package/dist/lib/effects/smooth-scroll.effect.d.ts +35 -11
- package/dist/lib/effects/smooth-scroll.effect.d.ts.map +1 -1
- package/dist/lib/interfaces/index.d.ts +2 -0
- package/dist/lib/interfaces/index.d.ts.map +1 -1
- package/dist/lib/interfaces/tab-group.interface.d.ts +13 -0
- package/dist/lib/interfaces/tab-group.interface.d.ts.map +1 -0
- package/dist/lib/interfaces/tab-panels.interface.d.ts +20 -0
- package/dist/lib/interfaces/tab-panels.interface.d.ts.map +1 -0
- package/dist/lib/interfaces/tab.interface.d.ts +2 -1
- package/dist/lib/interfaces/tab.interface.d.ts.map +1 -1
- package/dist/lib/styles/index.d.ts +1 -0
- package/dist/lib/styles/index.d.ts.map +1 -1
- package/dist/lib/styles/tab-panels.style.d.ts +31 -0
- package/dist/lib/styles/tab-panels.style.d.ts.map +1 -0
- package/dist/lib/styles/tab.style.d.ts +2 -0
- package/dist/lib/styles/tab.style.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/lib/components/Chip.tsx +2 -1
- package/src/lib/components/Chips.tsx +57 -16
- package/src/lib/components/Tab.tsx +5 -1
- package/src/lib/components/TabGroup.tsx +60 -0
- package/src/lib/components/TabGroupContext.tsx +11 -0
- package/src/lib/components/TabPanel.tsx +24 -0
- package/src/lib/components/TabPanels.tsx +71 -0
- package/src/lib/components/Tabs.tsx +17 -6
- package/src/lib/components/index.ts +3 -0
- package/src/lib/effects/smooth-scroll.effect.tsx +81 -125
- package/src/lib/interfaces/index.ts +2 -0
- package/src/lib/interfaces/tab-group.interface.ts +13 -0
- package/src/lib/interfaces/tab-panels.interface.ts +21 -0
- package/src/lib/interfaces/tab.interface.ts +2 -1
- package/src/lib/styles/index.ts +1 -0
- package/src/lib/styles/tab-panels.style.ts +35 -0
- package/src/stories/effect/smooth-scroll.stories.tsx +34 -25
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import React, { useContext } from 'react';
|
|
2
|
+
import { AnimatePresence, motion } from 'motion/react';
|
|
3
|
+
import { TabGroupContext } from './TabGroupContext';
|
|
4
|
+
import { TabPanelsInterface } from '../interfaces/tab-panels.interface';
|
|
5
|
+
import { ReactProps } from '../utils/component';
|
|
6
|
+
import { useTabPanelsStyle } from '../styles/tab-panels.style';
|
|
7
|
+
import { TabPanel } from './TabPanel';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* TabPanels renders the content panels with slide animation
|
|
11
|
+
* Must be used within a TabGroup
|
|
12
|
+
* @status beta
|
|
13
|
+
* @category Navigation
|
|
14
|
+
*/
|
|
15
|
+
export const TabPanels = ({
|
|
16
|
+
children,
|
|
17
|
+
className,
|
|
18
|
+
}: ReactProps<TabPanelsInterface>) => {
|
|
19
|
+
const context = useContext(TabGroupContext);
|
|
20
|
+
|
|
21
|
+
if (!context) {
|
|
22
|
+
console.warn('TabPanels must be used within a TabGroup');
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const { selectedTab, direction, tabsId } = context;
|
|
27
|
+
|
|
28
|
+
const panelChildren = React.Children.toArray(children).filter(
|
|
29
|
+
(child) => React.isValidElement(child) && child.type === TabPanel,
|
|
30
|
+
) as React.ReactElement[];
|
|
31
|
+
|
|
32
|
+
const styles = useTabPanelsStyle({
|
|
33
|
+
children,
|
|
34
|
+
className,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div className={styles.tabPanels}>
|
|
39
|
+
<AnimatePresence initial={false} custom={direction} mode="popLayout">
|
|
40
|
+
{panelChildren.map(
|
|
41
|
+
(child, index) =>
|
|
42
|
+
selectedTab === index && (
|
|
43
|
+
<motion.div
|
|
44
|
+
key={index}
|
|
45
|
+
custom={direction}
|
|
46
|
+
variants={{
|
|
47
|
+
enter: (dir: number) => ({
|
|
48
|
+
x: dir * 100 + '%',
|
|
49
|
+
opacity: 1,
|
|
50
|
+
}),
|
|
51
|
+
center: { x: 0, opacity: 1 },
|
|
52
|
+
exit: (dir: number) => ({
|
|
53
|
+
x: dir * -100 + '%',
|
|
54
|
+
opacity: 1,
|
|
55
|
+
}),
|
|
56
|
+
}}
|
|
57
|
+
initial="enter"
|
|
58
|
+
animate="center"
|
|
59
|
+
exit="exit"
|
|
60
|
+
transition={{ type: 'spring', stiffness: 400, damping: 40 }}
|
|
61
|
+
role="tabpanel"
|
|
62
|
+
aria-labelledby={`tab-${tabsId}-${index}`}
|
|
63
|
+
>
|
|
64
|
+
{React.cloneElement(child, { isSelected: true })}
|
|
65
|
+
</motion.div>
|
|
66
|
+
),
|
|
67
|
+
)}
|
|
68
|
+
</AnimatePresence>
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useMemo, useState } from 'react';
|
|
1
|
+
import React, { useContext, useMemo, useState } from 'react';
|
|
2
2
|
import { v4 as uuidv4 } from 'uuid';
|
|
3
3
|
import { TabsInterface } from '../interfaces/tabs.interface';
|
|
4
4
|
|
|
@@ -6,6 +6,7 @@ import { useTabsStyle } from '../styles/tabs.style';
|
|
|
6
6
|
import { ReactProps } from '../utils/component';
|
|
7
7
|
import { TabProps } from '../interfaces/tab.interface';
|
|
8
8
|
import { Tab } from './Tab';
|
|
9
|
+
import { TabGroupContext } from './TabGroupContext';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Tabs organize content across different screens and views
|
|
@@ -21,22 +22,28 @@ export const Tabs = ({
|
|
|
21
22
|
setSelectedTab: externalSetSelectedTab,
|
|
22
23
|
scrollable = false,
|
|
23
24
|
}: ReactProps<TabsInterface>) => {
|
|
25
|
+
const tabGroupContext = useContext(TabGroupContext);
|
|
26
|
+
|
|
24
27
|
const [internalSelectedTab, internalSetSelectedTab] = useState<number | null>(
|
|
25
28
|
null,
|
|
26
29
|
);
|
|
27
30
|
|
|
31
|
+
// Priorité : props > context > état interne
|
|
28
32
|
let selectedTab: number | null;
|
|
29
|
-
if (externalSelectedTab
|
|
33
|
+
if (externalSelectedTab === 0 || externalSelectedTab != undefined) {
|
|
30
34
|
selectedTab = externalSelectedTab;
|
|
35
|
+
} else if (tabGroupContext) {
|
|
36
|
+
selectedTab = tabGroupContext.selectedTab;
|
|
31
37
|
} else {
|
|
32
38
|
selectedTab = internalSelectedTab;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
|
-
const setSelectedTab =
|
|
41
|
+
const setSelectedTab =
|
|
42
|
+
externalSetSelectedTab ?? tabGroupContext?.setSelectedTab ?? internalSetSelectedTab;
|
|
36
43
|
|
|
37
44
|
const tabChildren = React.Children.toArray(children).filter(
|
|
38
45
|
(child) => React.isValidElement(child) && child.type === Tab,
|
|
39
|
-
);
|
|
46
|
+
) as React.ReactElement<TabProps>[];
|
|
40
47
|
|
|
41
48
|
const ref = React.useRef<HTMLDivElement | null>(null);
|
|
42
49
|
|
|
@@ -60,7 +67,10 @@ export const Tabs = ({
|
|
|
60
67
|
}
|
|
61
68
|
};
|
|
62
69
|
|
|
63
|
-
const tabsId = useMemo(
|
|
70
|
+
const tabsId = useMemo(
|
|
71
|
+
() => tabGroupContext?.tabsId ?? uuidv4(),
|
|
72
|
+
[tabGroupContext?.tabsId],
|
|
73
|
+
);
|
|
64
74
|
|
|
65
75
|
const styles = useTabsStyle({
|
|
66
76
|
children,
|
|
@@ -71,10 +81,11 @@ export const Tabs = ({
|
|
|
71
81
|
className,
|
|
72
82
|
variant,
|
|
73
83
|
});
|
|
84
|
+
|
|
74
85
|
return (
|
|
75
86
|
<div ref={ref} role="tablist" className={styles.tabs}>
|
|
76
87
|
{tabChildren.map((child, index) => {
|
|
77
|
-
return React.cloneElement(child
|
|
88
|
+
return React.cloneElement(child, {
|
|
78
89
|
key: index,
|
|
79
90
|
index,
|
|
80
91
|
variant: variant,
|
|
@@ -17,6 +17,9 @@ export * from './Snackbar';
|
|
|
17
17
|
export * from './Switch';
|
|
18
18
|
export * from './Tab';
|
|
19
19
|
export * from './Tabs';
|
|
20
|
+
export * from './TabGroup';
|
|
21
|
+
export * from './TabPanels';
|
|
22
|
+
export * from './TabPanel';
|
|
20
23
|
export * from './TextField';
|
|
21
24
|
export * from './NavigationRailItem';
|
|
22
25
|
export * from './NavigationRail';
|
|
@@ -1,142 +1,98 @@
|
|
|
1
|
-
import { useEffect, useRef,
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { useEffect, useRef, ReactNode } from 'react';
|
|
2
|
+
import Lenis from 'lenis';
|
|
3
|
+
|
|
4
|
+
export type SmoothScrollProps = {
|
|
5
|
+
/**
|
|
6
|
+
* Duration of the scroll animation in seconds or as a CSS string (e.g., '1s', '500ms').
|
|
7
|
+
* Default: 1.2
|
|
8
|
+
*/
|
|
9
|
+
transition?: number | string;
|
|
10
|
+
/**
|
|
11
|
+
* Easing function for the scroll animation.
|
|
12
|
+
* Default: easeOutQuint
|
|
13
|
+
*/
|
|
14
|
+
easing?: (t: number) => number;
|
|
15
|
+
/**
|
|
16
|
+
* Scroll orientation.
|
|
17
|
+
* Default: 'vertical'
|
|
18
|
+
*/
|
|
19
|
+
orientation?: 'vertical' | 'horizontal';
|
|
20
|
+
/**
|
|
21
|
+
* Enable smooth scrolling on touch devices.
|
|
22
|
+
* Default: false (native touch scrolling is usually preferred)
|
|
23
|
+
*/
|
|
24
|
+
smoothTouch?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Multiplier for touch scroll sensitivity.
|
|
27
|
+
* Default: 2
|
|
28
|
+
*/
|
|
29
|
+
touchMultiplier?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Children elements (optional, component works at document level)
|
|
32
|
+
*/
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
};
|
|
6
35
|
|
|
7
36
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Rework it later (e.g., via Lenis or another solution) before using it in production.
|
|
37
|
+
* SmoothScroll component using Lenis for smooth scrolling.
|
|
38
|
+
* This component enables smooth scrolling at the document level.
|
|
11
39
|
*/
|
|
12
40
|
export const SmoothScroll = ({
|
|
13
|
-
transition,
|
|
41
|
+
transition = 1.2,
|
|
42
|
+
easing,
|
|
14
43
|
orientation = 'vertical',
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
| 'easeOut'
|
|
22
|
-
| 'easeInOut'
|
|
23
|
-
| 'circIn'
|
|
24
|
-
| 'circOut'
|
|
25
|
-
| 'circInOut'
|
|
26
|
-
| 'backIn'
|
|
27
|
-
| 'backOut'
|
|
28
|
-
| 'backInOut'
|
|
29
|
-
| 'anticipate'
|
|
30
|
-
| ((t: number) => number);
|
|
31
|
-
duration?: number;
|
|
32
|
-
};
|
|
33
|
-
} & ReactProps<CustomScrollInterface>) => {
|
|
34
|
-
// Target value (instant), driven by wheel/touch/keyboard or native scroll sync
|
|
35
|
-
const [scrollY, setScrollY] = useState(0);
|
|
36
|
-
|
|
37
|
-
const [el, setEl] = useState<HTMLHtmlElement>();
|
|
38
|
-
|
|
39
|
-
const isScrolling = useRef(false);
|
|
40
|
-
const scrollTimeoutRef = useRef<NodeJS.Timeout>();
|
|
41
|
-
const lastAppliedYRef = useRef(0);
|
|
42
|
-
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
setEl(document as unknown as HTMLHtmlElement);
|
|
45
|
-
const y = document.documentElement.scrollTop;
|
|
46
|
-
setScrollY(y);
|
|
47
|
-
lastAppliedYRef.current = y;
|
|
48
|
-
}, []);
|
|
44
|
+
smoothTouch = false,
|
|
45
|
+
touchMultiplier = 2,
|
|
46
|
+
children,
|
|
47
|
+
}: SmoothScrollProps) => {
|
|
48
|
+
const lenisRef = useRef<Lenis | null>(null);
|
|
49
|
+
const rafRef = useRef<number | null>(null);
|
|
49
50
|
|
|
50
|
-
// Sync native scroll (e.g., scrollbar, programmatic) back to target after a small delay
|
|
51
51
|
useEffect(() => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// Drive the spring when target changes
|
|
65
|
-
const currentY = useRef<number | null>();
|
|
66
|
-
const animationRef = useRef<AnimationPlaybackControls | null>(null);
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
const y = scrollY;
|
|
69
|
-
|
|
70
|
-
if (animationRef.current) {
|
|
71
|
-
animationRef.current.stop();
|
|
72
|
-
animationRef.current = null;
|
|
52
|
+
// Parse duration from string if needed (e.g., '1s' -> 1, '500ms' -> 0.5)
|
|
53
|
+
let duration: number;
|
|
54
|
+
if (typeof transition === 'string') {
|
|
55
|
+
if (transition.endsWith('ms')) {
|
|
56
|
+
duration = parseFloat(transition) / 1000;
|
|
57
|
+
} else if (transition.endsWith('s')) {
|
|
58
|
+
duration = parseFloat(transition);
|
|
59
|
+
} else {
|
|
60
|
+
duration = parseFloat(transition) || 1.2;
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
duration = transition;
|
|
73
64
|
}
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
duration
|
|
81
|
-
|
|
66
|
+
// Default easing: easeOutQuint
|
|
67
|
+
const defaultEasing = (t: number) => 1 - Math.pow(1 - t, 5);
|
|
68
|
+
|
|
69
|
+
// Initialize Lenis
|
|
70
|
+
lenisRef.current = new Lenis({
|
|
71
|
+
duration,
|
|
72
|
+
easing: easing ?? defaultEasing,
|
|
73
|
+
orientation,
|
|
74
|
+
smoothWheel: true,
|
|
75
|
+
touchMultiplier,
|
|
76
|
+
syncTouch: smoothTouch,
|
|
77
|
+
});
|
|
82
78
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
// Animation frame loop
|
|
80
|
+
const raf = (time: number) => {
|
|
81
|
+
lenisRef.current?.raf(time);
|
|
82
|
+
rafRef.current = requestAnimationFrame(raf);
|
|
83
|
+
};
|
|
88
84
|
|
|
89
|
-
|
|
90
|
-
// Avoid micro-movements causing extra layout work
|
|
91
|
-
const rounded = Math.round(value * 1000) / 1000;
|
|
92
|
-
const last = lastAppliedYRef.current;
|
|
93
|
-
if (Math.abs(rounded - last) < 0.1) return;
|
|
94
|
-
lastAppliedYRef.current = rounded;
|
|
85
|
+
rafRef.current = requestAnimationFrame(raf);
|
|
95
86
|
|
|
96
|
-
|
|
97
|
-
html.scrollTo({ top: rounded });
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
onComplete: () => {
|
|
101
|
-
scrollTimeoutRef.current = setTimeout(() => {
|
|
102
|
-
isScrolling.current = false;
|
|
103
|
-
}, 300);
|
|
104
|
-
animationRef.current = null;
|
|
105
|
-
},
|
|
106
|
-
});
|
|
87
|
+
// Cleanup
|
|
107
88
|
return () => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
animationRef.current.stop();
|
|
111
|
-
animationRef.current = null;
|
|
89
|
+
if (rafRef.current !== null) {
|
|
90
|
+
cancelAnimationFrame(rafRef.current);
|
|
112
91
|
}
|
|
92
|
+
lenisRef.current?.destroy();
|
|
93
|
+
lenisRef.current = null;
|
|
113
94
|
};
|
|
114
|
-
}, [
|
|
115
|
-
|
|
116
|
-
if (!el) return null;
|
|
117
|
-
|
|
118
|
-
return (
|
|
119
|
-
<BlockScroll
|
|
120
|
-
touch={false}
|
|
121
|
-
el={el as unknown as HTMLElement}
|
|
122
|
-
onScroll={(scroll) => {
|
|
123
|
-
if (
|
|
124
|
-
'deltaY' in scroll &&
|
|
125
|
-
scroll.deltaY !== 0 &&
|
|
126
|
-
el &&
|
|
127
|
-
scrollY !== null
|
|
128
|
-
) {
|
|
129
|
-
let y = scrollY + scroll.deltaY;
|
|
130
|
-
const html = el.querySelector('html');
|
|
131
|
-
if (html) {
|
|
132
|
-
y = Math.min(y, html.scrollHeight - html.clientHeight);
|
|
133
|
-
}
|
|
134
|
-
y = Math.max(y, 0);
|
|
135
|
-
setScrollY(y);
|
|
95
|
+
}, [transition, easing, orientation, smoothTouch, touchMultiplier]);
|
|
136
96
|
|
|
137
|
-
|
|
138
|
-
}
|
|
139
|
-
}}
|
|
140
|
-
></BlockScroll>
|
|
141
|
-
);
|
|
97
|
+
return children ? <>{children}</> : null;
|
|
142
98
|
};
|
|
@@ -15,6 +15,8 @@ export * from './snackbar.interface';
|
|
|
15
15
|
export * from './switch.interface';
|
|
16
16
|
export * from './tab.interface';
|
|
17
17
|
export * from './tabs.interface';
|
|
18
|
+
export * from './tab-group.interface';
|
|
19
|
+
export * from './tab-panels.interface';
|
|
18
20
|
export * from './text-field.interface';
|
|
19
21
|
export * from './navigation-rail-item.interface';
|
|
20
22
|
export * from './tooltip.interface';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Dispatch, ReactNode, SetStateAction } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface TabGroupInterface {
|
|
4
|
+
type: 'div';
|
|
5
|
+
props: {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
selectedTab?: number | null;
|
|
8
|
+
setSelectedTab?: Dispatch<SetStateAction<number | null>>;
|
|
9
|
+
defaultTab?: number;
|
|
10
|
+
};
|
|
11
|
+
states: object;
|
|
12
|
+
elements: ['tabGroup'];
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface TabPanelsInterface {
|
|
4
|
+
type: 'div';
|
|
5
|
+
props: {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
};
|
|
8
|
+
states: object;
|
|
9
|
+
elements: ['tabPanels'];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface TabPanelInterface {
|
|
13
|
+
type: 'div';
|
|
14
|
+
props: {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
};
|
|
17
|
+
states: {
|
|
18
|
+
isSelected: boolean;
|
|
19
|
+
};
|
|
20
|
+
elements: ['tabPanel'];
|
|
21
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ActionOrLink } from '../utils/component';
|
|
2
2
|
import { TabsVariant } from './tabs.interface';
|
|
3
|
-
import { Dispatch, RefObject, SetStateAction } from 'react';
|
|
3
|
+
import { Dispatch, ReactNode, RefObject, SetStateAction } from 'react';
|
|
4
4
|
import { Icon } from '../icon';
|
|
5
5
|
|
|
6
6
|
export type TabProps = {
|
|
@@ -18,6 +18,7 @@ export type TabProps = {
|
|
|
18
18
|
) => void;
|
|
19
19
|
index?: number;
|
|
20
20
|
scrollable?: boolean;
|
|
21
|
+
children?: ReactNode;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
type Elements = ['tab', 'stateLayer', 'icon', 'label', 'content', 'underline'];
|
package/src/lib/styles/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ export * from './snackbar.style';
|
|
|
15
15
|
export * from './switch.style';
|
|
16
16
|
export * from './tab.style';
|
|
17
17
|
export * from './tabs.style';
|
|
18
|
+
export * from './tab-panels.style';
|
|
18
19
|
export * from './text-field.style';
|
|
19
20
|
export * from './tooltip.style';
|
|
20
21
|
export { useButtonStyle } from './button.style';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { TabPanelsInterface, TabPanelInterface } from '../interfaces';
|
|
2
|
+
import {
|
|
3
|
+
type ClassNameComponent,
|
|
4
|
+
classNames,
|
|
5
|
+
createUseClassNames,
|
|
6
|
+
defaultClassNames,
|
|
7
|
+
} from '../utils';
|
|
8
|
+
|
|
9
|
+
const tabPanelsConfig: ClassNameComponent<TabPanelsInterface> = () => ({
|
|
10
|
+
tabPanels: classNames('overflow-hidden'),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const tabPanelsStyle = defaultClassNames<TabPanelsInterface>(
|
|
14
|
+
'tabPanels',
|
|
15
|
+
tabPanelsConfig,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export const useTabPanelsStyle = createUseClassNames<TabPanelsInterface>(
|
|
19
|
+
'tabPanels',
|
|
20
|
+
tabPanelsConfig,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const tabPanelConfig: ClassNameComponent<TabPanelInterface> = () => ({
|
|
24
|
+
tabPanel: classNames(''),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const tabPanelStyle = defaultClassNames<TabPanelInterface>(
|
|
28
|
+
'tabPanel',
|
|
29
|
+
tabPanelConfig,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export const useTabPanelStyle = createUseClassNames<TabPanelInterface>(
|
|
33
|
+
'tabPanel',
|
|
34
|
+
tabPanelConfig,
|
|
35
|
+
);
|
|
@@ -2,42 +2,51 @@ import type { Meta, StoryObj } from '@storybook/react';
|
|
|
2
2
|
import { SmoothScroll } from '../../';
|
|
3
3
|
import { JSX } from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
|
-
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
|
|
6
5
|
const meta = {
|
|
7
6
|
title: 'effect/SmoothScroll',
|
|
8
7
|
component: SmoothScroll,
|
|
9
|
-
parameters: {
|
|
10
|
-
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
|
|
11
|
-
},
|
|
12
|
-
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
|
|
8
|
+
parameters: {},
|
|
13
9
|
tags: ['autodocs'],
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
argTypes: {
|
|
11
|
+
transition: {
|
|
12
|
+
control: { type: 'text' },
|
|
13
|
+
description: 'Duration of the scroll animation (e.g., "1s", "500ms", or number in seconds)',
|
|
14
|
+
},
|
|
15
|
+
orientation: {
|
|
16
|
+
control: { type: 'select' },
|
|
17
|
+
options: ['vertical', 'horizontal'],
|
|
18
|
+
},
|
|
19
|
+
smoothTouch: {
|
|
20
|
+
control: { type: 'boolean' },
|
|
21
|
+
description: 'Enable smooth scrolling on touch devices',
|
|
22
|
+
},
|
|
23
|
+
touchMultiplier: {
|
|
24
|
+
control: { type: 'number' },
|
|
25
|
+
description: 'Multiplier for touch scroll sensitivity',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
16
28
|
} satisfies Meta<typeof SmoothScroll>;
|
|
17
29
|
|
|
18
30
|
export default meta;
|
|
19
31
|
type Story = StoryObj<typeof meta>;
|
|
20
32
|
|
|
21
|
-
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
|
22
|
-
|
|
23
33
|
const createSmoothScrollStory = () => {
|
|
24
34
|
const SmoothScrollStory: () => JSX.Element = () => (
|
|
25
|
-
|
|
26
|
-
<SmoothScroll transition=
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
</div>
|
|
35
|
+
<>
|
|
36
|
+
<SmoothScroll transition="1s" />
|
|
37
|
+
<div className="h-52 bg-primary" />
|
|
38
|
+
<div className="h-52 bg-secondary" />
|
|
39
|
+
<div className="h-52 bg-tertiary" />
|
|
40
|
+
<div className="h-52 bg-primary" />
|
|
41
|
+
<div className="h-52 bg-secondary" />
|
|
42
|
+
<div className="h-52 bg-tertiary" />
|
|
43
|
+
<div className="h-52 bg-primary" />
|
|
44
|
+
<div className="h-52 bg-secondary" />
|
|
45
|
+
<div className="h-52 bg-tertiary" />
|
|
46
|
+
<div className="h-52 bg-primary" />
|
|
47
|
+
<div className="h-52 bg-secondary" />
|
|
48
|
+
<div className="h-52 bg-tertiary" />
|
|
49
|
+
</>
|
|
41
50
|
);
|
|
42
51
|
|
|
43
52
|
return SmoothScrollStory;
|