diff --git a/packages/components/button/src/button.ts b/packages/components/button/src/button.ts index 9743c804..b5363ff5 100644 --- a/packages/components/button/src/button.ts +++ b/packages/components/button/src/button.ts @@ -22,6 +22,10 @@ export enum PuikButtonSizes { Medium = 'md', Large = 'lg', } +export enum PuikButtonLoaderPositions { + Left = 'left', + Right = 'right' +} export interface ButtonProps { variant?: PuikButtonVariants | `${PuikButtonVariants}` @@ -32,6 +36,8 @@ export interface ButtonProps { disabledReason?: string leftIcon?: string rightIcon?: string + loading?: boolean + loaderPosition?: `${PuikButtonLoaderPositions}` to?: RouteLocationRaw href?: string value?: string | number | Record | any[] diff --git a/packages/components/button/src/button.vue b/packages/components/button/src/button.vue index d35c8400..a42cc002 100644 --- a/packages/components/button/src/button.vue +++ b/packages/components/button/src/button.vue @@ -20,6 +20,13 @@ :data-test="dataTest" @click="setSelected" > + + (), { variant: PuikButtonVariants.Primary, - size: PuikButtonSizes.Medium + size: PuikButtonSizes.Medium, + loading: false, + loaderPosition: PuikButtonLoaderPositions.Right }); const { t } = useLocale(); @@ -86,10 +102,18 @@ const setSelected = () => { buttonGroup.selected.value = props.value; } }; + +const loaderColor = computed(() => { + if (props.variant === 'primary' || props.variant === 'secondary-reverse' || props.variant === 'text-reverse' || props.variant === 'destructive' || props.disabled) { + return 'reverse'; + } + return 'primary'; +}); diff --git a/packages/components/button/stories/button.stories.ts b/packages/components/button/stories/button.stories.ts index abea0187..edc3d829 100644 --- a/packages/components/button/stories/button.stories.ts +++ b/packages/components/button/stories/button.stories.ts @@ -1,10 +1,12 @@ -import { PuikButton, PuikButtonVariants, PuikButtonSizes } from '@prestashopcorp/puik-components'; +import { PuikButton, PuikButtonVariants, PuikButtonSizes, PuikButtonLoaderPositions } from '@prestashopcorp/puik-components'; import type { StoryObj, Meta, StoryFn, Args } from '@storybook/vue3'; const buttonVariants = Object.values(PuikButtonVariants); const buttonVariantsSummary = buttonVariants.join('|'); const buttonSizes = Object.values(PuikButtonSizes); const buttonSizesSummary = buttonSizes.join('|'); +const buttonLoaderPositions = Object.values(PuikButtonLoaderPositions); +const buttonLoaderPositionsSummary = buttonLoaderPositions.join('|'); export default { title: 'Components/Button', @@ -66,6 +68,31 @@ export default { rightIcon: { description: 'Sets the button right icon' }, + loading: { + control: 'boolean', + description: 'Sets the loading state of the button', + table: { + defaultValue: { + summary: false + }, + type: { + summary: 'boolean' + } + } + }, + loaderPosition: { + control: 'select', + description: 'Sets the loading position of the button', + options: buttonLoaderPositions, + table: { + defaultValue: { + summary: 'right' + }, + type: { + summary: buttonLoaderPositionsSummary + } + } + }, default: { control: 'text', description: 'Label/Content of the button' @@ -109,6 +136,8 @@ export default { disabledReason: 'Reason not specified', leftIcon: '', rightIcon: '', + loading: false, + loaderPosition: PuikButtonLoaderPositions.Right, to: undefined, href: undefined, default: 'Add to cart' @@ -238,6 +267,53 @@ const AllReversedVariantsTemplate: StoryFn = (args: Args, storyContext) => ({ ` }); +const LoadingTemplate: StoryFn = (args: Args, storyContext) => ({ + components: { PuikButton }, + args: { + loading: true + }, + setup() { + const loaderPositions = storyContext.argTypes.loaderPosition.options; + console.log(storyContext.argTypes.loaderPosition.options); + return { + args, + loaderPositions + }; + }, + template: ` +
+ +
+ ` +}); + +export const LoadingState: StoryObj = { + render: LoadingTemplate, + + parameters: { + docs: { + source: { + code: ` + + + Loading ... + + + + Loading ... + + + `, + language: 'html' + } + } + } +}; + export const Primary: StoryObj = { render: ButtonTemplate, diff --git a/packages/components/button/style/css.ts b/packages/components/button/style/css.ts index dd7a965b..2600c561 100644 --- a/packages/components/button/style/css.ts +++ b/packages/components/button/style/css.ts @@ -1,3 +1,4 @@ import '@prestashopcorp/puik-components/base/style/css'; import '@prestashopcorp/puik-theme/puik-button.css'; import '@prestashopcorp/puik-theme/puik-icon.css'; +import '@prestashopcorp/puik-theme/puik-spinner-loader.css'; diff --git a/packages/components/button/style/index.ts b/packages/components/button/style/index.ts index eb159db5..1fcfb353 100644 --- a/packages/components/button/style/index.ts +++ b/packages/components/button/style/index.ts @@ -1,3 +1,4 @@ import '@prestashopcorp/puik-components/base/style'; import '@prestashopcorp/puik-theme/src/puik-button.scss'; import '@prestashopcorp/puik-theme/src/puik-icon.scss'; +import '@prestashopcorp/puik-theme/src/puik-spinner-loader.scss'; diff --git a/packages/components/button/test/button.spec.ts b/packages/components/button/test/button.spec.ts index 0de50c84..9214b9fb 100644 --- a/packages/components/button/test/button.spec.ts +++ b/packages/components/button/test/button.spec.ts @@ -11,6 +11,9 @@ describe('Button tests', () => { const findButton = () => wrapper.find('.puik-button'); const findButtonLeftIcon = () => wrapper.find('.puik-button__left-icon'); const findButtonRightIcon = () => wrapper.find('.puik-button__right-icon'); + const findLoader = () => wrapper.find('.puik-button__loader'); + const findLeftLoader = () => wrapper.find('.puik-button__loader--left'); + const findRightLoader = () => wrapper.find('.puik-button__loader--right'); const disabledId = 'puik-button-disabled-mocked-id'; @@ -142,4 +145,37 @@ describe('Button tests', () => { factory(); expect(findButton().attributes('role')).toBe('button'); }); + + it('should display loader when loading is true', () => { + factory({ loading: true }); + expect(findLoader().exists()).toBeTruthy(); + }); + + it('should display loader on the left when loaderPosition is left', () => { + factory({ loading: true, loaderPosition: 'left' }); + expect(findLoader().exists()).toBeTruthy(); + expect(findLoader().classes()).toContain('puik-button__loader--left'); + }); + + it('should display loader on the right when loaderPosition is right', () => { + factory({ loading: true, loaderPosition: 'right' }); + expect(findLoader().exists()).toBeTruthy(); + expect(findLoader().classes()).toContain('puik-button__loader--right'); + }); + + it('should have a data-test attribute on left-loader and right-loader', () => { + factory({ + loading: true, + loaderPosition: 'left', + dataTest: 'button' + }); + expect(findLeftLoader().attributes('data-test')).toBe('leftLoader-button'); + + factory({ + loading: true, + loaderPosition: 'right', + dataTest: 'button' + }); + expect(findRightLoader().attributes('data-test')).toBe('rightLoader-button'); + }); });