@shohojdhara/atomix 0.2.6 → 0.2.8
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 +4 -0
- package/README.md +3 -3
- package/dist/atomix.css +373 -55
- package/dist/atomix.min.css +2 -2
- package/dist/index.d.ts +458 -19
- package/dist/index.esm.js +975 -261
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +984 -261
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/themes/applemix.css +373 -55
- package/dist/themes/applemix.min.css +2 -2
- package/dist/themes/boomdevs.css +372 -54
- package/dist/themes/boomdevs.min.css +2 -2
- package/dist/themes/esrar.css +373 -55
- package/dist/themes/esrar.min.css +2 -2
- package/dist/themes/flashtrade.css +1776 -612
- package/dist/themes/flashtrade.min.css +113 -7
- package/dist/themes/mashroom.css +372 -54
- package/dist/themes/mashroom.min.css +2 -2
- package/dist/themes/shaj-default.css +372 -54
- package/dist/themes/shaj-default.min.css +2 -2
- package/package.json +1 -1
- package/src/components/Button/Button.stories.tsx +199 -0
- package/src/components/Button/Button.tsx +238 -78
- package/src/components/Card/Card.stories.tsx +202 -0
- package/src/components/Card/Card.tsx +248 -77
- package/src/components/Form/Input.stories.tsx +228 -2
- package/src/components/Hero/Hero.stories.tsx +297 -0
- package/src/components/Hero/Hero.tsx +79 -0
- package/src/components/{Tab/Tab.stories.tsx → Tabs/Tabs.stories.tsx} +9 -9
- package/src/components/{Tab/Tab.tsx → Tabs/Tabs.tsx} +7 -7
- package/src/components/Tabs/index.ts +2 -0
- package/src/components/Tooltip/Tooltip.tsx +68 -66
- package/src/components/index.ts +12 -2
- package/src/lib/composables/useButton.ts +37 -5
- package/src/lib/composables/useHero.ts +33 -4
- package/src/lib/composables/useHeroBackgroundSlider.ts +228 -0
- package/src/lib/composables/useInput.ts +39 -1
- package/src/lib/constants/components.ts +59 -0
- package/src/lib/types/components.ts +376 -4
- package/src/styles/01-settings/_settings.tooltip.scss +2 -2
- package/src/styles/06-components/_components.button.scss +100 -0
- package/src/styles/06-components/_components.card.scss +219 -1
- package/src/styles/06-components/_components.hero.scss +51 -1
- package/src/styles/06-components/_components.tooltip.scss +89 -66
- package/src/components/Tab/index.ts +0 -2
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useState, useCallback, useMemo } from 'react';
|
|
2
|
+
import { HeroBackgroundSliderConfig } from '../types/components';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook result interface for hero background slider
|
|
6
|
+
*/
|
|
7
|
+
export interface UseHeroBackgroundSliderResult {
|
|
8
|
+
/**
|
|
9
|
+
* Current active slide index
|
|
10
|
+
*/
|
|
11
|
+
currentIndex: number;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Whether a transition is currently in progress
|
|
15
|
+
*/
|
|
16
|
+
isTransitioning: boolean;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Array of refs for slide container elements
|
|
20
|
+
*/
|
|
21
|
+
slideRefs: React.RefObject<HTMLDivElement>[];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Array of refs for video elements
|
|
25
|
+
*/
|
|
26
|
+
videoRefs: React.RefObject<HTMLVideoElement>[];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handle slide transition to next index
|
|
30
|
+
*/
|
|
31
|
+
handleSlideTransition: (nextIndex: number) => void;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Pause autoplay
|
|
35
|
+
*/
|
|
36
|
+
pauseAutoplay: () => void;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resume autoplay
|
|
40
|
+
*/
|
|
41
|
+
resumeAutoplay: () => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Hook for Hero background slider functionality
|
|
46
|
+
* @param config - Background slider configuration
|
|
47
|
+
* @returns Slider state and methods
|
|
48
|
+
*/
|
|
49
|
+
export function useHeroBackgroundSlider(
|
|
50
|
+
config: HeroBackgroundSliderConfig
|
|
51
|
+
): UseHeroBackgroundSliderResult {
|
|
52
|
+
const {
|
|
53
|
+
slides,
|
|
54
|
+
autoplay,
|
|
55
|
+
loop = true,
|
|
56
|
+
transition = 'fade',
|
|
57
|
+
transitionDuration = 1000,
|
|
58
|
+
} = config;
|
|
59
|
+
|
|
60
|
+
const [currentIndex, setCurrentIndex] = useState(0);
|
|
61
|
+
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
62
|
+
const autoplayRef = useRef<NodeJS.Timeout | null>(null);
|
|
63
|
+
const isPausedRef = useRef(false);
|
|
64
|
+
|
|
65
|
+
// Create refs for slide containers
|
|
66
|
+
const slideRefs = useMemo(
|
|
67
|
+
() => slides.map(() => React.createRef<HTMLDivElement>()),
|
|
68
|
+
[slides.length]
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Create refs for video elements
|
|
72
|
+
const videoRefs = useMemo(
|
|
73
|
+
() => slides.map(() => React.createRef<HTMLVideoElement>()),
|
|
74
|
+
[slides.length]
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Handle slide transition
|
|
79
|
+
*/
|
|
80
|
+
const handleSlideTransition = useCallback(
|
|
81
|
+
(nextIndex: number) => {
|
|
82
|
+
if (nextIndex === currentIndex || isTransitioning) return;
|
|
83
|
+
if (nextIndex < 0 || nextIndex >= slides.length) return;
|
|
84
|
+
|
|
85
|
+
setIsTransitioning(true);
|
|
86
|
+
|
|
87
|
+
// Update current index
|
|
88
|
+
setCurrentIndex(nextIndex);
|
|
89
|
+
|
|
90
|
+
// Play video if it's a video slide
|
|
91
|
+
const currentVideo = videoRefs[nextIndex]?.current;
|
|
92
|
+
if (currentVideo && slides[nextIndex].type === 'video') {
|
|
93
|
+
const videoOptions = slides[nextIndex].videoOptions || {};
|
|
94
|
+
if (videoOptions.autoplay !== false) {
|
|
95
|
+
currentVideo.play().catch(() => {
|
|
96
|
+
// Ignore autoplay errors
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Pause previous video if it exists
|
|
102
|
+
const prevVideo = videoRefs[currentIndex]?.current;
|
|
103
|
+
if (prevVideo && slides[currentIndex].type === 'video') {
|
|
104
|
+
prevVideo.pause();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Reset transitioning state after transition duration
|
|
108
|
+
setTimeout(() => {
|
|
109
|
+
setIsTransitioning(false);
|
|
110
|
+
}, transitionDuration);
|
|
111
|
+
},
|
|
112
|
+
[currentIndex, isTransitioning, slides, videoRefs, transitionDuration]
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Move to next slide
|
|
117
|
+
*/
|
|
118
|
+
const nextSlide = useCallback(() => {
|
|
119
|
+
if (slides.length === 0) return;
|
|
120
|
+
|
|
121
|
+
let nextIndex: number;
|
|
122
|
+
if (loop) {
|
|
123
|
+
nextIndex = (currentIndex + 1) % slides.length;
|
|
124
|
+
} else {
|
|
125
|
+
nextIndex = Math.min(currentIndex + 1, slides.length - 1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
handleSlideTransition(nextIndex);
|
|
129
|
+
}, [currentIndex, slides.length, loop, handleSlideTransition]);
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Pause autoplay
|
|
133
|
+
*/
|
|
134
|
+
const pauseAutoplay = useCallback(() => {
|
|
135
|
+
isPausedRef.current = true;
|
|
136
|
+
if (autoplayRef.current) {
|
|
137
|
+
clearInterval(autoplayRef.current);
|
|
138
|
+
autoplayRef.current = null;
|
|
139
|
+
}
|
|
140
|
+
}, []);
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Resume autoplay
|
|
144
|
+
*/
|
|
145
|
+
const resumeAutoplay = useCallback(() => {
|
|
146
|
+
if (isPausedRef.current && autoplay && slides.length > 1) {
|
|
147
|
+
isPausedRef.current = false;
|
|
148
|
+
const delay = typeof autoplay === 'object' ? autoplay.delay : 3000;
|
|
149
|
+
|
|
150
|
+
// Restart autoplay
|
|
151
|
+
if (!autoplayRef.current) {
|
|
152
|
+
autoplayRef.current = setInterval(() => {
|
|
153
|
+
if (!isPausedRef.current && !isTransitioning) {
|
|
154
|
+
nextSlide();
|
|
155
|
+
}
|
|
156
|
+
}, delay);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}, [autoplay, slides.length, nextSlide, isTransitioning]);
|
|
160
|
+
|
|
161
|
+
// Autoplay effect
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (!autoplay || slides.length <= 1) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const delay = typeof autoplay === 'object' ? autoplay.delay : 3000;
|
|
168
|
+
const pauseOnHover = typeof autoplay === 'object' ? autoplay.pauseOnHover : false;
|
|
169
|
+
|
|
170
|
+
// Clear any existing interval
|
|
171
|
+
if (autoplayRef.current) {
|
|
172
|
+
clearInterval(autoplayRef.current);
|
|
173
|
+
autoplayRef.current = null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Start autoplay if not paused
|
|
177
|
+
if (!isPausedRef.current) {
|
|
178
|
+
autoplayRef.current = setInterval(() => {
|
|
179
|
+
if (!isPausedRef.current && !isTransitioning) {
|
|
180
|
+
nextSlide();
|
|
181
|
+
}
|
|
182
|
+
}, delay);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return () => {
|
|
186
|
+
if (autoplayRef.current) {
|
|
187
|
+
clearInterval(autoplayRef.current);
|
|
188
|
+
autoplayRef.current = null;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}, [autoplay, slides.length, nextSlide, isTransitioning]);
|
|
192
|
+
|
|
193
|
+
// Initialize first video if needed
|
|
194
|
+
useEffect(() => {
|
|
195
|
+
if (slides.length > 0 && slides[currentIndex]?.type === 'video') {
|
|
196
|
+
const video = videoRefs[currentIndex]?.current;
|
|
197
|
+
if (video) {
|
|
198
|
+
const videoOptions = slides[currentIndex].videoOptions || {};
|
|
199
|
+
if (videoOptions.autoplay !== false) {
|
|
200
|
+
video.play().catch(() => {
|
|
201
|
+
// Ignore autoplay errors
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}, [currentIndex, slides, videoRefs]);
|
|
207
|
+
|
|
208
|
+
// Cleanup on unmount
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
return () => {
|
|
211
|
+
if (autoplayRef.current) {
|
|
212
|
+
clearInterval(autoplayRef.current);
|
|
213
|
+
autoplayRef.current = null;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}, []);
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
currentIndex,
|
|
220
|
+
isTransitioning,
|
|
221
|
+
slideRefs,
|
|
222
|
+
videoRefs,
|
|
223
|
+
handleSlideTransition,
|
|
224
|
+
pauseAutoplay,
|
|
225
|
+
resumeAutoplay,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
@@ -6,7 +6,14 @@ import { INPUT } from '../constants/components';
|
|
|
6
6
|
* @param initialProps - Initial input properties
|
|
7
7
|
* @returns Input state and methods
|
|
8
8
|
*/
|
|
9
|
-
export function useInput(initialProps?: Partial<InputProps>
|
|
9
|
+
export function useInput(initialProps?: Partial<InputProps> & {
|
|
10
|
+
prefixIcon?: boolean;
|
|
11
|
+
suffixIcon?: boolean;
|
|
12
|
+
clearable?: boolean;
|
|
13
|
+
showCounter?: boolean;
|
|
14
|
+
showPasswordToggle?: boolean;
|
|
15
|
+
fullWidth?: boolean;
|
|
16
|
+
}) {
|
|
10
17
|
// Default input properties
|
|
11
18
|
const defaultProps: Partial<InputProps> = {
|
|
12
19
|
size: 'md',
|
|
@@ -51,8 +58,39 @@ export function useInput(initialProps?: Partial<InputProps>) {
|
|
|
51
58
|
return `${INPUT.CLASSES.BASE} ${sizeClass} ${variantClass} ${textareaClass} ${validationClass} ${disabledClass} ${className}`.trim();
|
|
52
59
|
};
|
|
53
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Generate wrapper class based on properties
|
|
63
|
+
* @param props - Wrapper properties
|
|
64
|
+
* @returns Class string
|
|
65
|
+
*/
|
|
66
|
+
const generateWrapperClass = (props: { className?: string }): string => {
|
|
67
|
+
const { className = '' } = props;
|
|
68
|
+
const {
|
|
69
|
+
prefixIcon = false,
|
|
70
|
+
suffixIcon = false,
|
|
71
|
+
clearable = false,
|
|
72
|
+
showCounter = false,
|
|
73
|
+
showPasswordToggle = false,
|
|
74
|
+
fullWidth = false,
|
|
75
|
+
} = initialProps || {};
|
|
76
|
+
|
|
77
|
+
const classes = [INPUT.ELEMENTS.WRAPPER];
|
|
78
|
+
|
|
79
|
+
if (prefixIcon) classes.push(INPUT.CLASSES.PREFIX_ICON);
|
|
80
|
+
if (suffixIcon || clearable || showPasswordToggle) classes.push(INPUT.CLASSES.SUFFIX_ICON);
|
|
81
|
+
if (clearable) classes.push(INPUT.CLASSES.CLEARABLE);
|
|
82
|
+
if (showCounter) classes.push(INPUT.CLASSES.WITH_COUNTER);
|
|
83
|
+
if (showPasswordToggle) classes.push(INPUT.CLASSES.PASSWORD_TOGGLE);
|
|
84
|
+
if (fullWidth) classes.push(INPUT.CLASSES.FULL_WIDTH);
|
|
85
|
+
|
|
86
|
+
if (className) classes.push(className);
|
|
87
|
+
|
|
88
|
+
return classes.filter(Boolean).join(' ');
|
|
89
|
+
};
|
|
90
|
+
|
|
54
91
|
return {
|
|
55
92
|
defaultProps,
|
|
56
93
|
generateInputClass,
|
|
94
|
+
generateWrapperClass,
|
|
57
95
|
};
|
|
58
96
|
}
|
|
@@ -35,7 +35,17 @@ export const CLASS_PREFIX = {
|
|
|
35
35
|
export const BUTTON = {
|
|
36
36
|
BASE_CLASS: 'c-btn',
|
|
37
37
|
ICON_CLASS: 'c-btn__icon',
|
|
38
|
+
LABEL_CLASS: 'c-btn__label',
|
|
39
|
+
SPINNER_CLASS: 'c-btn__spinner',
|
|
38
40
|
VARIANT_PREFIX: 'c-btn--',
|
|
41
|
+
CLASSES: {
|
|
42
|
+
BASE: 'c-btn',
|
|
43
|
+
LOADING: 'c-btn--loading',
|
|
44
|
+
FULL_WIDTH: 'c-btn--full-width',
|
|
45
|
+
BLOCK: 'c-btn--block',
|
|
46
|
+
ACTIVE: 'c-btn--active',
|
|
47
|
+
SELECTED: 'c-btn--selected',
|
|
48
|
+
},
|
|
39
49
|
};
|
|
40
50
|
|
|
41
51
|
/**
|
|
@@ -177,12 +187,18 @@ export const HERO = {
|
|
|
177
187
|
BG_IMAGE: '.c-hero__bg-image',
|
|
178
188
|
OVERLAY: '.c-hero__overlay',
|
|
179
189
|
IMAGE_WRAPPER: '.c-hero__image-wrapper',
|
|
190
|
+
SLIDER: '.c-hero__slider',
|
|
191
|
+
SLIDER_ITEM: '.c-hero__slider-item',
|
|
180
192
|
},
|
|
181
193
|
CLASSES: {
|
|
182
194
|
CENTER: 'c-hero--center',
|
|
183
195
|
RIGHT: 'c-hero--right',
|
|
184
196
|
LEFT: 'c-hero--left',
|
|
185
197
|
FULL_VH: 'c-hero--full-vh',
|
|
198
|
+
SLIDER_FADE: 'c-hero__slider--fade',
|
|
199
|
+
SLIDER_SLIDE: 'c-hero__slider--slide',
|
|
200
|
+
SLIDER_CUSTOM: 'c-hero__slider--custom',
|
|
201
|
+
SLIDER_ITEM_ACTIVE: 'c-hero__slider-item--active',
|
|
186
202
|
},
|
|
187
203
|
};
|
|
188
204
|
|
|
@@ -724,6 +740,22 @@ export const INPUT = {
|
|
|
724
740
|
INVALID: 'is-invalid',
|
|
725
741
|
VALID: 'is-valid',
|
|
726
742
|
DISABLED: 'is-disabled',
|
|
743
|
+
FULL_WIDTH: 'c-input--full-width',
|
|
744
|
+
PREFIX_ICON: 'c-input--prefix-icon',
|
|
745
|
+
SUFFIX_ICON: 'c-input--suffix-icon',
|
|
746
|
+
CLEARABLE: 'c-input--clearable',
|
|
747
|
+
WITH_COUNTER: 'c-input--with-counter',
|
|
748
|
+
PASSWORD_TOGGLE: 'c-input--password-toggle',
|
|
749
|
+
},
|
|
750
|
+
ELEMENTS: {
|
|
751
|
+
WRAPPER: 'c-input-wrapper',
|
|
752
|
+
PREFIX: 'c-input__prefix',
|
|
753
|
+
SUFFIX: 'c-input__suffix',
|
|
754
|
+
CLEAR_BUTTON: 'c-input__clear',
|
|
755
|
+
PASSWORD_TOGGLE: 'c-input__password-toggle',
|
|
756
|
+
COUNTER: 'c-input__counter',
|
|
757
|
+
ERROR_MESSAGE: 'c-input__error',
|
|
758
|
+
HELPER_TEXT: 'c-input__helper',
|
|
727
759
|
},
|
|
728
760
|
};
|
|
729
761
|
|
|
@@ -766,15 +798,42 @@ export const CARD = {
|
|
|
766
798
|
},
|
|
767
799
|
CLASSES: {
|
|
768
800
|
BASE: 'c-card',
|
|
801
|
+
// Size modifiers
|
|
802
|
+
SM: 'c-card--sm',
|
|
803
|
+
MD: 'c-card--md',
|
|
804
|
+
LG: 'c-card--lg',
|
|
805
|
+
// Layout modifiers
|
|
769
806
|
ROW: 'c-card--row',
|
|
770
807
|
FLAT: 'c-card--flat',
|
|
808
|
+
// Appearance modifiers
|
|
809
|
+
FILLED: 'c-card--filled',
|
|
810
|
+
OUTLINED: 'c-card--outlined',
|
|
811
|
+
GHOST: 'c-card--ghost',
|
|
812
|
+
ELEVATED: 'c-card--elevated',
|
|
813
|
+
// Elevation modifiers
|
|
814
|
+
ELEVATION_NONE: 'c-card--elevation-none',
|
|
815
|
+
ELEVATION_SM: 'c-card--elevation-sm',
|
|
816
|
+
ELEVATION_MD: 'c-card--elevation-md',
|
|
817
|
+
ELEVATION_LG: 'c-card--elevation-lg',
|
|
818
|
+
ELEVATION_XL: 'c-card--elevation-xl',
|
|
819
|
+
// State modifiers
|
|
771
820
|
ACTIVE: 'is-active',
|
|
821
|
+
DISABLED: 'c-card--disabled',
|
|
822
|
+
LOADING: 'c-card--loading',
|
|
823
|
+
SELECTED: 'c-card--selected',
|
|
824
|
+
INTERACTIVE: 'c-card--interactive',
|
|
825
|
+
// Other modifiers
|
|
772
826
|
FLIPPED: 'is-flipped',
|
|
773
827
|
FOCUSED: 'is-focused',
|
|
774
828
|
CLICKABLE: 'is-clickable',
|
|
829
|
+
GLASS: 'c-card--glass',
|
|
775
830
|
},
|
|
776
831
|
DEFAULTS: {
|
|
777
832
|
HOVER: true,
|
|
833
|
+
SIZE: 'md',
|
|
834
|
+
VARIANT: 'primary',
|
|
835
|
+
APPEARANCE: 'filled',
|
|
836
|
+
ELEVATION: 'none',
|
|
778
837
|
},
|
|
779
838
|
};
|
|
780
839
|
|