diff --git a/packages/carousel/package.json b/packages/carousel/package.json index ec430a7ed..8fae14e7e 100644 --- a/packages/carousel/package.json +++ b/packages/carousel/package.json @@ -29,6 +29,8 @@ "react" ], "peerDependencies": { + "@crave/farmblocks-icon": "^1.0.0", + "@crave/farmblocks-button": "^10.0.5", "prop-types": "^15.7.2", "react": "^16.13.0", "styled-components": "^5.2.2" @@ -36,6 +38,7 @@ "dependencies": { "@crave/farmblocks-image": "^3.2.6", "@crave/farmblocks-text": "^3.6.5", - "@crave/farmblocks-theme": "^1.10.1" + "@crave/farmblocks-theme": "^1.10.1", + "lodash.debounce": "^4.0.8" } } diff --git a/packages/carousel/src/Carousel.js b/packages/carousel/src/Carousel.js index 5f05d324e..38247080b 100644 --- a/packages/carousel/src/Carousel.js +++ b/packages/carousel/src/Carousel.js @@ -1,139 +1,190 @@ -import * as React from "react"; +import React, { useState, useEffect, useMemo } from "react"; import PropTypes from "prop-types"; -import Image from "@crave/farmblocks-image"; -import Text from "@crave/farmblocks-text"; - -import Container from "./styledComponents/Carousel"; - -const defaultConfig = { - width: 656, - height: 328, - margin: 20, - fontSize: 88, - displayTime: 4, - transitionTime: 2, - border: "4px solid rgba(255, 255, 255, 0.56)", - borderRadius: "16px", -}; +import debounce from "lodash.debounce"; +import { SmChevronRight, SmChevronLeft } from "@crave/farmblocks-icon"; +import { + Container, + Wrapper, + Content, + ButtonContainer, + ArrowButton, +} from "./styledComponents/Carousel"; + +import Dots from "./components/Dots"; +import useTouch from "./hooks/useTouch"; + +function Carousel( + { + qtyOfSlidesPerSet, + infiniteLoop, + children, + leftButtonProps, + rightButtonProps, + }, + ...props +) { + const CAROUSEL_DELAY = 300; + + const displayNumber = + qtyOfSlidesPerSet < children.length ? qtyOfSlidesPerSet : children.length; + + const [dotIndex, setDotIndex] = useState(0); + const [currentIndex, setCurrentIndex] = useState( + infiniteLoop && displayNumber < children.length ? displayNumber : 0, + ); + + useEffect(() => { + if (infiniteLoop) setCurrentIndex(dotIndex + displayNumber); + else if (currentIndex > children.length - qtyOfSlidesPerSet) + setCurrentIndex(children.length - qtyOfSlidesPerSet); + }, [displayNumber]); + + const totalOfCards = children.length; + const isRepeating = useMemo( + () => infiniteLoop && children.length > displayNumber, + [children, infiniteLoop, displayNumber], + ); + + const [transitionEnabled, setTransitionEnabled] = useState(true); + + useEffect(() => { + if (isRepeating) { + if (currentIndex === displayNumber || currentIndex === totalOfCards) { + setTransitionEnabled(true); + } + } + }, [currentIndex, isRepeating, displayNumber, totalOfCards]); -class Carousel extends React.Component { - constructor(props) { - super(props); - this.state = { - activeItem: 0, - }; + function handleDotClick(index) { + setDotIndex(index); + setCurrentIndex(index + displayNumber); } - componentDidMount = () => { - this.setInterval(); - }; + const nextSlide = debounce(() => { + if (dotIndex < totalOfCards - 1) setDotIndex((prevState) => prevState + 1); + else if (isRepeating && dotIndex === totalOfCards - 1) { + setDotIndex(0); + } + const result = totalOfCards - displayNumber; - componentDidUpdate(prevProps) { - if (prevProps.imageSet !== this.props.imageSet) { - this.setState({ activeItem: 0 }); - this.setInterval(); + if (isRepeating || currentIndex < result) { + setCurrentIndex((prevState) => prevState + 1); } - } + }, CAROUSEL_DELAY); - componentWillUnmount = () => { - this.clearInterval(); - }; + const prevSlide = debounce(() => { + if (dotIndex === 0) setDotIndex(totalOfCards - 1); + else setDotIndex((prevState) => prevState - 1); - nextItem = () => { - const activeItem = this.state.activeItem + 1; // eslint-disable-line - if (activeItem === this.props.imageSet.length) { - this.clearInterval(); - this.props.onEnd(); - return; + if (isRepeating || currentIndex > 0) { + setCurrentIndex((prevState) => prevState - 1); } - this.props.onChange(activeItem); - this.setState({ activeItem }); - }; - - setInterval = () => { - if (this.transitionId) { - return; + }, CAROUSEL_DELAY); + + const { handleTouchStart, handleTouchMove } = useTouch({ + nextSlide, + prevSlide, + }); + + function handleTransitionEnd() { + if (isRepeating) { + if (currentIndex === 0) { + setTransitionEnabled(false); + setCurrentIndex(totalOfCards); + } else if (currentIndex === totalOfCards + displayNumber) { + setTransitionEnabled(false); + setCurrentIndex(displayNumber); + } } + } - const { displayTime } = { ...defaultConfig, ...this.props.itemConfig }; - - this.transitionId = window.setInterval(this.nextItem, displayTime * 1000); - }; - - clearInterval = () => { - if (this.transitionId) { - window.clearInterval(this.transitionId); - delete this.transitionId; + const renderExtraPrev = useMemo(() => { + const output = []; + for (let index = 0; index < displayNumber; index += 1) { + output.push(children[totalOfCards - 1 - index]); } - }; - - render() { - const { imageSet, itemConfig } = this.props; - const configProps = { ...defaultConfig, ...itemConfig }; - - return ( - - - - ); - } + output.reverse(); + return output; + }, [children, totalOfCards, displayNumber]); + + const renderExtraNext = useMemo(() => { + const output = []; + for (let index = 0; index < displayNumber; index += 1) { + output.push(children[index]); + } + return output; + }, [children, displayNumber]); + + const showLeftArrow = isRepeating || currentIndex > 0; + const showRightArrow = + isRepeating || currentIndex < totalOfCards - displayNumber; + const renderExtras = totalOfCards > displayNumber && isRepeating; + + return ( + + + + {showLeftArrow && ( + } + {...leftButtonProps} + onClick={(event) => { + prevSlide(); + leftButtonProps?.onClick?.(event); + }} + /> + )} + +
+ handleTouchStart(event)} + onTouchMove={(event) => handleTouchMove(event)} + > + {renderExtras && renderExtraPrev} + {children} + {renderExtras && renderExtraNext} + +
+ + {showRightArrow && ( + } + {...rightButtonProps} + onClick={(event) => { + nextSlide(); + rightButtonProps?.onClick?.(event); + }} + /> + )} + +
+ {isRepeating && ( + + )} +
+ ); } Carousel.propTypes = { - imageSet: PropTypes.arrayOf( - PropTypes.shape({ image: PropTypes.string, name: PropTypes.string }), - ), - onChange: PropTypes.func, - onEnd: PropTypes.func, - scale: PropTypes.bool, - itemConfig: PropTypes.shape({ - width: PropTypes.number, - height: PropTypes.number, - margin: PropTypes.number, - fontSize: PropTypes.number, - displayTime: PropTypes.number, - transitionTime: PropTypes.number, - border: PropTypes.string, - }), - className: PropTypes.string, + children: PropTypes.node.isRequired, + qtyOfSlidesPerSet: PropTypes.number, + infiniteLoop: PropTypes.bool, + leftButtonProps: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), + rightButtonProps: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), }; - Carousel.defaultProps = { - itemConfig: defaultConfig, - scale: true, - onChange: () => null, - onEnd: () => null, + infiniteLoop: false, + qtyOfSlidesPerSet: 1, }; export default Carousel; diff --git a/packages/carousel/src/Carousel.story.js b/packages/carousel/src/Carousel.story.js index 77b9d5d4c..b16a5a727 100644 --- a/packages/carousel/src/Carousel.story.js +++ b/packages/carousel/src/Carousel.story.js @@ -1,101 +1,159 @@ import React from "react"; import { storiesOf } from "@storybook/react"; -import { action } from "@storybook/addon-actions"; -import Carousel from "."; +import { MdArrowLeft, MdArrowRight } from "@crave/farmblocks-icon"; + +import { Carousel, Slide, useResizeWindow } from "."; const imageSet = [ - { - image: "https://picsum.photos/640/?image=1080", - name: "Organic Pepper", - }, - { - image: "https://picsum.photos/640/?image=824", - name: "Tomato", - }, - { - image: "https://picsum.photos/640/?image=889", - name: "Grapefruit", - }, - { - image: "https://picsum.photos/640/?image=674", - name: "Tomato", - }, - { - image: "https://picsum.photos/640/?image=292", - name: "Tomato", - }, - { - image: "https://picsum.photos/640/?image=517", - name: "Tomato", - }, - { - image: "https://picsum.photos/640/?image=627", - name: "Tomato", - }, - { - image: "https://picsum.photos/640/?image=75", - name: "Tomato", + Organic Pepper, + Tomato, + Grapefruit, + Tomato, + Tomato, + Tomato, + Tomato, + Tomato, + Romaine Lettuce, +]; + +const leftButtonStyle = { + icon: , + style: { + borderRadius: "0px", }, - { - image: "https://picsum.photos/640/?image=766", - name: "Romaine Lettuce", +}; +const rightButtonStyle = { + icon: , + style: { + borderRadius: "0px", }, -]; +}; storiesOf("Carousel", module) - .add("1 photo", () => ) + .add("1 photo", () => ( +
+ + {imageSet[0]} + +
+ )) - .add("1 photo with onEnd", () => ( - + .add("2 photos", () => ( +
+ + {imageSet[0]} + {imageSet[1]} + +
)) - .add("2 photos", () => ) + .add("all photos", () => { + const AllPhotos = () => { + const { displayNumber } = useResizeWindow({ + breakpoints: [ + { + width: 768, + slidesToShow: 1, + }, + { + width: 1200, + slidesToShow: 3, + }, + { + width: 1000, + slidesToShow: 2, + }, + ], + qtyOfSlidesPerSet: 4, + }); + return ( +
+ + {imageSet.map((value) => ( + {value} + ))} + +
+ ); + }; - .add("all photos", () => ) - .add("no scale", () => ) + return ; + }) + .add("infinite loop", () => { + const InfinitLoop = () => { + const { displayNumber } = useResizeWindow({ + breakpoints: [ + { + width: 768, + slidesToShow: 1, + }, + { + width: 1200, + slidesToShow: 2, + }, + ], + infiniteLoop: true, + qtyOfSlidesPerSet: 3, + numberOfCards: imageSet.length, + dotIndex: 0, + }); + return ( +
+ + {imageSet.map((value) => ( + {value} + ))} + +
+ ); + }; - .add("all photos with onChange and onEnd", () => ( - - )) - .add("partial custom config", () => ( - - )) - .add("custom config", () => ( - ; + }) + .add("Custom carousel", () => ( +
- )) - .add("extended style", () => ( - + > + + {imageSet.map((value) => ( + {value} + ))} + +
)); diff --git a/packages/carousel/src/Carousel.test.js b/packages/carousel/src/Carousel.test.js index 964876d56..7e0dbca2b 100644 --- a/packages/carousel/src/Carousel.test.js +++ b/packages/carousel/src/Carousel.test.js @@ -1,122 +1,89 @@ import React from "react"; -import renderer from "react-test-renderer"; -import { configure, mount } from "enzyme"; -import Adapter from "enzyme-adapter-react-16"; -import Carousel from "."; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; -describe("Carousel", () => { - configure({ adapter: new Adapter() }); - jest.useFakeTimers(); - - let clearIntervalSpy; - let setIntervalSpy; - - beforeEach(() => { - clearIntervalSpy = jest.spyOn(window, "clearInterval"); - setIntervalSpy = jest.spyOn(window, "setInterval"); - }); - - afterEach(() => { - clearTimeout.mockClear(); - clearIntervalSpy.mockClear(); - setIntervalSpy.mockClear(); - }); - - test("active photo should change after displayTime", () => { - const imageSet = [ - { image: "http://example.com/1.png", name: "1" }, - { image: "http://example.com/2.png", name: "2" }, - { image: "http://example.com/3.png", name: "3" }, - ]; - const component = renderer.create(); - const state = component.getInstance().state; - expect(state.activeItem).toBe(0); - - jest.runOnlyPendingTimers(); - - const finalState = component.getInstance().state; - expect(finalState.activeItem).toBe(1); - }); - - test("onEnd event handler should be called after the last photo", () => { - const imageSet = [ - { image: "http://example.com/1.png", name: "1" }, - { image: "http://example.com/2.png", name: "2" }, - { image: "http://example.com/3.png", name: "3" }, - ]; - const onEndMock = jest.fn(); - renderer.create(); - jest.runAllTimers(); - - expect(onEndMock).toBeCalled(); - }); - - test("setInterval should be called on mount and not called if there's a transitionId", () => { - const imageSet = [{ image: "http://example.com/1.png", name: "1" }]; - const component = renderer.create(); +import { Carousel, Slide } from "."; - const cb = component.getInstance().nextItem; - - expect(setIntervalSpy).toHaveBeenCalledWith(cb, 4000); - expect(setIntervalSpy).toHaveBeenCalledTimes(1); - - // set interval should not be called again - component.getInstance().setInterval(); - expect(setIntervalSpy).toHaveBeenCalledTimes(1); +describe("Carousel", () => { + const imageSet = [ + Organic Pepper, + Tomato, + Grapefruit, + ]; + + const makeSut = ({ ...props }) => { + render( + + {imageSet.map((value) => ( + {value} + ))} + , + ); + }; + + it("should render component without arrows and dots", () => { + const initialValues = { + qtyOfSlidesPerSet: imageSet.length, + }; + makeSut(initialValues); + + expect(screen.queryByTestId("left-arrow")).not.toBeInTheDocument(); + expect(screen.queryByTestId("right-arrow")).not.toBeInTheDocument(); + expect(screen.queryByTestId("dots-container")).not.toBeInTheDocument(); }); + it("should render component with arrows", () => { + const initialValues = { + qtyOfSlidesPerSet: imageSet.length - 1, + }; + makeSut(initialValues); - test("clearInterval should be called on unmount", () => { - const imageSet = [ - { image: "http://example.com/1.png", name: "1" }, - { image: "http://example.com/2.png", name: "2" }, - { image: "http://example.com/3.png", name: "3" }, - ]; - const component = renderer.create(); - - const transitionId = component.getInstance().transitionId; - - expect(transitionId).toBeDefined(); - component.unmount(); - expect(clearIntervalSpy).toHaveBeenCalledWith(transitionId); - }); + // check if proper elements are renderer + const rightArrow = screen.queryByTestId("right-arrow"); - test("clearInterval should not be called if there is no transitionId on unmount", () => { - const imageSet = [{ image: "http://example.com/1.png", name: "1" }]; - const component = renderer.create(); + expect(screen.queryByTestId("left-arrow")).not.toBeInTheDocument(); + expect(screen.queryByTestId("dots-container")).not.toBeInTheDocument(); + expect(rightArrow).toBeInTheDocument(); - delete component.getInstance().transitionId; + // click o right arrow + userEvent.click(rightArrow); - component.unmount(); - expect(clearIntervalSpy).not.toHaveBeenCalled(); + // check if proper elements are renderer + expect(rightArrow).not.toBeInTheDocument(); + expect(screen.queryByTestId("left-arrow")).toBeInTheDocument(); }); - describe("Receiving new props", () => { - const imageSet = [{ image: "http://example.com/1.png", name: "1" }]; - let component, setStateSpy, setIntervSpy; - - beforeEach(() => { - component = mount(); - setStateSpy = jest.spyOn(component.instance(), "setState"); - setIntervSpy = jest.spyOn(component.instance(), "setInterval"); - }); - - afterEach(() => { - setStateSpy.mockClear(); - setIntervSpy.mockClear(); - }); - - test("activeItem should be set to 0 when imageSet changes", () => { - component.setProps({ imageSet: [] }); - - expect(setStateSpy).toHaveBeenCalledWith({ activeItem: 0 }); - expect(setIntervSpy).toHaveBeenCalledTimes(1); - }); - - test("state should not change when imageSet doesn't change", () => { - component.setProps({ imageSet }); - - expect(setStateSpy).not.toHaveBeenCalled(); - expect(setIntervSpy).not.toHaveBeenCalled(); - }); + it("should render component with infinite scroll", () => { + const initialValues = { + qtyOfSlidesPerSet: 2, + infiniteLoop: true, + }; + makeSut(initialValues); + + // check if proper elements are renderer + const rightArrow = screen.queryByTestId("right-arrow"); + const leftArrow = screen.queryByTestId("left-arrow"); + const dotsContainer = screen.queryByTestId("dots-container"); + + expect(dotsContainer.children[0].classList.contains("active")).toBe(true); + expect(rightArrow).toBeInTheDocument(); + expect(leftArrow).toBeInTheDocument(); + + // click on last Dot + userEvent.click(dotsContainer.children[2]); + + // check if active dot has changed and arrows are still in screen + expect(rightArrow).toBeInTheDocument(); + expect(leftArrow).toBeInTheDocument(); + expect(dotsContainer.children[0].classList.contains("active")).toBe(false); + expect(dotsContainer.children[2].classList.contains("active")).toBe(true); + + // click on next + userEvent.click(rightArrow); + + // check if active dot has go back to first position + expect(rightArrow).toBeInTheDocument(); + expect(leftArrow).toBeInTheDocument(); + expect(dotsContainer.children[2].classList.contains("active")).toBe(false); + expect(dotsContainer.children[0].classList.contains("active")).toBe(true); }); }); diff --git a/packages/carousel/src/__snapshots__/Carousel.story.storyshot b/packages/carousel/src/__snapshots__/Carousel.story.storyshot index c99a21eee..4d7200a07 100644 --- a/packages/carousel/src/__snapshots__/Carousel.story.storyshot +++ b/packages/carousel/src/__snapshots__/Carousel.story.storyshot @@ -1,1905 +1,1972 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Storyshots Carousel 1 photo 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +.c5 { + padding: 8px; } -.c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c5 * { + width: 100%; + border-radius: 20px; + box-shadow: 0px 4px 8px 0px rgba(0,0,0,0.08); } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -399.83200000000005px; - height: 439.83200000000005px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; +.c4 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2s; - -webkit-transition: transform 2s; - transition: transform 2s; - will-change: transform; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; } -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2s; - transition: all 2s; - will-change: transform; +.c0 { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c1 { + display: grid; + grid-template-columns: 1fr 10fr 1fr; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 91.83200000000005px; +.c3 { + width: 100%; + height: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-transition: all 250ms linear; + transition: all 250ms linear; + -ms-overflow-style: none; + -webkit-scrollbar-width: none; + -moz-scrollbar-width: none; + -ms-scrollbar-width: none; + scrollbar-width: none; + -webkit-transform: translateX( -NaN% ); + -ms-transform: translateX( -NaN% ); + transform: translateX( -NaN% ); +} + +.c3 > * { + width: NaN%; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c3::-webkit-scrollbar { + display: none; } .c2 { - border: 4px solid rgba(255,255,255,0.56); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-right: 16px; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-left: 16px; }
-
    -
  • +
    -
    - Organic Pepper +
    +
    +
    + Organic Pepper +
    +
    +
    -
  • -
+
+
+
`; -exports[`Storyshots Carousel 1 photo with onEnd 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +exports[`Storyshots Carousel 2 photos 1`] = ` +.c5 { + padding: 8px; } -.c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c5 * { + width: 100%; + border-radius: 20px; + box-shadow: 0px 4px 8px 0px rgba(0,0,0,0.08); } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -399.83200000000005px; - height: 439.83200000000005px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; +.c4 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2s; - -webkit-transition: transform 2s; - transition: transform 2s; - will-change: transform; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; } -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2s; - transition: all 2s; - will-change: transform; +.c0 { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c1 { + display: grid; + grid-template-columns: 1fr 10fr 1fr; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 91.83200000000005px; +.c3 { + width: 100%; + height: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-transition: all 250ms linear; + transition: all 250ms linear; + -ms-overflow-style: none; + -webkit-scrollbar-width: none; + -moz-scrollbar-width: none; + -ms-scrollbar-width: none; + scrollbar-width: none; + -webkit-transform: translateX( -0% ); + -ms-transform: translateX( -0% ); + transform: translateX( -0% ); +} + +.c3 > * { + width: 50%; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c3::-webkit-scrollbar { + display: none; } .c2 { - border: 4px solid rgba(255,255,255,0.56); + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-right: 16px; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-left: 16px; }
-
    -
  • +
    -
    - Organic Pepper +
    +
    +
    + Organic Pepper +
    +
    +
    +
    + Tomato +
    +
    +
    -
  • -
+
+
+
`; -exports[`Storyshots Carousel 2 photos 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +exports[`Storyshots Carousel Custom carousel 1`] = ` +.c5 { + display: inline-block; + vertical-align: text-bottom; } -.c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c5 .farmblocks-icon { + display: block; } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -399.83200000000005px; - height: 439.83200000000005px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; +.c3 { + font-size: 16px; + font-family: lato,sans-serif; + font-weight: 600; + -webkit-font-smoothing: antialiased !important; + -moz-osx-font-smoothing: grayscale; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2s; - -webkit-transition: transform 2s; - transition: transform 2s; - will-change: transform; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + padding: 4px 4px; + border-radius: 4px; + line-height: 1.5; + height: 40px; + min-width: 40px; + width: 40px; + white-space: nowrap; + cursor: pointer; + -webkit-transition: background 0.3s,color 0.3s,border-color 0.3s; + transition: background 0.3s,color 0.3s,border-color 0.3s; + background-color: #FFFFFF; + color: #59636f; + border: solid 1px rgba(0,0,0,0.16); + box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.16); } -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2s; - transition: all 2s; - will-change: transform; +.c3 span { + overflow: hidden; + text-overflow: ellipsis; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c3:disabled { + background-color: rgba(0,0,0,0.32); + color: rgba(0,0,0,0.32); + border-width: 1px; + border-color: rgba(0,0,0,0.16); + box-shadow: none; + cursor: default; } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 91.83200000000005px; +.c3:disabled .icon { + color: rgba(0,0,0,0.32); } -.c2 { - border: 4px solid rgba(255,255,255,0.56); +.c3 .icon { + -webkit-transition: color 0.3s ease; + transition: color 0.3s ease; + color: rgba(0,0,0,0.32); + line-height: 1; } -
-
    -
  • - -
    - Organic Pepper -
    -
  • -
  • - -
    - Tomato -
    -
  • -
-
-`; - -exports[`Storyshots Carousel all photos 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +.c3:not(:disabled):hover, +.c3:not(:disabled).hovered, +.c3:not(:disabled):active, +.c3:not(:disabled).active { + color: #3498db; + border-width: 2px; + border-color: #3498db; + box-shadow: 0px 4px 4px 0px rgba(0,0,0,0.16); + padding: 3px 3px; } -.c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c3:not(:disabled):hover .icon, +.c3:not(:disabled).hovered .icon, +.c3:not(:disabled):active .icon, +.c3:not(:disabled).active .icon, +.c3:not(:disabled):focus .icon, +.c3:not(:disabled).focused .icon { + color: #3498db; } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -399.83200000000005px; - height: 439.83200000000005px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2s; - -webkit-transition: transform 2s; - transition: transform 2s; - will-change: transform; +.c3:not(:disabled).active, +.c3:not(:disabled):active { + box-shadow: none; } -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2s; - transition: all 2s; - will-change: transform; +.c3:focus, +.c3.focused { + outline: none; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c3.focus-visible, +.c3.focused:not(:disabled) { + box-shadow: 0 0 0 3px rgba(52,152,219,0.56); } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 91.83200000000005px; +.c8 { + padding: 8px; } -.c2 { - border: 4px solid rgba(255,255,255,0.56); +.c8 * { + width: 100%; + border-radius: 500px; + box-shadow: 0px 4px 8px 0px rgba(0,0,0,0.08); } -
-
    -
  • - -
    - Organic Pepper -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Grapefruit -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Romaine Lettuce -
    -
  • -
-
-`; +.c7 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; +} -exports[`Storyshots Carousel all photos with onChange and onEnd 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +.c0 { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } .c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; + display: grid; + grid-template-columns: 1fr 10fr 1fr; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; +} + +.c6 { + width: 100%; + height: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-transition: all 250ms linear; + transition: all 250ms linear; + -ms-overflow-style: none; + -webkit-scrollbar-width: none; + -moz-scrollbar-width: none; + -ms-scrollbar-width: none; + scrollbar-width: none; + -webkit-transform: translateX( -100% ); + -ms-transform: translateX( -100% ); + transform: translateX( -100% ); +} + +.c6 > * { + width: 50%; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c6::-webkit-scrollbar { + display: none; } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -399.83200000000005px; - height: 439.83200000000005px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2s; - -webkit-transition: transform 2s; - transition: transform 2s; - will-change: transform; + margin-right: 16px; +} + +.c9 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-left: 16px; +} + +.c4 { + border-radius: 32px; } -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2s; - transition: all 2s; - will-change: transform; +.c10 { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c11 { + height: 8px; + width: 8px; + margin-right: 6px; + cursor: pointer; + border-radius: 50%; + background: rgba(0,0,0,0.08); } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 91.83200000000005px; +.c11.active { + background: rgba(0,0,0,0.48); } -.c2 { - border: 4px solid rgba(255,255,255,0.56); +@media (hover:none) and (pointer:coarse) { + .c4 { + display: none; + } }
-
    -
  • +
    -
    - Organic Pepper +
    -
  • -
  • -
    - Tomato +
    +
    +
    + Tomato +
    +
    +
    +
    + Romaine Lettuce +
    +
    +
    +
    + Organic Pepper +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Grapefruit +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Romaine Lettuce +
    +
    +
    +
    + Organic Pepper +
    +
    +
    +
    + Tomato +
    +
    +
    -
  • -
  • -
    - Grapefruit +
    -
  • -
  • +
    - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Romaine Lettuce -
    -
  • -
+ + + +
+ `; -exports[`Storyshots Carousel custom config 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +exports[`Storyshots Carousel all photos 1`] = ` +.c9 { + display: inline-block; + vertical-align: text-bottom; } -.c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c9 .farmblocks-icon { + display: block; } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -121.9px; - height: 247.8px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; +.c7 { + font-size: 16px; + font-family: lato,sans-serif; + font-weight: 600; + -webkit-font-smoothing: antialiased !important; + -moz-osx-font-smoothing: grayscale; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 0.5s; - -webkit-transition: transform 0.5s; - transition: transform 0.5s; - will-change: transform; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + padding: 4px 4px; + border-radius: 4px; + line-height: 1.5; + height: 40px; + min-width: 40px; + width: 40px; + white-space: nowrap; + cursor: pointer; + -webkit-transition: background 0.3s,color 0.3s,border-color 0.3s; + transition: background 0.3s,color 0.3s,border-color 0.3s; + background-color: #FFFFFF; + color: #59636f; + border: solid 1px rgba(0,0,0,0.16); + box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.16); } -.c0 ul li { - margin: 2px; - min-width: 200px; - width: 200px; - height: 200px; - -webkit-transition: all 0.5s; - transition: all 0.5s; - will-change: transform; +.c7 span { + overflow: hidden; + text-overflow: ellipsis; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c7:disabled { + background-color: rgba(0,0,0,0.32); + color: rgba(0,0,0,0.32); + border-width: 1px; + border-color: rgba(0,0,0,0.16); + box-shadow: none; + cursor: default; } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 23.900000000000006px; +.c7:disabled .icon { + color: rgba(0,0,0,0.32); } -.c2 border { - radius: 100%; - width: 4px; - color: green; +.c7 .icon { + -webkit-transition: color 0.3s ease; + transition: color 0.3s ease; + color: rgba(0,0,0,0.32); + line-height: 1; } -
-
    -
  • - -
    - Organic Pepper -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Grapefruit -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Romaine Lettuce -
    -
  • -
-
-`; +.c7:not(:disabled):hover, +.c7:not(:disabled).hovered, +.c7:not(:disabled):active, +.c7:not(:disabled).active { + color: #3498db; + border-width: 2px; + border-color: #3498db; + box-shadow: 0px 4px 4px 0px rgba(0,0,0,0.16); + padding: 3px 3px; +} -exports[`Storyshots Carousel extended style 1`] = ` -.c4 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +.c7:not(:disabled):hover .icon, +.c7:not(:disabled).hovered .icon, +.c7:not(:disabled):active .icon, +.c7:not(:disabled).active .icon, +.c7:not(:disabled):focus .icon, +.c7:not(:disabled).focused .icon { + color: #3498db; } -.c2 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c7:not(:disabled).active, +.c7:not(:disabled):active { + box-shadow: none; } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -399.83200000000005px; - height: 439.83200000000005px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; +.c7:focus, +.c7.focused { + outline: none; +} + +.c7.focus-visible, +.c7.focused:not(:disabled) { + box-shadow: 0 0 0 3px rgba(52,152,219,0.56); +} + +.c5 { + padding: 8px; +} + +.c5 * { + width: 100%; + border-radius: 20px; + box-shadow: 0px 4px 8px 0px rgba(0,0,0,0.08); +} + +.c4 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2s; - -webkit-transition: transform 2s; - transition: transform 2s; - will-change: transform; -} - -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2s; - transition: all 2s; - will-change: transform; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c0 { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 91.83200000000005px; +.c1 { + display: grid; + grid-template-columns: 1fr 10fr 1fr; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; } .c3 { - border: 4px solid rgba(255,255,255,0.56); + width: 100%; + height: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-transition: all 250ms linear; + transition: all 250ms linear; + -ms-overflow-style: none; + -webkit-scrollbar-width: none; + -moz-scrollbar-width: none; + -ms-scrollbar-width: none; + scrollbar-width: none; + -webkit-transform: translateX( -0% ); + -ms-transform: translateX( -0% ); + transform: translateX( -0% ); +} + +.c3 > * { + width: 25%; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c3::-webkit-scrollbar { + display: none; } -.c1 { - background: lavender; +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-right: 16px; +} + +.c6 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-left: 16px; } -.c1 .image { - background-size: 50%; - background-repeat: repeat; +.c8 { + border-radius: 32px; } -.c1 .itemLabel { - color: red; +@media (hover:none) and (pointer:coarse) { + .c8 { + display: none; + } }
-
    -
  • - -
    - Organic Pepper -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Grapefruit -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • +
    -
    - Tomato -
    -
  • -
  • -
    - Tomato +
    +
    +
    + Organic Pepper +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Grapefruit +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Romaine Lettuce +
    +
    +
    -
  • -
  • -
    - Romaine Lettuce +
    -
  • -
+
+ `; -exports[`Storyshots Carousel no scale 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +exports[`Storyshots Carousel infinite loop 1`] = ` +.c5 { + display: inline-block; + vertical-align: text-bottom; } -.c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c5 .farmblocks-icon { + display: block; } -.c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -328px; - height: 368px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; +.c3 { + font-size: 16px; + font-family: lato,sans-serif; + font-weight: 600; + -webkit-font-smoothing: antialiased !important; + -moz-osx-font-smoothing: grayscale; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2s; - -webkit-transition: transform 2s; - transition: transform 2s; - will-change: transform; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + padding: 4px 4px; + border-radius: 4px; + line-height: 1.5; + height: 40px; + min-width: 40px; + width: 40px; + white-space: nowrap; + cursor: pointer; + -webkit-transition: background 0.3s,color 0.3s,border-color 0.3s; + transition: background 0.3s,color 0.3s,border-color 0.3s; + background-color: #FFFFFF; + color: #59636f; + border: solid 1px rgba(0,0,0,0.16); + box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.16); } -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2s; - transition: all 2s; - will-change: transform; +.c3 span { + overflow: hidden; + text-overflow: ellipsis; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c3:disabled { + background-color: rgba(0,0,0,0.32); + color: rgba(0,0,0,0.32); + border-width: 1px; + border-color: rgba(0,0,0,0.16); + box-shadow: none; + cursor: default; } -.c0 ul li.active { - -webkit-transform: scale(1); - -ms-transform: scale(1); - transform: scale(1); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 20px; +.c3:disabled .icon { + color: rgba(0,0,0,0.32); } -.c2 { - border: 4px solid rgba(255,255,255,0.56); +.c3 .icon { + -webkit-transition: color 0.3s ease; + transition: color 0.3s ease; + color: rgba(0,0,0,0.32); + line-height: 1; } -
-
    -
  • - -
    - Organic Pepper -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Grapefruit -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Romaine Lettuce -
    -
  • -
-
-`; +.c3:not(:disabled):hover, +.c3:not(:disabled).hovered, +.c3:not(:disabled):active, +.c3:not(:disabled).active { + color: #3498db; + border-width: 2px; + border-color: #3498db; + box-shadow: 0px 4px 4px 0px rgba(0,0,0,0.16); + padding: 3px 3px; +} -exports[`Storyshots Carousel partial custom config 1`] = ` -.c3 { - font-family: Lato,sans-serif; - font-size: 88px; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - color: #2f313a; - text-align: center; - font-weight: 600; +.c3:not(:disabled):hover .icon, +.c3:not(:disabled).hovered .icon, +.c3:not(:disabled):active .icon, +.c3:not(:disabled).active .icon, +.c3:not(:disabled):focus .icon, +.c3:not(:disabled).focused .icon { + color: #3498db; } -.c1 { - box-sizing: border-box; - border-radius: 16px; - object-fit: cover; +.c3:not(:disabled).active, +.c3:not(:disabled):active { + box-shadow: none; +} + +.c3:focus, +.c3.focused { + outline: none; +} + +.c3.focus-visible, +.c3.focused:not(:disabled) { + box-shadow: 0 0 0 3px rgba(52,152,219,0.56); +} + +.c8 { + padding: 8px; +} + +.c8 * { + width: 100%; + border-radius: 20px; + box-shadow: 0px 4px 8px 0px rgba(0,0,0,0.08); +} + +.c7 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; } .c0 { - position: relative; -} - -.c0 ul { - position: relative; - left: 50%; - margin-left: -399.83200000000005px; - height: 439.83200000000005px; - list-style: none; - padding: 0; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} + +.c1 { + display: grid; + grid-template-columns: 1fr 10fr 1fr; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; +} + +.c6 { + width: 100%; + height: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-transition: all 250ms linear; + transition: all 250ms linear; + -ms-overflow-style: none; + -webkit-scrollbar-width: none; + -moz-scrollbar-width: none; + -ms-scrollbar-width: none; + scrollbar-width: none; + -webkit-transform: translateX( -100% ); + -ms-transform: translateX( -100% ); + transform: translateX( -100% ); +} + +.c6 > * { + width: 33.333333333333336%; + -webkit-flex-shrink: 0; + -ms-flex-negative: 0; + flex-shrink: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + -ms-flex-positive: 1; + flex-grow: 1; +} + +.c6::-webkit-scrollbar { + display: none; +} + +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + -ms-flex-pack: end; + justify-content: flex-end; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin-right: 16px; +} + +.c9 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -webkit-justify-content: flex-start; + -ms-flex-pack: start; + justify-content: flex-start; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-transform: translateX( 0px ); - -ms-transform: translateX( 0px ); - transform: translateX( 0px ); - -webkit-transition: -webkit-transform 2.5s; - -webkit-transition: transform 2.5s; - transition: transform 2.5s; - will-change: transform; + margin-left: 16px; } -.c0 ul li { - margin: 20px; - min-width: 656px; - width: 656px; - height: 328px; - -webkit-transition: all 2.5s; - transition: all 2.5s; - will-change: transform; +.c4 { + border-radius: 32px; +} + +.c10 { + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; } -.c0 ul li .image { - box-shadow: 0 4px 40px 0 rgba(0,0,0,0.32); +.c11 { + height: 8px; + width: 8px; + margin-right: 6px; + cursor: pointer; + border-radius: 50%; + background: rgba(0,0,0,0.08); } -.c0 ul li.active { - -webkit-transform: scale(1.219); - -ms-transform: scale(1.219); - transform: scale(1.219); - -webkit-transform-origin: bottom; - -ms-transform-origin: bottom; - transform-origin: bottom; - margin: 0 91.83200000000005px; +.c11.active { + background: rgba(0,0,0,0.48); } -.c2 { - border: 4px solid rgba(255,255,255,0.56); +@media (hover:none) and (pointer:coarse) { + .c4 { + display: none; + } }
-
    -
  • +
    -
    - Organic Pepper +
    -
  • -
  • -
    - Tomato +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Romaine Lettuce +
    +
    +
    +
    + Organic Pepper +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Grapefruit +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Romaine Lettuce +
    +
    +
    +
    + Organic Pepper +
    +
    +
    +
    + Tomato +
    +
    +
    +
    + Grapefruit +
    +
    +
    -
  • -
  • -
    - Grapefruit +
    -
  • -
  • +
    - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Tomato -
    -
  • -
  • - -
    - Romaine Lettuce -
    -
  • -
+ + + +
+ `; diff --git a/packages/carousel/src/components/Dots.js b/packages/carousel/src/components/Dots.js new file mode 100644 index 000000000..e4414d6d0 --- /dev/null +++ b/packages/carousel/src/components/Dots.js @@ -0,0 +1,25 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Dot, DotsContainer } from "../styledComponents/Dots"; + +function Dots({ slides, handleClick, selectedDot }) { + return ( + + {slides.map((item, index) => ( + handleClick(index)} + className={selectedDot === index ? "active" : ""} + /> + ))} + + ); +} + +Dots.propTypes = { + slides: PropTypes.node.isRequired, + handleClick: PropTypes.func, + selectedDot: PropTypes.number, +}; + +export default Dots; diff --git a/packages/carousel/src/components/Slide.js b/packages/carousel/src/components/Slide.js new file mode 100644 index 000000000..dd44f497f --- /dev/null +++ b/packages/carousel/src/components/Slide.js @@ -0,0 +1,23 @@ +import React from "react"; +import PropTypes from "prop-types"; + +import { Container, Wrapper } from "../styledComponents/Slide"; + +const Slide = ({ children, borderRadius, ...props }) => ( + + + {children} + + +); + +Slide.propTypes = { + children: PropTypes.node.isRequired, + borderRadius: PropTypes.number, +}; + +Slide.defaultProps = { + borderRadius: 20, +}; + +export default Slide; diff --git a/packages/carousel/src/hooks/useResizeWindow.js b/packages/carousel/src/hooks/useResizeWindow.js new file mode 100644 index 000000000..21e778bb0 --- /dev/null +++ b/packages/carousel/src/hooks/useResizeWindow.js @@ -0,0 +1,71 @@ +import { useState, useEffect, useRef, useCallback } from "react"; +import PropTypes from "prop-types"; + +import debounce from "lodash.debounce"; + +const getWidth = () => window.innerWidth; + +const useResizeWindow = ({ qtyOfSlidesPerSet, breakpoints }) => { + const RESIZE_DELAY = 300; + const [screendWidth, setScreenWidth] = useState(window.innerWidth); + const [screenThresholds, setScreenThresholds] = useState(breakpoints); + const [displayNumber, setDisplayNumber] = useState(qtyOfSlidesPerSet); + + const handleWindowSizeChange = () => { + setScreenWidth(window.innerWidth); + }; + + function handleResize() { + const screenSize = getWidth(); + for (let i = 0; i < screenThresholds.length; i += 1) { + if (screenSize <= screenThresholds[i].width) { + setDisplayNumber(screenThresholds[i].slidesToShow); + return; + } + } + setDisplayNumber(qtyOfSlidesPerSet); + } + + function sortBreakpoints() { + setScreenThresholds( + breakpoints.sort((a, b) => (a.width > b.width ? 1 : -1)), + ); + } + + useEffect(() => { + sortBreakpoints(); + }, []); + + const debouncedFunctionRef = useRef(); + debouncedFunctionRef.current = () => handleResize(); + + const debouncedChange = useCallback( + debounce(() => debouncedFunctionRef.current(), RESIZE_DELAY), + [], + ); + + useEffect(() => { + debouncedChange(); + }, [screendWidth]); + + useEffect(() => { + window.addEventListener("resize", handleWindowSizeChange); + return () => { + window.removeEventListener("resize", handleWindowSizeChange); + }; + }, []); + + return { displayNumber }; +}; + +useResizeWindow.propTypes = { + qtyOfSlidesPerSet: PropTypes.number, + breakpoints: PropTypes.arrayOf( + PropTypes.shape({ + width: PropTypes.number, + slidesToShow: PropTypes.number, + }), + ), +}; + +export default useResizeWindow; diff --git a/packages/carousel/src/hooks/useResizeWindow.test.js b/packages/carousel/src/hooks/useResizeWindow.test.js new file mode 100644 index 000000000..b07365a95 --- /dev/null +++ b/packages/carousel/src/hooks/useResizeWindow.test.js @@ -0,0 +1,165 @@ +import React from "react"; +import { render } from "@testing-library/react"; +import PropTypes from "prop-types"; +import useResizeWindow from "./useResizeWindow"; + +const CompWithResizeHook = ({ + displayNumber, + setDisplayNumber, + setCurrentIndex, + dotIndex, + numberOfCards, + defaultQtyOfSlides, + breakpoints, + infiniteLoop, +}) => { + useResizeWindow({ + displayNumber, + setDisplayNumber, + setCurrentIndex, + dotIndex, + numberOfCards, + defaultQtyOfSlides, + breakpoints, + infiniteLoop, + }); + + return ( +
+ image1.png +
+ ); +}; + +CompWithResizeHook.propTypes = { + displayNumber: PropTypes.number, + setDisplayNumber: PropTypes.func, + setCurrentIndex: PropTypes.func, + dotIndex: PropTypes.number, + numberOfCards: PropTypes.number, + defaultQtyOfSlides: PropTypes.number, + breakpoints: PropTypes.arrayOf(PropTypes.number), + infiniteLoop: PropTypes.bool, +}; + +describe("(Carousel/hooks) useResizeWindow", () => { + const setDisplayNumberMock = jest.fn(); + const setCurrentIndexMock = jest.fn(); + const spy = jest.fn(); + const testSmallWidth = 700; + const testMediumWidth = 900; + const testLargeWidth = 1600; + + beforeEach(() => { + window.addEventListener("resize", spy); + }); + + afterAll(() => { + jest.restoreAllMocks(); + window.removeEventListener("resize", spy); + }); + + const makeSut = ({ ...props }) => render(); + + it("should not fire resize event by default", () => { + const initialValues = { + displayNumber: 3, + setDisplayNumber: setDisplayNumberMock, + setCurrentIndex: setCurrentIndexMock, + dotIndex: 0, + numberOfCards: 5, + defaultQtyOfSlides: 3, + breakpoints: [1, 2], + infiniteLoop: true, + }; + makeSut(initialValues); + + expect(spy).not.toHaveBeenCalled(); + expect(window.innerWidth).not.toBeLessThanOrEqual(testSmallWidth); + expect(window.innerWidth).toBeGreaterThan(testMediumWidth); + expect(window.innerWidth).toBeLessThanOrEqual(testLargeWidth); + }); + + xdescribe("when resize event is fired", () => { + const initialDotIndex = 0; + + beforeAll(() => { + window.dispatchEvent(new Event("resize")); + }); + + it("should update the values relevant for a width lower than 768px", () => { + const initialValues = { + displayNumber: 3, + setDisplayNumber: setDisplayNumberMock, + setCurrentIndex: setCurrentIndexMock, + dotIndex: initialDotIndex, + numberOfCards: 5, + defaultQtyOfSlides: 3, + breakpoints: [1, 2], + infiniteLoop: true, + }; + // Set screenwidth to be 700 + window.innerWidth = testSmallWidth; + + makeSut(initialValues); + + expect(spy).toHaveBeenCalled(); + expect(window.innerWidth).toBe(testSmallWidth); + // Need to set de diplsay to 1 + expect(setDisplayNumberMock).toBeCalledWith(1); + // Current index will be dotIndex + 1 < numberOfCards ? dotIndex + 1 : 0 + expect(setCurrentIndexMock).toBeCalledWith(initialDotIndex + 1); + }); + + it("should update the values relevant for a width lower than 1200px", () => { + const initialValues = { + displayNumber: 3, + setDisplayNumber: setDisplayNumberMock, + setCurrentIndex: setCurrentIndexMock, + dotIndex: initialDotIndex, + numberOfCards: 5, + defaultQtyOfSlides: 3, + breakpoints: [1, 2], + infiniteLoop: true, + }; + // Set screenwidth to be 900 + window.innerWidth = testMediumWidth; + + makeSut(initialValues); + + expect(spy).toHaveBeenCalled(); + expect(window.innerWidth).toBe(testMediumWidth); + // Need to set de diplsay to 2 + expect(setDisplayNumberMock).toBeCalledWith(2); + // Current index will be numberOfCards > 2 ? dotIndex + 2 : 0 + expect(setCurrentIndexMock).toBeCalledWith(initialDotIndex + 2); + }); + + it("should update the values relevant for a width greater or equal than 1200px", () => { + const slidesToShowMock = 3; + const initialValues = { + displayNumber: 3, + setDisplayNumber: setDisplayNumberMock, + setCurrentIndex: setCurrentIndexMock, + dotIndex: initialDotIndex, + numberOfCards: 5, + defaultQtyOfSlides: slidesToShowMock, + breakpoints: [1, 2], + infiniteLoop: true, + }; + // Set screenwidth to be 1600 + window.innerWidth = testLargeWidth; + + makeSut(initialValues); + + expect(spy).toHaveBeenCalled(); + expect(window.innerWidth).toBe(testLargeWidth); + // Need to set de diplsay to slidesToShowMock + expect(setDisplayNumberMock).toBeCalledWith(slidesToShowMock); + // Current index will be dotIndex + slidesToShowMock + expect(setCurrentIndexMock).toBeCalledWith( + initialDotIndex + slidesToShowMock, + ); + }); + }); +}); diff --git a/packages/carousel/src/hooks/useTouch.js b/packages/carousel/src/hooks/useTouch.js new file mode 100644 index 000000000..6464081d9 --- /dev/null +++ b/packages/carousel/src/hooks/useTouch.js @@ -0,0 +1,38 @@ +import { useState } from "react"; +import PropTypes from "prop-types"; + +const useTouch = ({ nextSlide, prevSlide }) => { + const TOUCH_THRESHOLD = 5; + const [touchPosition, setTouchPosition] = useState(null); + const handleTouchStart = (event) => { + const touchDown = event.touches[0].clientX; + setTouchPosition(touchDown); + }; + + const handleTouchMove = (event) => { + const touchDown = touchPosition; + + if (touchDown === null) { + return; + } + const currentTouch = event.touches[0].clientX; + const touchDragDiff = touchDown - currentTouch; + + if (touchDragDiff > TOUCH_THRESHOLD) { + nextSlide(); + } + + if (touchDragDiff < -TOUCH_THRESHOLD) { + prevSlide(); + } + setTouchPosition(null); + }; + return { handleTouchStart, handleTouchMove }; +}; + +useTouch.propTypes = { + nextSlide: PropTypes.func, + prevSlide: PropTypes.func, +}; + +export default useTouch; diff --git a/packages/carousel/src/index.js b/packages/carousel/src/index.js index db04c20ed..ad6e449b6 100644 --- a/packages/carousel/src/index.js +++ b/packages/carousel/src/index.js @@ -1 +1,5 @@ -export { default } from "./Carousel"; +import Slide from "./components/Slide"; +import Carousel from "./Carousel"; +import useResizeWindow from "./hooks/useResizeWindow"; + +export { Carousel, Slide, useResizeWindow }; diff --git a/packages/carousel/src/styledComponents/Carousel.js b/packages/carousel/src/styledComponents/Carousel.js index 50a5879f0..beead5232 100644 --- a/packages/carousel/src/styledComponents/Carousel.js +++ b/packages/carousel/src/styledComponents/Carousel.js @@ -1,63 +1,57 @@ import styled from "styled-components"; -import { colors } from "@crave/farmblocks-theme"; +import Button from "@crave/farmblocks-button"; -const scale = (props) => (props.shouldScale ? 1.219 : 1); -const activeItemWidth = (props) => props.itemConfig.width * scale(props); -const activeItemHeight = (props) => props.itemConfig.height * scale(props); -const spaceBetweenItems = (props) => props.itemConfig.margin * 2; -const stepDistance = (props) => - props.itemConfig.width + spaceBetweenItems(props); -const activeItemMargin = (props) => { - const { itemConfig } = props; - const scaledWidth = itemConfig.width * scale(props); - - // We get the difference from scaled width and normal width. - // This difference is the total margin we have to compensate due to transform: scale. - // Then we divide it by 2 because we need to add this on left and right margin - const scaledMargin = (scaledWidth - itemConfig.width) / 2; - - // Just add the default margin to it - return scaledMargin + itemConfig.margin; -}; - -const Container = styled.div` - position: relative; - ul { - position: relative; - left: 50%; - margin-left: ${(props) => -(activeItemWidth(props) / 2)}px; - height: ${(props) => activeItemHeight(props) + spaceBetweenItems(props)}px; - list-style: none; - padding: 0; - display: inline-flex; - align-items: center; +export const Container = styled.div` + width: 100%; + display: flex; + flex-direction: column; +`; - transform: translateX( - ${(props) => -(props.activeItem * stepDistance(props))}px - ); - transition: transform ${(props) => props.itemConfig.transitionTime}s; - will-change: transform; +export const Wrapper = styled.div` + display: grid; + grid-template-columns: 1fr 10fr 1fr; + align-items: center; + justify-content: center; + flex-direction: row; +`; - li { - margin: ${(props) => props.itemConfig.margin}px; - min-width: ${(props) => props.itemConfig.width}px; - width: ${(props) => props.itemConfig.width}px; - height: ${(props) => props.itemConfig.height}px; +export const Content = styled.div` + width: 100%; + height: 100%; + display: flex; + transition: ${(props) => + props.transitionEnabled ? "all 250ms linear" : "none"}; + -ms-overflow-style: none; + scrollbar-width: none; + transform: translateX( + -${(props) => props.currentIndex * (100 / props.displayNumber)}% + ); + + & > * { + width: ${(props) => 100 / props.displayNumber}%; + flex-shrink: 0; + flex-grow: 1; + } + &::-webkit-scrollbar { + display: none; + } +`; - transition: all ${(props) => props.itemConfig.transitionTime}s; - will-change: transform; +export const ButtonContainer = styled.div` + display: flex; + justify-content: ${(props) => + props.direction === "left" ? "flex-end" : "flex-start"}; + align-items: center; + ${(props) => + props.direction === "left" ? "margin-right: 16px" : "margin-left: 16px"}; +`; - .image { - box-shadow: 0 4px 40px 0 ${colors.GREY_32}; - } +export const ArrowButton = styled(Button)` + border-radius: 32px; - &.active { - transform: scale(${scale}); - transform-origin: bottom; - margin: 0 ${activeItemMargin}px; - } + @media (hover: none) and (pointer: coarse) { + & { + display: none; } } `; - -export default Container; diff --git a/packages/carousel/src/styledComponents/Dots.js b/packages/carousel/src/styledComponents/Dots.js new file mode 100644 index 000000000..5f596bd9b --- /dev/null +++ b/packages/carousel/src/styledComponents/Dots.js @@ -0,0 +1,21 @@ +import styled from "styled-components"; + +export const DotsContainer = styled.div` + width: 100%; + display: flex; + align-items: center; + justify-content: center; +`; + +export const Dot = styled.span` + height: 8px; + width: 8px; + margin-right: 6px; + cursor: pointer; + border-radius: 50%; + background: rgba(0, 0, 0, 0.08); + + &.active { + background: rgba(0, 0, 0, 0.48); + } +`; diff --git a/packages/carousel/src/styledComponents/Slide.js b/packages/carousel/src/styledComponents/Slide.js new file mode 100644 index 000000000..0da0c4bd9 --- /dev/null +++ b/packages/carousel/src/styledComponents/Slide.js @@ -0,0 +1,16 @@ +import styled from "styled-components"; + +export const Container = styled.div` + padding: 8px; + * { + width: 100%; + border-radius: ${({ borderRadius }) => borderRadius}px; + box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.08); + } +`; + +export const Wrapper = styled.div` + display: flex; + align-items: center; + justify-content: center; +`;