@growth-angels/ds-core 0.0.1

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.
Files changed (63) hide show
  1. package/LICENSE +14 -0
  2. package/dist/atoms/Button/Button.d.ts +4 -0
  3. package/dist/atoms/Button/Button.js +21 -0
  4. package/dist/atoms/Button/Button.stories.d.ts +8 -0
  5. package/dist/atoms/Button/Button.stories.js +31 -0
  6. package/dist/atoms/Button/Button.types.d.ts +13 -0
  7. package/dist/atoms/Button/Button.types.js +1 -0
  8. package/dist/atoms/Icon/Icon.d.ts +2 -0
  9. package/dist/atoms/Icon/Icon.js +7 -0
  10. package/dist/atoms/Icon/Icon.stories.d.ts +6 -0
  11. package/dist/atoms/Icon/Icon.stories.js +22 -0
  12. package/dist/atoms/Icon/Icon.types.d.ts +5 -0
  13. package/dist/atoms/Icon/Icon.types.js +1 -0
  14. package/dist/atoms/Text/Text.d.ts +5 -0
  15. package/dist/atoms/Text/Text.js +8 -0
  16. package/dist/atoms/Text/Text.types.d.ts +6 -0
  17. package/dist/atoms/Text/Text.types.js +1 -0
  18. package/dist/atoms/atoms.d.ts +1 -0
  19. package/dist/atoms/atoms.js +1 -0
  20. package/dist/global.types.d.ts +3 -0
  21. package/dist/global.types.js +1 -0
  22. package/dist/hooks/useBreakPointObserver.d.ts +5 -0
  23. package/dist/hooks/useBreakPointObserver.js +21 -0
  24. package/dist/hooks/useReactAdaptater.d.ts +2 -0
  25. package/dist/hooks/useReactAdaptater.js +7 -0
  26. package/dist/hooks/useThemeAssets.d.ts +8 -0
  27. package/dist/hooks/useThemeAssets.js +12 -0
  28. package/dist/index.d.ts +4 -0
  29. package/dist/index.js +4 -0
  30. package/dist/layout/Container/Container.d.ts +3 -0
  31. package/dist/layout/Container/Container.js +6 -0
  32. package/dist/layout/Container/Container.types.d.ts +6 -0
  33. package/dist/layout/Container/Container.types.js +1 -0
  34. package/dist/layout/Grid/Grid.d.ts +3 -0
  35. package/dist/layout/Grid/Grid.js +6 -0
  36. package/dist/layout/Grid/Grid.types.d.ts +8 -0
  37. package/dist/layout/Grid/Grid.types.js +1 -0
  38. package/dist/layout/Grid/GridItem/GridItem.d.ts +3 -0
  39. package/dist/layout/Grid/GridItem/GridItem.js +11 -0
  40. package/dist/layout/Grid/GridItem/GridItem.types.d.ts +13 -0
  41. package/dist/layout/Grid/GridItem/GridItem.types.js +1 -0
  42. package/dist/layout/layout.d.ts +3 -0
  43. package/dist/layout/layout.js +3 -0
  44. package/dist/organisms/Card/Card.d.ts +3 -0
  45. package/dist/organisms/Card/Card.js +5 -0
  46. package/dist/organisms/Card/Card.types.d.ts +8 -0
  47. package/dist/organisms/Card/Card.types.js +1 -0
  48. package/dist/organisms/Card/CardDefault.stories.d.ts +7 -0
  49. package/dist/organisms/Card/CardDefault.stories.js +32 -0
  50. package/dist/organisms/Card/CardEditorial.stories.d.ts +7 -0
  51. package/dist/organisms/Card/CardEditorial.stories.js +32 -0
  52. package/dist/organisms/Carousel/Carousel.d.ts +2 -0
  53. package/dist/organisms/Carousel/Carousel.js +81 -0
  54. package/dist/organisms/Carousel/Carousel.stories.d.ts +6 -0
  55. package/dist/organisms/Carousel/Carousel.stories.js +31 -0
  56. package/dist/organisms/Carousel/Carousel.types.d.ts +20 -0
  57. package/dist/organisms/Carousel/Carousel.types.js +1 -0
  58. package/dist/organisms/organisms.d.ts +2 -0
  59. package/dist/organisms/organisms.js +2 -0
  60. package/dist/utils.d.ts +0 -0
  61. package/dist/utils.js +1 -0
  62. package/package.json +55 -0
  63. package/src/index.scss +3 -0
package/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mathieu ALBORÉ (Growth Angels)
4
+
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to use,
8
+ copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, subject to the condition that the above copyright notice and
10
+ this permission notice shall be included in all copies or substantial portions
11
+ of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED.
@@ -0,0 +1,4 @@
1
+ import { JSX } from 'react/jsx-runtime';
2
+ import type { ButtonProps } from './Button.types';
3
+ import React from 'react';
4
+ export declare const Button: <T extends React.ElementType = "button">(props: ButtonProps<T>) => JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Icon } from '../Icon/Icon';
4
+ export const Button = (props) => {
5
+ const { as, children, variant, preventDefault, icon, extraClassNames, ...restProps } = props;
6
+ let customVariant = variant;
7
+ if (icon) {
8
+ customVariant = 'icon';
9
+ }
10
+ const classNames = ['ga-ds-btn', `ga-ds-btn--${customVariant}`, ...(extraClassNames || [])];
11
+ const handleClick = (e) => {
12
+ if (preventDefault)
13
+ e.preventDefault();
14
+ props?.onClick?.(e);
15
+ };
16
+ return React.createElement(as || 'button', {
17
+ ...restProps,
18
+ className: classNames.join(' '),
19
+ onClick: handleClick
20
+ }, _jsxs(_Fragment, { children: [icon && _jsx(Icon, { name: icon, size: 'sm' }), children && children] }));
21
+ };
@@ -0,0 +1,8 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Button } from './Button';
3
+ declare const meta: Meta<typeof Button>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Button>;
6
+ export declare const Primary: Story;
7
+ export declare const Secondary: Story;
8
+ export declare const Link: Story;
@@ -0,0 +1,31 @@
1
+ import { Button } from './Button';
2
+ const meta = {
3
+ title: 'Atoms/Button',
4
+ component: Button,
5
+ tags: ['autodocs'],
6
+ };
7
+ export default meta;
8
+ export const Primary = {
9
+ args: {
10
+ variant: 'primary',
11
+ children: 'Button',
12
+ as: 'a',
13
+ href: '#',
14
+ },
15
+ };
16
+ export const Secondary = {
17
+ args: {
18
+ variant: 'secondary',
19
+ children: 'Button',
20
+ as: 'a',
21
+ href: '#',
22
+ },
23
+ };
24
+ export const Link = {
25
+ args: {
26
+ variant: 'link',
27
+ children: 'Button',
28
+ as: 'a',
29
+ href: '#',
30
+ },
31
+ };
@@ -0,0 +1,13 @@
1
+ import { WordpressDefault } from "../../global.types.js";
2
+ import React, { ElementType, ComponentPropsWithoutRef } from "react";
3
+ export type Variant = "primary" | "secondary" | "tertiary" | "link" | "icon";
4
+ export type ButtonProps<T extends ElementType = "button"> = {
5
+ as?: T;
6
+ variant?: Variant;
7
+ hasIcon?: "left" | "right";
8
+ icon?: "chevron-left" | "chevron-right";
9
+ preventDefault?: boolean;
10
+ children?: React.ReactNode;
11
+ } & WordpressDefault & Omit<ComponentPropsWithoutRef<T>, "as" | "className" | "onClick"> & {
12
+ onClick?: React.MouseEventHandler<React.ElementRef<T>>;
13
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { IconProps } from "./Icon.types";
2
+ export declare const Icon: ({ name, size }: IconProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useThemeAssets } from "../../hooks/useThemeAssets";
3
+ export const Icon = ({ name, size }) => {
4
+ const { iconsSprite } = useThemeAssets();
5
+ const classeNames = ['ga-ds-icon', ...(size ? [`ga-ds-icon--${size}`] : [])];
6
+ return _jsx("svg", { className: classeNames.join(' '), xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", children: _jsx("use", { xlinkHref: `${iconsSprite}#${name}` }) });
7
+ };
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Icon } from './Icon';
3
+ declare const meta: Meta<typeof Icon>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Icon>;
6
+ export declare const Primary: Story;
@@ -0,0 +1,22 @@
1
+ import { Icon } from './Icon';
2
+ const meta = {
3
+ title: 'Atoms/Icon',
4
+ component: Icon,
5
+ tags: ['autodocs'],
6
+ argTypes: {
7
+ name: {
8
+ control: 'select',
9
+ options: ['chevron-left', 'chevron-right'],
10
+ },
11
+ size: {
12
+ control: 'radio',
13
+ options: [undefined, 'sm', 'md', 'lg'],
14
+ },
15
+ }
16
+ };
17
+ export default meta;
18
+ export const Primary = {
19
+ args: {
20
+ name: 'chevron-left'
21
+ }
22
+ };
@@ -0,0 +1,5 @@
1
+ export interface IconProps {
2
+ name: string;
3
+ size?: 'sm' | 'md' | 'lg';
4
+ spriteFile?: string;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ import { TextProps } from "./Text.types";
3
+ export declare const Text: (props: TextProps) => React.DetailedReactHTMLElement<{
4
+ className: string;
5
+ }, HTMLElement>;
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ export const Text = (props) => {
3
+ const { as, children, classNames, type = "paragraph" } = props;
4
+ const className = typeof classNames === 'string' ? classNames : classNames?.join(' ') || '';
5
+ return React.createElement(as, {
6
+ className: `ga-ds-${type} ${className}`,
7
+ }, children);
8
+ };
@@ -0,0 +1,6 @@
1
+ export interface TextProps {
2
+ as: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span';
3
+ classNames?: string[] | string;
4
+ type?: 'heading' | 'paragraph';
5
+ children: string;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export * from './Button/Button';
@@ -0,0 +1 @@
1
+ export * from './Button/Button';
@@ -0,0 +1,3 @@
1
+ export interface WordpressDefault {
2
+ extraClassNames?: string[];
3
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ export declare function useBreakpointObserver(breakpoints?: {
2
+ sm: number;
3
+ md: number;
4
+ lg: number;
5
+ }): "sm" | "md" | "lg";
@@ -0,0 +1,21 @@
1
+ import { useReactAdapter } from './useReactAdaptater';
2
+ export function useBreakpointObserver(breakpoints = { sm: 640, md: 1024, lg: 1280 }) {
3
+ const { useEffect, useState } = useReactAdapter();
4
+ const [current, setCurrent] = useState('sm');
5
+ useEffect(() => {
6
+ let frameId;
7
+ const check = () => {
8
+ const width = window.innerWidth;
9
+ let bp = 'sm';
10
+ if (width >= breakpoints.md)
11
+ bp = 'lg';
12
+ else if (width >= breakpoints.sm)
13
+ bp = 'md';
14
+ setCurrent((prev) => (prev !== bp ? bp : prev));
15
+ frameId = requestAnimationFrame(check);
16
+ };
17
+ frameId = requestAnimationFrame(check);
18
+ return () => cancelAnimationFrame(frameId);
19
+ }, [breakpoints]);
20
+ return current;
21
+ }
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const useReactAdapter: () => typeof React;
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export const useReactAdapter = () => {
3
+ if (typeof window === 'undefined' || !window.wp || !window.wp.element) {
4
+ return React;
5
+ }
6
+ return window.wp.element;
7
+ };
@@ -0,0 +1,8 @@
1
+ declare let defaultThemeAssets: {
2
+ iconsSprite: string;
3
+ };
4
+ export declare const setThemeAssets: (assets: typeof defaultThemeAssets) => void;
5
+ export declare const useThemeAssets: () => {
6
+ iconsSprite: string;
7
+ };
8
+ export {};
@@ -0,0 +1,12 @@
1
+ let defaultThemeAssets = {
2
+ iconsSprite: '/assets/svg/sprites/icons.svg'
3
+ };
4
+ export const setThemeAssets = (assets) => {
5
+ defaultThemeAssets = {
6
+ ...defaultThemeAssets,
7
+ ...assets,
8
+ };
9
+ };
10
+ export const useThemeAssets = () => {
11
+ return defaultThemeAssets;
12
+ };
@@ -0,0 +1,4 @@
1
+ export * from './atoms/atoms';
2
+ export * from './organisms/organisms';
3
+ export * from './layout/layout';
4
+ export { setThemeAssets } from './hooks/useThemeAssets';
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './atoms/atoms';
2
+ export * from './organisms/organisms';
3
+ export * from './layout/layout';
4
+ export { setThemeAssets } from './hooks/useThemeAssets';
@@ -0,0 +1,3 @@
1
+ import type { JSX } from 'react/jsx-runtime';
2
+ import type { ContainerProps } from './Container.types';
3
+ export declare const Container: (props: ContainerProps) => JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export const Container = (props) => {
3
+ const { size, children } = props;
4
+ const classes = ['ga-ds-container', `ga-ds-container--${size}`, ...(props.extraClassNames || [])];
5
+ return _jsx("div", { className: classes.join(' '), children: children });
6
+ };
@@ -0,0 +1,6 @@
1
+ import { WordpressDefault } from "../../global.types";
2
+ export type ContainerSize = 'large' | 'medium' | 'small';
3
+ export interface ContainerProps extends WordpressDefault {
4
+ size: ContainerSize;
5
+ children: React.ReactNode | React.ReactNode[];
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { JSX } from 'react/jsx-runtime';
2
+ import { GridProps } from './Grid.types';
3
+ export declare const Grid: (props: GridProps) => JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export const Grid = (props) => {
3
+ const { children, alignItems, justifyContent, extraClassNames } = props;
4
+ const classNames = ['ga-ds-grid', ...(extraClassNames || [])];
5
+ return _jsx("div", { className: classNames.join(' '), style: { alignItems, justifyContent }, children: children });
6
+ };
@@ -0,0 +1,8 @@
1
+ import { WordpressDefault } from "../../global.types";
2
+ export interface Attributes {
3
+ alignItems: 'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline';
4
+ justifyContent: 'flex-start' | 'center' | 'flex-end' | 'space-between' | 'space-around';
5
+ }
6
+ export interface GridProps extends WordpressDefault, Attributes {
7
+ children: React.ReactNode | React.ReactNode[];
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { JSX } from 'react/jsx-runtime';
2
+ import { GridItemProps } from './GridItem.types';
3
+ export declare const GridItem: (props: GridItemProps) => JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export const GridItem = (props) => {
3
+ const { children, sizes = {
4
+ xs: 12,
5
+ sm: 12,
6
+ md: 12,
7
+ lg: 12,
8
+ } } = props;
9
+ const style = Object.fromEntries(Object.entries(sizes).map(([key, value]) => [`--ga-ds-grid-item-size-${key}`, `${value}`]));
10
+ return _jsx("div", { className: "ga-ds-grid-item", style: style, children: children });
11
+ };
@@ -0,0 +1,13 @@
1
+ import { WordpressDefault } from "../../../global.types";
2
+ export type ColumnSize = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '10' | '11' | '12';
3
+ export interface Attributes {
4
+ sizes: {
5
+ xs: ColumnSize;
6
+ sm: ColumnSize;
7
+ md: ColumnSize;
8
+ lg: ColumnSize;
9
+ };
10
+ }
11
+ export interface GridItemProps extends WordpressDefault, Attributes {
12
+ children: React.ReactNode | React.ReactNode[];
13
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export * from './Container/Container';
2
+ export * from './Grid/Grid';
3
+ export * from './Grid/GridItem/GridItem';
@@ -0,0 +1,3 @@
1
+ export * from './Container/Container';
2
+ export * from './Grid/Grid';
3
+ export * from './Grid/GridItem/GridItem';
@@ -0,0 +1,3 @@
1
+ import { JSX } from 'react/jsx-runtime';
2
+ import type { CardProps } from './Card.types';
3
+ export declare const Card: ({ children, variant, extraClassNames, type }: CardProps) => JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export const Card = ({ children, variant = 'primary', extraClassNames, type = 'default' }) => {
3
+ const classNames = ['ga-ds-card', `ga-ds-card--${variant}`, `ga-ds-card--${type}`, ...(extraClassNames || [])];
4
+ return _jsx("div", { className: classNames.join(' '), children: children });
5
+ };
@@ -0,0 +1,8 @@
1
+ export type Variant = 'primary' | 'secondary';
2
+ export type CardType = 'default' | 'editorial' | 'image' | 'icon';
3
+ export interface CardProps {
4
+ children: React.ReactNode | React.ReactNode[] | JSX.Element;
5
+ variant: Variant;
6
+ type?: CardType;
7
+ extraClassNames?: string[];
8
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Card } from './Card';
3
+ declare const meta: Meta<typeof Card>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Card>;
6
+ export declare const Primary: Story;
7
+ export declare const Secondary: Story;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Card } from './Card';
3
+ import { Button } from '../../atoms/atoms';
4
+ import CardDefaultHeader600x400 from '../../../assets/600x400.svg';
5
+ import CardDefaultHeader50x50 from '../../../assets/50x50.svg';
6
+ const meta = {
7
+ title: 'Organisms/Card/Default',
8
+ component: Card,
9
+ tags: ['autodocs'],
10
+ };
11
+ export default meta;
12
+ const CardChildren = ({ image }) => {
13
+ const images = {
14
+ '400x600': CardDefaultHeader600x400,
15
+ '50x50': CardDefaultHeader50x50
16
+ };
17
+ return _jsxs(_Fragment, { children: [_jsx("div", { className: "ga-ds-card__header", children: _jsx("img", { src: images[image], alt: "Card header" }) }), _jsx("div", { className: "ga-ds-card__title", children: _jsx("h2", { children: "Card title" }) }), _jsx("div", { className: 'ga-ds-card__content', children: _jsx("p", { children: "Lorem ipsum dolor sit amet consectetur, adipisicing elit. Porro temporibus quam ex consequatur est laboriosam nam quisquam doloremque perferendis quo ut, tempora error neque modi delectus assumenda! A, doloremque nulla." }) }), _jsx("div", { className: "ga-ds-card__footer", children: _jsx(Button, { as: "a", variant: 'primary', children: "Read more" }) })] });
18
+ };
19
+ export const Primary = {
20
+ args: {
21
+ variant: 'primary',
22
+ type: 'default',
23
+ children: _jsx(CardChildren, { image: '400x600' })
24
+ }
25
+ };
26
+ export const Secondary = {
27
+ args: {
28
+ variant: 'secondary',
29
+ type: 'default',
30
+ children: _jsx(CardChildren, { image: '400x600' })
31
+ }
32
+ };
@@ -0,0 +1,7 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Card } from './Card';
3
+ declare const meta: Meta<typeof Card>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Card>;
6
+ export declare const Primary: Story;
7
+ export declare const Secondary: Story;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Card } from './Card';
3
+ import { Button } from '../../atoms/atoms';
4
+ import CardDefaultHeader600x400 from '../../../assets/600x400.svg';
5
+ import CardDefaultHeader50x50 from '../../../assets/50x50.svg';
6
+ const meta = {
7
+ title: 'Organisms/Card/Editorial',
8
+ component: Card,
9
+ tags: ['autodocs'],
10
+ };
11
+ export default meta;
12
+ const CardChildren = ({ image }) => {
13
+ const images = {
14
+ '400x600': CardDefaultHeader600x400,
15
+ '50x50': CardDefaultHeader50x50
16
+ };
17
+ return _jsxs(_Fragment, { children: [_jsx("div", { className: "ga-ds-card__header", children: _jsx("img", { src: images[image], alt: "Card header" }) }), _jsx("div", { className: "ga-ds-card__title", children: _jsx("h2", { children: "Card title" }) }), _jsx("div", { className: 'ga-ds-card__content', children: _jsx("p", { children: "Lorem ipsum dolor sit amet consectetur, adipisicing elit. Porro temporibus quam ex consequatur est laboriosam nam quisquam doloremque perferendis quo ut, tempora error neque modi delectus assumenda! A, doloremque nulla." }) }), _jsx("div", { className: "ga-ds-card__footer", children: _jsx(Button, { as: "a", variant: 'primary', children: "Read more" }) })] });
18
+ };
19
+ export const Primary = {
20
+ args: {
21
+ variant: 'primary',
22
+ type: 'editorial',
23
+ children: _jsx(CardChildren, { image: '50x50' })
24
+ }
25
+ };
26
+ export const Secondary = {
27
+ args: {
28
+ variant: 'secondary',
29
+ type: 'editorial',
30
+ children: _jsx(CardChildren, { image: '50x50' })
31
+ }
32
+ };
@@ -0,0 +1,2 @@
1
+ import { CarouselProps } from "./Carousel.types";
2
+ export declare const Carousel: (props: CarouselProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "../../atoms/atoms";
3
+ import { useBreakpointObserver } from "../../hooks/useBreakPointObserver";
4
+ import { useReactAdapter } from "../../hooks/useReactAdaptater";
5
+ export const Carousel = (props) => {
6
+ const { children, slidesPerView = { sm: 1, md: 2, lg: 3 }, spaceBetween = 20, navigation, pagination, context, hasPagination, hasNavigation, } = props;
7
+ const { useEffect, useState, useRef, Children } = useReactAdapter();
8
+ const trackRef = useRef(null);
9
+ const slides = Children.toArray(children);
10
+ const calculatePages = (totalSlides = 0, slidesPerView = 0, step = 1) => {
11
+ return Math.max(1, Math.ceil((totalSlides - slidesPerView) / step) + 1);
12
+ };
13
+ const [activeSlideIndex, setActiveSlideIndex] = useState(0);
14
+ const [isAtEnd, setIsAtEnd] = useState(false);
15
+ const [isAtStart, setIsAtStart] = useState(true);
16
+ const [totalPages, setTotalPages] = useState(0);
17
+ useEffect(() => {
18
+ setIsAtStart(activeSlideIndex === 0);
19
+ setIsAtEnd(activeSlideIndex === totalPages - 1);
20
+ }, [activeSlideIndex, totalPages]);
21
+ const breakpoint = useBreakpointObserver({ sm: 768, md: 992, lg: 1200 });
22
+ useEffect(() => {
23
+ setTotalPages(calculatePages(slides.length, slidesPerView[breakpoint], 1));
24
+ }, [breakpoint, slidesPerView]);
25
+ const style = Object.fromEntries(Object.entries(slidesPerView).map(([key, value]) => [`--ga-ds-slides-per-view-${key}`, `${value}`]));
26
+ const goPrev = () => {
27
+ if (!trackRef.current)
28
+ return;
29
+ const slides = trackRef.current.querySelectorAll(".ga-ds-carousel__slide");
30
+ if (activeSlideIndex === 0)
31
+ return;
32
+ const nextIndex = activeSlideIndex - 1;
33
+ slides[nextIndex]?.scrollIntoView({
34
+ behavior: "smooth",
35
+ block: "nearest",
36
+ inline: "start",
37
+ });
38
+ setActiveSlideIndex(nextIndex);
39
+ };
40
+ const goNext = () => {
41
+ if (!trackRef.current)
42
+ return;
43
+ const slides = trackRef.current.querySelectorAll(".ga-ds-carousel__slide");
44
+ const totalSlides = slides.length;
45
+ if (activeSlideIndex >= totalSlides - 1)
46
+ return;
47
+ if (isAtEnd)
48
+ return;
49
+ const nextIndex = activeSlideIndex + 1;
50
+ slides[nextIndex]?.scrollIntoView({
51
+ behavior: "smooth",
52
+ block: "nearest",
53
+ inline: "start",
54
+ });
55
+ setActiveSlideIndex(nextIndex);
56
+ };
57
+ const goTo = (nextIndex) => {
58
+ if (!trackRef.current)
59
+ return;
60
+ const slides = trackRef.current.querySelectorAll(".ga-ds-carousel__slide");
61
+ slides[nextIndex]?.scrollIntoView({
62
+ behavior: "smooth",
63
+ block: "nearest",
64
+ inline: "start",
65
+ });
66
+ setActiveSlideIndex(nextIndex);
67
+ };
68
+ return (_jsxs("div", { className: "ga-ds-carousel", style: style, children: [navigation?.positionY === "top" && hasNavigation && (_jsx(CarouselNavigation, { goPrev: goPrev, goNext: goNext, isAtStart: isAtStart, isAtEnd: isAtEnd })), _jsx("div", { className: "ga-ds-carousel__track", ref: trackRef, style: {
69
+ "--ga-ds-space-between": `${spaceBetween / 10}rem`,
70
+ }, children: context === "wp-editor"
71
+ ? children
72
+ : slides.map((child, index) => (_jsx("div", { className: `ga-ds-carousel__slide ${index === activeSlideIndex ? "ga-ds-carousel__slide--active" : ""}`, children: child }, index))) }), _jsxs("div", { className: "ga-ds-carousel__navigation", children: [pagination && hasPagination && (_jsx(CarouselPagination, { totalPages: totalPages, activeSlideIndex: activeSlideIndex, goTo: goTo, clickable: pagination.clickable })), hasNavigation && navigation?.positionY === "bottom" && (_jsx(CarouselNavigation, { goPrev: goPrev, goNext: goNext, isAtStart: isAtStart, isAtEnd: isAtEnd }))] })] }));
73
+ };
74
+ const CarouselNavigation = ({ goPrev, goNext, isAtStart, isAtEnd, }) => {
75
+ return (_jsxs("div", { className: `ga-ds-carousel__arrows`, children: [_jsx(Button, { extraClassNames: ["ga-ds-carousel__button", "ga-ds-carousel__button--prev"], icon: "chevron-left", onClick: goPrev, disabled: isAtStart }), _jsx(Button, { extraClassNames: ["ga-ds-carousel__button", "ga-ds-carousel__button--next"], icon: "chevron-right", onClick: goNext, disabled: isAtEnd })] }));
76
+ };
77
+ const CarouselPagination = ({ totalPages, activeSlideIndex, goTo, clickable, }) => {
78
+ return (_jsx("div", { className: "ga-ds-carousel__dots", children: Array.from({ length: totalPages }, (_, index) => index).map((_, index) => (_jsx("span", { className: `ga-ds-carousel__dot ${index === activeSlideIndex ? "ga-ds-carousel__dot--active" : ""}`, onClick: () => clickable && goTo(index), style: {
79
+ cursor: clickable ? "pointer" : "default",
80
+ } }, index))) }));
81
+ };
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import { Carousel } from "./Carousel";
3
+ declare const meta: Meta<typeof Carousel>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof Carousel>;
6
+ export declare const Primary: Story;
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Carousel } from "./Carousel";
3
+ const meta = {
4
+ title: "Organisms/Carousel",
5
+ component: Carousel,
6
+ tags: ["autodocs"],
7
+ };
8
+ export default meta;
9
+ export const Primary = {
10
+ args: {
11
+ children: [
12
+ _jsx("div", { children: "Slide 1" }),
13
+ _jsx("div", { children: "Slide 2" }),
14
+ _jsx("div", { children: "Slide 3" }),
15
+ _jsx("div", { children: "Slide 4" }),
16
+ _jsx("div", { children: "Slide 5" }),
17
+ _jsx("div", { children: "Slide 6" }),
18
+ _jsx("div", { children: "Slide 7" }),
19
+ ],
20
+ slidesPerView: { sm: 1, md: 2, lg: 3 },
21
+ spaceBetween: 16,
22
+ pagination: {
23
+ clickable: true,
24
+ },
25
+ navigation: {
26
+ positionY: "bottom",
27
+ },
28
+ hasNavigation: true,
29
+ hasPagination: true,
30
+ },
31
+ };
@@ -0,0 +1,20 @@
1
+ export type Attributes = {
2
+ context?: 'wp-editor';
3
+ slidesPerView?: {
4
+ sm: number;
5
+ md: number;
6
+ lg: number;
7
+ };
8
+ spaceBetween?: number;
9
+ hasPagination?: boolean;
10
+ hasNavigation?: boolean;
11
+ pagination?: {
12
+ clickable: boolean;
13
+ };
14
+ navigation?: {
15
+ positionY: 'bottom' | 'top';
16
+ };
17
+ };
18
+ export interface CarouselProps extends Attributes {
19
+ children: React.ReactNode | React.ReactNode[];
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from './Card/Card';
2
+ export * from './Carousel/Carousel';
@@ -0,0 +1,2 @@
1
+ export * from './Card/Card';
2
+ export * from './Carousel/Carousel';
File without changes
package/dist/utils.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@growth-angels/ds-core",
3
+ "version": "0.0.1",
4
+ "description": "Design system by Growth Angels",
5
+ "license": "MIT",
6
+ "private": false,
7
+ "main": "dist/index.js",
8
+ "module": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "style": "src/index.scss",
11
+ "sideEffects": [
12
+ "src/index.scss"
13
+ ],
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/index.js",
17
+ "types": "./dist/index.d.ts"
18
+ },
19
+ "./styles": "./src/index.scss"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "src/index.scss"
24
+ ],
25
+ "scripts": {
26
+ "clean": "rm -rf dist",
27
+ "dev": "concurrently \"tsc --watch --preserveWatchOutput\" \"storybook dev -p 6006\"",
28
+ "build": "tsc",
29
+ "prepublishOnly": "pnpm build",
30
+ "storybook": "storybook dev -p 6006",
31
+ "build-storybook": "storybook build"
32
+ },
33
+ "dependencies": {
34
+ "@ga/foundation": "workspace:*"
35
+ },
36
+ "peerDependencies": {
37
+ "react": ">=18"
38
+ },
39
+ "devDependencies": {
40
+ "@chromatic-com/storybook": "^4.1.1",
41
+ "@storybook/addon-a11y": "^9.1.13",
42
+ "@storybook/addon-docs": "^9.1.13",
43
+ "@storybook/addon-vitest": "^9.1.13",
44
+ "@storybook/react-vite": "^9.1.13",
45
+ "@types/react": "^18.0.0",
46
+ "@vitest/browser": "^3.2.4",
47
+ "@vitest/coverage-v8": "^3.2.4",
48
+ "concurrently": "^9.2.1",
49
+ "playwright": "^1.56.1",
50
+ "sass": "^1.93.2",
51
+ "storybook": "^9.1.13",
52
+ "typescript": "^5.4.0",
53
+ "vitest": "^3.2.4"
54
+ }
55
+ }
package/src/index.scss ADDED
@@ -0,0 +1,3 @@
1
+ @use "./atoms/atoms";
2
+ @use "./organisms/organisms";
3
+ @use "./layout/layout";