@yamada-ui/carousel 0.1.0

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.
@@ -0,0 +1,246 @@
1
+ // src/use-carousel.ts
2
+ import { layoutStylesProperties } from "@yamada-ui/core";
3
+ import { useControllableState } from "@yamada-ui/use-controllable-state";
4
+ import {
5
+ createContext,
6
+ dataAttr,
7
+ handlerAll,
8
+ splitObject,
9
+ useUpdateEffect
10
+ } from "@yamada-ui/utils";
11
+ import useEmblaCarousel from "embla-carousel-react";
12
+ import { Children, useCallback, useEffect, useRef, useState } from "react";
13
+ var [CarouselProvider, useCarouselContext] = createContext({
14
+ name: "CarouselContext",
15
+ errorMessage: `useCarouselContext returned is 'undefined'. Seems you forgot to wrap the components in "<Carousel />"`
16
+ });
17
+ var useCarousel = ({
18
+ index,
19
+ defaultIndex = 0,
20
+ onChange,
21
+ align = "center",
22
+ orientation = "horizontal",
23
+ autoplay = false,
24
+ stopMouseEnterAutoplay = true,
25
+ loop = true,
26
+ speed = 10,
27
+ delay = 4e3,
28
+ gap = "md",
29
+ slidesToScroll = 1,
30
+ draggable = true,
31
+ dragFree = false,
32
+ inViewThreshold = 0,
33
+ skipSnaps = false,
34
+ containScroll = "",
35
+ slideSize = "100%",
36
+ includeGapInSize = true,
37
+ onScrollProgress,
38
+ children,
39
+ ...rest
40
+ }) => {
41
+ const computedProps = splitObject(rest, layoutStylesProperties);
42
+ const [selectedIndex, setSelectedIndex] = useControllableState({
43
+ value: index,
44
+ defaultValue: defaultIndex,
45
+ onChange
46
+ });
47
+ const isVertical = orientation === "vertical";
48
+ const [carouselRef, carousel] = useEmblaCarousel({
49
+ axis: isVertical ? "y" : "x",
50
+ startIndex: defaultIndex,
51
+ loop,
52
+ align,
53
+ slidesToScroll,
54
+ draggable,
55
+ dragFree,
56
+ speed,
57
+ inViewThreshold,
58
+ skipSnaps,
59
+ containScroll
60
+ });
61
+ const [indexes, setIndexes] = useState([]);
62
+ const [isMouseEnter, setIsMouseEnter] = useState(false);
63
+ const timeoutId = useRef(void 0);
64
+ const onScroll = useCallback(() => {
65
+ if (!carousel)
66
+ return;
67
+ const progress = Math.round(Math.max(0, Math.min(1, carousel.scrollProgress())) * 100);
68
+ onScrollProgress == null ? void 0 : onScrollProgress(progress);
69
+ }, [carousel, onScrollProgress]);
70
+ const onSelect = useCallback(() => {
71
+ if (!carousel)
72
+ return;
73
+ const index2 = carousel.selectedScrollSnap();
74
+ setSelectedIndex(index2);
75
+ }, [carousel, setSelectedIndex]);
76
+ useEffect(() => {
77
+ const isStop = isMouseEnter && stopMouseEnterAutoplay;
78
+ const isLast = !(carousel == null ? void 0 : carousel.canScrollNext());
79
+ if (carousel && autoplay && !isStop && !isLast) {
80
+ timeoutId.current = setInterval(() => {
81
+ carousel.scrollNext();
82
+ }, delay);
83
+ } else {
84
+ if (timeoutId.current)
85
+ clearInterval(timeoutId.current);
86
+ timeoutId.current = void 0;
87
+ }
88
+ return () => {
89
+ if (timeoutId.current)
90
+ clearInterval(timeoutId.current);
91
+ };
92
+ }, [autoplay, delay, stopMouseEnterAutoplay, carousel, isMouseEnter, loop, selectedIndex]);
93
+ useUpdateEffect(() => {
94
+ if (!carousel)
95
+ return;
96
+ carousel.reInit();
97
+ const snapList = carousel.scrollSnapList();
98
+ const indexes2 = snapList.map((_, i) => i);
99
+ setIndexes(indexes2);
100
+ }, [
101
+ Children.toArray(children).length,
102
+ align,
103
+ orientation,
104
+ loop,
105
+ speed,
106
+ gap,
107
+ slidesToScroll,
108
+ draggable,
109
+ dragFree,
110
+ inViewThreshold,
111
+ skipSnaps,
112
+ containScroll,
113
+ slideSize,
114
+ includeGapInSize
115
+ ]);
116
+ useUpdateEffect(() => {
117
+ if (!carousel)
118
+ return;
119
+ const snapList = carousel.scrollSnapList();
120
+ const indexes2 = snapList.map((_, i) => i);
121
+ setIndexes(indexes2);
122
+ }, [carousel]);
123
+ useUpdateEffect(() => {
124
+ if (carousel) {
125
+ carousel.on("select", onSelect);
126
+ carousel.on("scroll", onScroll);
127
+ onScroll();
128
+ return () => {
129
+ carousel.off("select", onSelect);
130
+ carousel.off("scroll", onScroll);
131
+ };
132
+ }
133
+ }, [carousel, onScroll]);
134
+ const getContainerProps = useCallback(
135
+ (props = {}, ref = null) => ({
136
+ ...computedProps[0],
137
+ ...props,
138
+ ref,
139
+ onMouseEnter: handlerAll(props.onMouseEnter, () => {
140
+ setIsMouseEnter(true);
141
+ }),
142
+ onMouseLeave: handlerAll(props.onMouseLeave, () => {
143
+ setIsMouseEnter(false);
144
+ })
145
+ }),
146
+ [computedProps]
147
+ );
148
+ const getSlidesProps = useCallback(
149
+ (props = {}) => ({
150
+ ...computedProps[1],
151
+ ...props,
152
+ ref: carouselRef
153
+ }),
154
+ [computedProps, carouselRef]
155
+ );
156
+ return {
157
+ carousel,
158
+ children,
159
+ indexes,
160
+ selectedIndex,
161
+ orientation,
162
+ slideSize,
163
+ gap,
164
+ slidesToScroll,
165
+ includeGapInSize,
166
+ getContainerProps,
167
+ getSlidesProps
168
+ };
169
+ };
170
+ var useCarouselSlide = ({ index }) => {
171
+ const { selectedIndex, slidesToScroll } = useCarouselContext();
172
+ index = Math.floor((index != null ? index : 0) / (slidesToScroll != null ? slidesToScroll : 1));
173
+ const isSelected = index === selectedIndex;
174
+ const getSlideProps = useCallback(
175
+ (props = {}) => ({
176
+ ...props,
177
+ role: "carousel-slide",
178
+ "data-index": index,
179
+ "data-selected": dataAttr(isSelected)
180
+ }),
181
+ [isSelected, index]
182
+ );
183
+ return { getSlideProps };
184
+ };
185
+ var useCarouselControl = ({ operation, ...rest }) => {
186
+ var _a, _b;
187
+ const { carousel } = useCarouselContext();
188
+ const isPrev = operation === "prev";
189
+ const disabled = (_b = (_a = rest.disabled) != null ? _a : rest.isDisabled) != null ? _b : isPrev ? !(carousel == null ? void 0 : carousel.canScrollPrev()) : !(carousel == null ? void 0 : carousel.canScrollNext());
190
+ const onClick = useCallback(() => {
191
+ if (!carousel)
192
+ return;
193
+ if (isPrev) {
194
+ carousel.scrollPrev();
195
+ } else {
196
+ carousel.scrollNext();
197
+ }
198
+ }, [carousel, isPrev]);
199
+ const getControlProps = useCallback(
200
+ (props = {}, ref = null) => ({
201
+ ...props,
202
+ ref,
203
+ disabled,
204
+ role: "carousel-control",
205
+ onClick: handlerAll(props.onClick, onClick)
206
+ }),
207
+ [disabled, onClick]
208
+ );
209
+ return { getControlProps };
210
+ };
211
+ var useCarouselIndicators = () => {
212
+ const { selectedIndex, carousel, indexes } = useCarouselContext();
213
+ const onClick = useCallback(
214
+ (ev, index) => {
215
+ if (!carousel)
216
+ return;
217
+ ev.stopPropagation();
218
+ carousel.scrollTo(index);
219
+ },
220
+ [carousel]
221
+ );
222
+ const getIndicatorProps = useCallback(
223
+ ({ index, ...props } = {}) => {
224
+ const isSelected = index === selectedIndex;
225
+ return {
226
+ ...props,
227
+ key: index,
228
+ role: "carousel-indicator",
229
+ "data-index": index,
230
+ "data-selected": dataAttr(isSelected),
231
+ onClick: handlerAll(props.onClick, (ev) => onClick(ev, index))
232
+ };
233
+ },
234
+ [onClick, selectedIndex]
235
+ );
236
+ return { indexes, getIndicatorProps };
237
+ };
238
+
239
+ export {
240
+ CarouselProvider,
241
+ useCarouselContext,
242
+ useCarousel,
243
+ useCarouselSlide,
244
+ useCarouselControl,
245
+ useCarouselIndicators
246
+ };
@@ -0,0 +1,29 @@
1
+ import {
2
+ useCarouselContext,
3
+ useCarouselSlide
4
+ } from "./chunk-4P3A5PTO.mjs";
5
+
6
+ // src/carousel-slide.tsx
7
+ import { ui, forwardRef } from "@yamada-ui/core";
8
+ import { cx } from "@yamada-ui/utils";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var CarouselSlide = forwardRef(
11
+ ({ className, size, ...rest }, ref) => {
12
+ const { slideSize, includeGapInSize, orientation, gap } = useCarouselContext();
13
+ const { getSlideProps } = useCarouselSlide(rest);
14
+ size != null ? size : size = slideSize;
15
+ const css = {
16
+ position: "relative",
17
+ flex: `0 0 ${size}`,
18
+ ...includeGapInSize ? { [orientation === "vertical" ? "pb" : "pr"]: gap } : { [orientation === "vertical" ? "mb" : "mr"]: gap }
19
+ };
20
+ return /* @__PURE__ */ jsx(ui.div, { className: cx("ui-carousel-slide", className), __css: css, ...getSlideProps({}), children: /* @__PURE__ */ jsx(CarouselSlideInner, { ref, ...rest }) });
21
+ }
22
+ );
23
+ var CarouselSlideInner = forwardRef(({ ...rest }, ref) => {
24
+ return /* @__PURE__ */ jsx(ui.div, { ref, className: "ui-carousel-slide-inner", w: "100%", h: "100%", ...rest });
25
+ });
26
+
27
+ export {
28
+ CarouselSlide
29
+ };
@@ -0,0 +1,85 @@
1
+ import {
2
+ useCarouselContext,
3
+ useCarouselControl
4
+ } from "./chunk-4P3A5PTO.mjs";
5
+
6
+ // src/carousel-control.tsx
7
+ import { IconButton } from "@yamada-ui/button";
8
+ import { forwardRef, useColorModetValue } from "@yamada-ui/core";
9
+ import { ChevronIcon } from "@yamada-ui/icon";
10
+ import { cx } from "@yamada-ui/utils";
11
+ import { jsx } from "react/jsx-runtime";
12
+ var CarouselControlPrev = forwardRef(
13
+ ({ className, ...rest }, ref) => {
14
+ const { orientation } = useCarouselContext();
15
+ const { getControlProps } = useCarouselControl({ operation: "prev" });
16
+ return /* @__PURE__ */ jsx(
17
+ CarouselControl,
18
+ {
19
+ operation: "prev",
20
+ className: cx("ui-carousel-control-prev", className),
21
+ icon: /* @__PURE__ */ jsx(
22
+ ChevronIcon,
23
+ {
24
+ __css: {
25
+ fontSize: "1.5em",
26
+ transform: orientation === "vertical" ? "rotate(180deg)" : "rotate(90deg)"
27
+ }
28
+ }
29
+ ),
30
+ ...getControlProps(rest, ref)
31
+ }
32
+ );
33
+ }
34
+ );
35
+ var CarouselControlNext = forwardRef(
36
+ ({ className, ...rest }, ref) => {
37
+ const { orientation } = useCarouselContext();
38
+ const { getControlProps } = useCarouselControl({ operation: "next" });
39
+ return /* @__PURE__ */ jsx(
40
+ CarouselControl,
41
+ {
42
+ operation: "next",
43
+ className: cx("ui-carousel-control-next", className),
44
+ icon: /* @__PURE__ */ jsx(
45
+ ChevronIcon,
46
+ {
47
+ __css: {
48
+ fontSize: "1.5em",
49
+ transform: orientation === "vertical" ? "rotate(0deg)" : "rotate(-90deg)"
50
+ }
51
+ }
52
+ ),
53
+ ...getControlProps(rest, ref)
54
+ }
55
+ );
56
+ }
57
+ );
58
+ var CarouselControl = forwardRef(
59
+ ({ className, operation, ...rest }, ref) => {
60
+ const { styles } = useCarouselContext();
61
+ const colorScheme = useColorModetValue("whiteAlpha", "blackAlpha");
62
+ const css = {
63
+ position: "absolute",
64
+ zIndex: "kurillin",
65
+ ...styles.control,
66
+ ...styles[operation]
67
+ };
68
+ return /* @__PURE__ */ jsx(
69
+ IconButton,
70
+ {
71
+ ref,
72
+ className: cx("ui-carousel-control", className),
73
+ colorScheme,
74
+ isRound: true,
75
+ __css: css,
76
+ ...rest
77
+ }
78
+ );
79
+ }
80
+ );
81
+
82
+ export {
83
+ CarouselControlPrev,
84
+ CarouselControlNext
85
+ };
@@ -0,0 +1,139 @@
1
+ import {
2
+ CarouselControlNext,
3
+ CarouselControlPrev
4
+ } from "./chunk-FDF2QUCY.mjs";
5
+ import {
6
+ CarouselIndicators
7
+ } from "./chunk-UMRTZXZW.mjs";
8
+ import {
9
+ CarouselSlide
10
+ } from "./chunk-BWFAE3UJ.mjs";
11
+ import {
12
+ CarouselProvider,
13
+ useCarousel,
14
+ useCarouselContext
15
+ } from "./chunk-4P3A5PTO.mjs";
16
+
17
+ // src/carousel.tsx
18
+ import {
19
+ ui,
20
+ forwardRef,
21
+ useMultiComponentStyle,
22
+ omitThemeProps
23
+ } from "@yamada-ui/core";
24
+ import { useToken } from "@yamada-ui/use-token";
25
+ import { useValue } from "@yamada-ui/use-value";
26
+ import {
27
+ cx,
28
+ filterUndefined,
29
+ findChildren,
30
+ getValidChildren,
31
+ omitChildren,
32
+ pickChildren
33
+ } from "@yamada-ui/utils";
34
+ import { cloneElement } from "react";
35
+ import { jsx, jsxs } from "react/jsx-runtime";
36
+ var Carousel = forwardRef(
37
+ ({ h, height, minH, minHeight, ...props }, ref) => {
38
+ var _a, _b;
39
+ const orientation = useValue(props.orientation);
40
+ const align = useValue(props.align);
41
+ const autoplay = useValue(props.autoplay);
42
+ const stopMouseEnterAutoplay = useValue(props.stopMouseEnterAutoplay);
43
+ const loop = useValue(props.loop);
44
+ const speed = useValue(props.speed);
45
+ const delay = useValue(props.delay);
46
+ const slidesToScroll = useValue(props.slidesToScroll);
47
+ const draggable = useValue(props.draggable);
48
+ const dragFree = useValue(props.dragFree);
49
+ const inViewThreshold = useValue(props.inViewThreshold);
50
+ const skipSnaps = useValue(props.skipSnaps);
51
+ const containScroll = useValue(props.containScroll);
52
+ const includeGapInSize = useValue(props.includeGapInSize);
53
+ const gap = (_a = useToken("spaces", useValue(props.gap))) != null ? _a : useValue(props.gap);
54
+ const slideSize = (_b = useToken("sizes", useValue(props.slideSize))) != null ? _b : useValue(props.slideSize);
55
+ const [styles, mergedProps] = useMultiComponentStyle("Carousel", {
56
+ ...props,
57
+ orientation,
58
+ align,
59
+ autoplay,
60
+ stopMouseEnterAutoplay,
61
+ loop,
62
+ speed,
63
+ delay,
64
+ slidesToScroll,
65
+ draggable,
66
+ dragFree,
67
+ inViewThreshold,
68
+ skipSnaps,
69
+ containScroll,
70
+ includeGapInSize,
71
+ gap,
72
+ slideSize
73
+ });
74
+ const {
75
+ className,
76
+ inner,
77
+ withControls = true,
78
+ controlProps,
79
+ controlPrevProps,
80
+ controlNextProps,
81
+ withIndicators = true,
82
+ indicatorsProps,
83
+ ...computedProps
84
+ } = omitThemeProps(mergedProps);
85
+ const computedWithControls = useValue(withControls);
86
+ const computedWithIndicators = useValue(withIndicators);
87
+ const { getContainerProps, getSlidesProps, children, ...rest } = useCarousel({
88
+ ...computedProps
89
+ });
90
+ const validChildren = getValidChildren(children);
91
+ const [customCarouselControlPrev] = findChildren(validChildren, CarouselControlPrev);
92
+ const [customCarouselControlNext] = findChildren(validChildren, CarouselControlNext);
93
+ const [customCarouselIndicators] = findChildren(validChildren, CarouselIndicators);
94
+ const slideChildren = pickChildren(validChildren, CarouselSlide);
95
+ const otherChildren = omitChildren(
96
+ validChildren,
97
+ CarouselControlPrev,
98
+ CarouselControlNext,
99
+ CarouselIndicators,
100
+ CarouselSlide
101
+ );
102
+ const cloneSlideChildren = slideChildren.map((child, index) => cloneElement(child, { index }));
103
+ h != null ? h : h = height;
104
+ minH != null ? minH : minH = minHeight;
105
+ return /* @__PURE__ */ jsx(CarouselProvider, { value: { styles, ...rest }, children: /* @__PURE__ */ jsxs(
106
+ ui.div,
107
+ {
108
+ className: cx("ui-carousel", className),
109
+ __css: { position: "relative", h: "fit-content", ...styles.container },
110
+ ...getContainerProps({}, ref),
111
+ children: [
112
+ customCarouselControlPrev != null ? customCarouselControlPrev : computedWithControls ? /* @__PURE__ */ jsx(CarouselControlPrev, { ...controlProps, ...controlPrevProps }) : null,
113
+ customCarouselControlNext != null ? customCarouselControlNext : computedWithControls ? /* @__PURE__ */ jsx(CarouselControlNext, { ...controlProps, ...controlNextProps }) : null,
114
+ /* @__PURE__ */ jsx(CarouselSlides, { ...getSlidesProps({ ...filterUndefined({ h, minH }), ...inner }), children: cloneSlideChildren }),
115
+ customCarouselIndicators != null ? customCarouselIndicators : computedWithIndicators ? /* @__PURE__ */ jsx(CarouselIndicators, { ...indicatorsProps }) : null,
116
+ otherChildren
117
+ ]
118
+ }
119
+ ) });
120
+ }
121
+ );
122
+ var CarouselSlides = forwardRef(({ ...rest }, ref) => {
123
+ const css = { w: "100%", h: "fit-content", overflow: "hidden" };
124
+ return /* @__PURE__ */ jsx(ui.div, { ref, className: "ui-carousel-sliders", __css: css, children: /* @__PURE__ */ jsx(CarouselSlidesInner, { ...rest }) });
125
+ });
126
+ var CarouselSlidesInner = ({ ...rest }) => {
127
+ const { orientation, includeGapInSize, gap, styles } = useCarouselContext();
128
+ const css = {
129
+ display: "flex",
130
+ flexDirection: orientation === "vertical" ? "column" : "row",
131
+ ...styles.inner,
132
+ ...includeGapInSize ? { [orientation === "vertical" ? "mb" : "mr"]: `-${gap}` } : {}
133
+ };
134
+ return /* @__PURE__ */ jsx(ui.div, { className: "ui-carousel-sliders-inner", __css: css, ...rest });
135
+ };
136
+
137
+ export {
138
+ Carousel
139
+ };
@@ -0,0 +1,51 @@
1
+ import {
2
+ useCarouselContext,
3
+ useCarouselIndicators
4
+ } from "./chunk-4P3A5PTO.mjs";
5
+
6
+ // src/carousel-indicators.tsx
7
+ import { ui, forwardRef } from "@yamada-ui/core";
8
+ import { cx } from "@yamada-ui/utils";
9
+ import { cloneElement } from "react";
10
+ import { jsx } from "react/jsx-runtime";
11
+ var CarouselIndicators = forwardRef(
12
+ ({ className, component = CarouselIndicator, ...rest }, ref) => {
13
+ const { selectedIndex, orientation, styles } = useCarouselContext();
14
+ const { indexes, getIndicatorProps } = useCarouselIndicators();
15
+ const cloneChildren = indexes.map((index) => {
16
+ const isSelected = index === selectedIndex;
17
+ const child = component({ index, isSelected });
18
+ if (!child)
19
+ return null;
20
+ const props = getIndicatorProps({ ...child.props, index });
21
+ return cloneElement(child, props);
22
+ });
23
+ const css = {
24
+ position: "absolute",
25
+ zIndex: "kurillin",
26
+ display: "flex",
27
+ justifyContent: "center",
28
+ ...styles.indicators,
29
+ ...orientation === "vertical" ? { flexDirection: "column" } : { flexDirection: "row" }
30
+ };
31
+ return /* @__PURE__ */ jsx(ui.div, { ref, className: cx("ui-carousel-indicators", className), __css: css, ...rest, children: cloneChildren });
32
+ }
33
+ );
34
+ var CarouselIndicator = ({ className, ...rest }) => {
35
+ const { styles } = useCarouselContext();
36
+ const css = { ...styles.indicator };
37
+ return /* @__PURE__ */ jsx(
38
+ ui.button,
39
+ {
40
+ type: "button",
41
+ tabIndex: -1,
42
+ className: cx("ui-carousel-indicator", className),
43
+ __css: css,
44
+ ...rest
45
+ }
46
+ );
47
+ };
48
+
49
+ export {
50
+ CarouselIndicators
51
+ };
@@ -0,0 +1,10 @@
1
+ export { Carousel, CarouselProps } from './carousel.js';
2
+ export { CarouselSlide, CarouselSlideProps } from './carousel-slide.js';
3
+ export { CarouselControlNext, CarouselControlPrev, CarouselControlProps } from './carousel-control.js';
4
+ export { CarouselIndicators, CarouselIndicatorsProps } from './carousel-indicators.js';
5
+ import '@yamada-ui/core';
6
+ import './use-carousel.js';
7
+ import '@yamada-ui/utils';
8
+ import 'react';
9
+ import '@yamada-ui/button';
10
+ import 'embla-carousel-react';