@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.
- package/LICENSE +14 -0
- package/dist/atoms/Button/Button.d.ts +4 -0
- package/dist/atoms/Button/Button.js +21 -0
- package/dist/atoms/Button/Button.stories.d.ts +8 -0
- package/dist/atoms/Button/Button.stories.js +31 -0
- package/dist/atoms/Button/Button.types.d.ts +13 -0
- package/dist/atoms/Button/Button.types.js +1 -0
- package/dist/atoms/Icon/Icon.d.ts +2 -0
- package/dist/atoms/Icon/Icon.js +7 -0
- package/dist/atoms/Icon/Icon.stories.d.ts +6 -0
- package/dist/atoms/Icon/Icon.stories.js +22 -0
- package/dist/atoms/Icon/Icon.types.d.ts +5 -0
- package/dist/atoms/Icon/Icon.types.js +1 -0
- package/dist/atoms/Text/Text.d.ts +5 -0
- package/dist/atoms/Text/Text.js +8 -0
- package/dist/atoms/Text/Text.types.d.ts +6 -0
- package/dist/atoms/Text/Text.types.js +1 -0
- package/dist/atoms/atoms.d.ts +1 -0
- package/dist/atoms/atoms.js +1 -0
- package/dist/global.types.d.ts +3 -0
- package/dist/global.types.js +1 -0
- package/dist/hooks/useBreakPointObserver.d.ts +5 -0
- package/dist/hooks/useBreakPointObserver.js +21 -0
- package/dist/hooks/useReactAdaptater.d.ts +2 -0
- package/dist/hooks/useReactAdaptater.js +7 -0
- package/dist/hooks/useThemeAssets.d.ts +8 -0
- package/dist/hooks/useThemeAssets.js +12 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/layout/Container/Container.d.ts +3 -0
- package/dist/layout/Container/Container.js +6 -0
- package/dist/layout/Container/Container.types.d.ts +6 -0
- package/dist/layout/Container/Container.types.js +1 -0
- package/dist/layout/Grid/Grid.d.ts +3 -0
- package/dist/layout/Grid/Grid.js +6 -0
- package/dist/layout/Grid/Grid.types.d.ts +8 -0
- package/dist/layout/Grid/Grid.types.js +1 -0
- package/dist/layout/Grid/GridItem/GridItem.d.ts +3 -0
- package/dist/layout/Grid/GridItem/GridItem.js +11 -0
- package/dist/layout/Grid/GridItem/GridItem.types.d.ts +13 -0
- package/dist/layout/Grid/GridItem/GridItem.types.js +1 -0
- package/dist/layout/layout.d.ts +3 -0
- package/dist/layout/layout.js +3 -0
- package/dist/organisms/Card/Card.d.ts +3 -0
- package/dist/organisms/Card/Card.js +5 -0
- package/dist/organisms/Card/Card.types.d.ts +8 -0
- package/dist/organisms/Card/Card.types.js +1 -0
- package/dist/organisms/Card/CardDefault.stories.d.ts +7 -0
- package/dist/organisms/Card/CardDefault.stories.js +32 -0
- package/dist/organisms/Card/CardEditorial.stories.d.ts +7 -0
- package/dist/organisms/Card/CardEditorial.stories.js +32 -0
- package/dist/organisms/Carousel/Carousel.d.ts +2 -0
- package/dist/organisms/Carousel/Carousel.js +81 -0
- package/dist/organisms/Carousel/Carousel.stories.d.ts +6 -0
- package/dist/organisms/Carousel/Carousel.stories.js +31 -0
- package/dist/organisms/Carousel/Carousel.types.d.ts +20 -0
- package/dist/organisms/Carousel/Carousel.types.js +1 -0
- package/dist/organisms/organisms.d.ts +2 -0
- package/dist/organisms/organisms.js +2 -0
- package/dist/utils.d.ts +0 -0
- package/dist/utils.js +1 -0
- package/package.json +55 -0
- 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,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,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,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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Button/Button';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Button/Button';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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,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
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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,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,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,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,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 {};
|
package/dist/utils.d.ts
ADDED
|
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