From 216a109b848e5f8de9968f5f6ba549b433898f63 Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Fri, 4 Oct 2024 18:10:55 +0200 Subject: [PATCH 1/6] feat: [new-component] - related #382 : PuikRatingCard (wip) --- CONTRIBUTING.md | 16 ++-- RELEASE-NOTES-V2.md | 2 + packages/components/index.ts | 1 + packages/components/rating-card/index.ts | 6 ++ .../components/rating-card/src/rating-card.ts | 23 +++++ .../rating-card/src/rating-card.vue | 84 +++++++++++++++++++ .../stories/rating-card.stories.ts | 34 ++++++++ packages/components/rating-card/style/css.ts | 2 + .../components/rating-card/style/index.ts | 2 + .../rating-card/test/rating-card.spec.ts | 20 +++++ packages/puik/component.ts | 2 + packages/puik/global.d.ts | 1 + packages/theme/src/index.scss | 1 + packages/theme/src/puik-rating-card.scss | 11 +++ .../web-components/components/rating-card.ts | 8 ++ packages/web-components/index.ts | 3 + 16 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 packages/components/rating-card/index.ts create mode 100644 packages/components/rating-card/src/rating-card.ts create mode 100644 packages/components/rating-card/src/rating-card.vue create mode 100644 packages/components/rating-card/stories/rating-card.stories.ts create mode 100644 packages/components/rating-card/style/css.ts create mode 100644 packages/components/rating-card/style/index.ts create mode 100644 packages/components/rating-card/test/rating-card.spec.ts create mode 100644 packages/theme/src/puik-rating-card.scss create mode 100644 packages/web-components/components/rating-card.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b03591e..7ab2c144 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,6 +27,7 @@ This mono repository contains multiple packages under the folder `packages` - `tailwind-preset` contains the [Tailwind Css](https://tailwindcss.com/) preset and is released under the name `@prestashopcorp/puik-tailwind-preset` - `theme` contains all the CSS classes used in our components and is released under the name `@prestashopcorp/puik-theme` - `utils` contains all the utility functions used across our packages, this package is bundled with the other packages when it's used and isn't released as a standalone +- `web-components` contains all the web components and is released under the name `@prestashopcorp/puik-web-components` ([see available web-components](https://github.com/PrestaShopCorp/puik/blob/main/RELEASE-NOTES-V2.md#available-components)) The `playground` folder contains a Vue 3 to help you develop your components @@ -80,7 +81,7 @@ $ pnpm component This command generates multiples files and injects code in these files -``` +``` plaintext puik/ └── packages/ ├── components/ @@ -100,11 +101,14 @@ puik/ ├── puik/ │ ├── component.ts │ └── global.d.ts - └── theme/ - └── src/ - ├── my-component.scss - └── index.scss - + ├── theme/ + │ └── src/ + │ ├── my-component.scss + │ └── index.scss + └── web-components/ + ├── components/ + │ └── component.ts + └── index.ts ``` ### Style diff --git a/RELEASE-NOTES-V2.md b/RELEASE-NOTES-V2.md index 305aabb6..efb4b06b 100644 --- a/RELEASE-NOTES-V2.md +++ b/RELEASE-NOTES-V2.md @@ -44,6 +44,7 @@ Here is the list of available components in the Vue and Web-Components version o | Progress-stepper | ✅ | ✅ | | | Progress-stepper-step | ✅ | ✅ | | | Radio | ✅ | ✅ | | +| Rating-card | ✅ | ✅ | | | Select | ✅ | ❌ | | | Sidebar | ✅ | ✅ | | | Sidebar-group-item | ✅ | ❌ | | @@ -52,6 +53,7 @@ Here is the list of available components in the Vue and Web-Components version o | Skeleton-loader | ✅ | ✅ | | | Skeleton-loader-group | ✅ | ✅ | | | Snackbar | ✅ | ❌ | Previously implemented with Headless UI, now moved to Radix Vue (see Storybook documentation for more details)| +| Sortable-list | ✅ | ❌ | | | Spinner-loader | ✅ | ✅ | | | Switch | ✅ | ✅ | | | Tab-navigation | ✅ | ✅ | | diff --git a/packages/components/index.ts b/packages/components/index.ts index 20f2710e..af016937 100644 --- a/packages/components/index.ts +++ b/packages/components/index.ts @@ -33,3 +33,4 @@ export * from './avatar'; export * from './divider'; export * from './notification-bar'; export * from './sortable-list'; +export * from './rating-card'; diff --git a/packages/components/rating-card/index.ts b/packages/components/rating-card/index.ts new file mode 100644 index 00000000..7537d3ae --- /dev/null +++ b/packages/components/rating-card/index.ts @@ -0,0 +1,6 @@ +import RatingCard from './src/rating-card.vue'; + +export const PuikRatingCard = RatingCard; +export default PuikRatingCard; + +export * from './src/rating-card'; diff --git a/packages/components/rating-card/src/rating-card.ts b/packages/components/rating-card/src/rating-card.ts new file mode 100644 index 00000000..783e4c57 --- /dev/null +++ b/packages/components/rating-card/src/rating-card.ts @@ -0,0 +1,23 @@ +import '@prestashopcorp/puik-components/rating-card/style/css'; +import type RatingCard from './rating-card.vue'; + +export enum PuikRatingCardVariants { + Extended = 'extended', + Compact = 'compact', +} +export enum PuikRatingSize { + Small = 'small', + large = 'large', +} + +export interface RatingCardProps { + id: string + variant?: `${PuikRatingCardVariants}` + size?: `${PuikRatingSize}` + totalRatings: number[] + showTotalRatings?: boolean + dataTest?: string + ariaLabel?: string +} + +export type RatingCardInstance = InstanceType; diff --git a/packages/components/rating-card/src/rating-card.vue b/packages/components/rating-card/src/rating-card.vue new file mode 100644 index 00000000..94ba385a --- /dev/null +++ b/packages/components/rating-card/src/rating-card.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/packages/components/rating-card/stories/rating-card.stories.ts b/packages/components/rating-card/stories/rating-card.stories.ts new file mode 100644 index 00000000..f6b8b144 --- /dev/null +++ b/packages/components/rating-card/stories/rating-card.stories.ts @@ -0,0 +1,34 @@ +import { PuikRatingCard } from '@prestashopcorp/puik-components'; +import { Meta, StoryFn, Args } from '@storybook/vue3'; + +export default { + title: 'Components/RatingCard', + component: PuikRatingCard +} as Meta; + +const Template: StoryFn = (args: Args) => ({ + components: { + PuikRatingCard + }, + setup() { + return { args }; + }, + template: '' +}); + +export const Default = { + render: Template, + args: {}, + parameters: { + docs: { + source: { + code: ` + + + + `, + language: 'html' + } + } + } +}; diff --git a/packages/components/rating-card/style/css.ts b/packages/components/rating-card/style/css.ts new file mode 100644 index 00000000..a61fc741 --- /dev/null +++ b/packages/components/rating-card/style/css.ts @@ -0,0 +1,2 @@ +import '@prestashopcorp/puik-components/base/style/css'; +import '@prestashopcorp/puik-theme/puik-rating-card.css'; diff --git a/packages/components/rating-card/style/index.ts b/packages/components/rating-card/style/index.ts new file mode 100644 index 00000000..3721c5ce --- /dev/null +++ b/packages/components/rating-card/style/index.ts @@ -0,0 +1,2 @@ +import '@prestashopcorp/puik-components/base/style'; +import '@prestashopcorp/puik-theme/src/puik-rating-card.scss'; diff --git a/packages/components/rating-card/test/rating-card.spec.ts b/packages/components/rating-card/test/rating-card.spec.ts new file mode 100644 index 00000000..d4bcad6b --- /dev/null +++ b/packages/components/rating-card/test/rating-card.spec.ts @@ -0,0 +1,20 @@ +import { mount, ComponentMountingOptions, VueWrapper } from '@vue/test-utils'; +import { describe, it, expect } from 'vitest'; +import { PuikRatingCard, RatingCardProps } from '@prestashopcorp/puik-components'; + +describe('RatingCard tests', () => { + let wrapper: VueWrapper; + const factory = ( + props: RatingCardProps, + options: ComponentMountingOptions + ) => { + wrapper = mount(PuikRatingCard, { + props, + ...options + }); + }; + it('should be a vue instance', () => { + factory(); + expect(wrapper).toBeTruthy(); + }); +}); diff --git a/packages/puik/component.ts b/packages/puik/component.ts index 57892257..c7fb2527 100644 --- a/packages/puik/component.ts +++ b/packages/puik/component.ts @@ -1,4 +1,5 @@ import { + PuikRatingCard, PuikSortableList, PuikNotificationBar, PuikAvatar, @@ -55,6 +56,7 @@ import type { Component } from 'vue'; // prettier-ignore export default [ + PuikRatingCard, PuikSortableList, PuikNotificationBar, PuikAvatar, diff --git a/packages/puik/global.d.ts b/packages/puik/global.d.ts index 23d45d9f..127b8861 100644 --- a/packages/puik/global.d.ts +++ b/packages/puik/global.d.ts @@ -1,6 +1,7 @@ // GlobalComponents for Volar declare module '@vue/runtime-core' { export interface GlobalComponents { + PuikRatingCard: typeof import('@prestashopcorp/puik-components')['PuikRatingCard'] PuikSortableList: typeof import('@prestashopcorp/puik-components')['PuikSortableList'] PuikNotificationBar: (typeof import('@prestashopcorp/puik-components'))['PuikNotificationBar'] PuikTag: (typeof import('@prestashopcorp/puik-components'))['PuikTag'] diff --git a/packages/theme/src/index.scss b/packages/theme/src/index.scss index 24a4131d..e66d06b6 100755 --- a/packages/theme/src/index.scss +++ b/packages/theme/src/index.scss @@ -48,3 +48,4 @@ @use 'puik-divider'; @use 'puik-notification-bar'; @use 'puik-sortable-list'; +@use 'puik-rating-card'; diff --git a/packages/theme/src/puik-rating-card.scss b/packages/theme/src/puik-rating-card.scss new file mode 100644 index 00000000..7e24cc9b --- /dev/null +++ b/packages/theme/src/puik-rating-card.scss @@ -0,0 +1,11 @@ +@use './common/typography.scss'; + +.puik-rating-card { + @apply flex items-center space-x-1; + &_stars-container { + @apply flex space-x-1; + } + &_average-value { + @extend .puik-body-default-bold; + } +} \ No newline at end of file diff --git a/packages/web-components/components/rating-card.ts b/packages/web-components/components/rating-card.ts new file mode 100644 index 00000000..a60c11ea --- /dev/null +++ b/packages/web-components/components/rating-card.ts @@ -0,0 +1,8 @@ +import { defineCustomElement } from 'vue'; +import { PuikRatingCard } from '@prestashopcorp/puik-components'; +import type { CustomElementWithName } from '../types'; + +const PuikRatingCardCe = defineCustomElement(PuikRatingCard) as CustomElementWithName; +PuikRatingCardCe.ceName = 'puik-rating-card-ce'; + +export default PuikRatingCardCe; diff --git a/packages/web-components/index.ts b/packages/web-components/index.ts index 688caaf2..41cd8d8c 100644 --- a/packages/web-components/index.ts +++ b/packages/web-components/index.ts @@ -2,6 +2,7 @@ import type { CustomElementWithName } from './types'; import initWeb from './utils/initWeb'; import initAllWeb from './utils/initAllWeb'; +import PuikRatingCardCe from './components/rating-card'; // import PuikSortableListCe from './components/sortable-list'; import PuikAccordionCe from './components/accordion'; import PuikAccordionGroupCe from './components/accordion-group'; @@ -52,6 +53,7 @@ import PuikTextareaCe from './components/textarea'; import PuikTooltipCe from './components/tooltip'; export const components: CustomElementWithName[] = [ + PuikRatingCardCe, // PuikSortableListCe, PuikAccordionCe, PuikAccordionGroupCe, @@ -103,6 +105,7 @@ export const components: CustomElementWithName[] = [ ]; export { + PuikRatingCardCe, // PuikSortableListCe, PuikAccordionCe, PuikAccordionGroupCe, From 8531ed9fbc1950666faf490849e4f88e282cc8c8 Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Mon, 7 Oct 2024 14:40:18 +0200 Subject: [PATCH 2/6] feat: [new-component][Rating-card] - related #382 : change deprecated Material Icons set to Material Symbols, add fill prop to icon component, remove useless size prop from rating-card component --- commitlint.config.cjs | 2 +- packages/components/icon/src/icon.ts | 1 + packages/components/icon/src/icon.vue | 6 ++++-- .../components/rating-card/src/rating-card.ts | 5 ----- .../rating-card/src/rating-card.vue | 20 ++++++++----------- packages/tailwind-preset/theme.ts | 2 +- packages/theme/src/common/font.scss | 2 +- packages/theme/src/puik-rating-card.scss | 3 +++ 8 files changed, 19 insertions(+), 22 deletions(-) diff --git a/commitlint.config.cjs b/commitlint.config.cjs index 9efbd6fc..7e03ed9c 100644 --- a/commitlint.config.cjs +++ b/commitlint.config.cjs @@ -1,6 +1,6 @@ module.exports = { extends: ['@commitlint/config-conventional'], rules: { - 'header-max-length': [2, 'always', 150] + 'header-max-length': [2, 'always', 300] } }; diff --git a/packages/components/icon/src/icon.ts b/packages/components/icon/src/icon.ts index 57f16a37..7f07657f 100644 --- a/packages/components/icon/src/icon.ts +++ b/packages/components/icon/src/icon.ts @@ -6,6 +6,7 @@ export interface IconProps { nodeType?: string fontSize?: string | number color?: string + fill?: number isDisabled?: boolean dataTest?: string ariaLabel?: string diff --git a/packages/components/icon/src/icon.vue b/packages/components/icon/src/icon.vue index 01bc7f2e..36e32cd5 100644 --- a/packages/components/icon/src/icon.vue +++ b/packages/components/icon/src/icon.vue @@ -24,7 +24,8 @@ defineOptions({ const props = withDefaults(defineProps(), { nodeType: 'div', fontSize: '1rem', - color: '#00000' + color: '#00000', + fill: 1 }); const fontSize = computed(() => { @@ -37,7 +38,8 @@ const fontSize = computed(() => { const style = computed(() => { return { fontSize: fontSize.value, - color: props.color + color: props.color, + 'font-variation-settings': `'FILL' ${props.fill}` }; }); diff --git a/packages/components/rating-card/src/rating-card.ts b/packages/components/rating-card/src/rating-card.ts index 783e4c57..a745a94b 100644 --- a/packages/components/rating-card/src/rating-card.ts +++ b/packages/components/rating-card/src/rating-card.ts @@ -5,15 +5,10 @@ export enum PuikRatingCardVariants { Extended = 'extended', Compact = 'compact', } -export enum PuikRatingSize { - Small = 'small', - large = 'large', -} export interface RatingCardProps { id: string variant?: `${PuikRatingCardVariants}` - size?: `${PuikRatingSize}` totalRatings: number[] showTotalRatings?: boolean dataTest?: string diff --git a/packages/components/rating-card/src/rating-card.vue b/packages/components/rating-card/src/rating-card.vue index 94ba385a..219c9577 100644 --- a/packages/components/rating-card/src/rating-card.vue +++ b/packages/components/rating-card/src/rating-card.vue @@ -2,7 +2,6 @@
@@ -34,7 +33,7 @@ v-else class="puik-rating-card_star" icon="star" - :font-size="props.size === PuikRatingSize.large ? '24px' : '16px'" + font-size="16px" color="#FFA000" node-type="span" /> @@ -49,7 +48,7 @@ diff --git a/packages/tailwind-preset/theme.ts b/packages/tailwind-preset/theme.ts index 424e8b5e..18aafe55 100644 --- a/packages/tailwind-preset/theme.ts +++ b/packages/tailwind-preset/theme.ts @@ -85,7 +85,7 @@ export default { fontFamily: { primary: ['IBM Plex Sans', 'Verdana', 'Arial', 'sans-serif'], secondary: ['Prestafont', 'Verdana', 'Arial', 'sans-serif'], - materialIcons: ['Material Icons Round'] + materialIcons: ['Material Symbols Rounded'] }, fontSize: { xs: ['0.75rem', { lineHeight: '1.125rem' }], diff --git a/packages/theme/src/common/font.scss b/packages/theme/src/common/font.scss index 68d81a83..31dbf575 100755 --- a/packages/theme/src/common/font.scss +++ b/packages/theme/src/common/font.scss @@ -4,4 +4,4 @@ } @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,700;0,900;1,300;1,400;1,500;1,700;1,900&display=swap'); -@import url('https://fonts.googleapis.com/icon?family=Material+Icons+Round&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200'); diff --git a/packages/theme/src/puik-rating-card.scss b/packages/theme/src/puik-rating-card.scss index 7e24cc9b..7ca4850a 100644 --- a/packages/theme/src/puik-rating-card.scss +++ b/packages/theme/src/puik-rating-card.scss @@ -8,4 +8,7 @@ &_average-value { @extend .puik-body-default-bold; } + &_total-ratings { + @extend .puik-body-small-medium; + } } \ No newline at end of file From e970443fa31124356829b309c1861f17506a82fa Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Wed, 9 Oct 2024 18:36:29 +0200 Subject: [PATCH 3/6] feat: [new-component][Rating-card] - fixed #382 : add tests and stories + fix typos --- .../accordion/stories/accordion.stories.ts | 2 +- .../components/alert/stories/alert.stories.ts | 12 +- .../avatar/stories/avatar.stories.ts | 4 +- .../components/badge/stories/badge.stories.ts | 6 +- .../button/stories/button.stories.ts | 18 +- .../components/card/stories/card.stories.ts | 4 +- .../checkbox/stories/checkbox.stories.ts | 10 +- .../components/icon/stories/icon.stories.ts | 12 +- .../components/input/stories/input.stories.ts | 30 +-- .../components/label/stories/label.stories.ts | 2 +- .../components/link/stories/link.stories.ts | 8 +- .../menu/stories/menu-item-title.stories.ts | 2 +- .../components/modal/stories/modal.stories.ts | 20 +- .../pagination/stories/pagination.stories.ts | 12 +- .../stories/progress-stepper-step.stories.ts | 2 +- .../components/radio/stories/radio.stories.ts | 6 +- .../rating-card/src/rating-card.vue | 5 +- .../stories/rating-card.stories.ts | 235 +++++++++++++++++- .../rating-card/test/rating-card.spec.ts | 100 +++++++- .../select/stories/select.stories.ts | 2 +- .../stories/sidebar-group-item.stories.ts | 10 +- .../sidebar/stories/sidebar-item.stories.ts | 12 +- .../sidebar/stories/sidebar-title.stories.ts | 6 +- .../stories/skeleton-loader-group.stories.ts | 4 +- .../stories/skeleton-loader.stories.ts | 4 +- .../stories/snackbar-provider.stories.ts | 2 +- .../snackbar/stories/snackbar.stories.ts | 8 +- .../stories/sortable-list.stories.ts | 2 +- .../stories/spinner-loader.stories.ts | 6 +- .../components/table/stories/table.stories.ts | 2 +- .../components/tag/stories/tag.stories.ts | 2 +- .../textarea/stories/textarea.stories.ts | 24 +- .../tooltip/stories/tooltip.stories.ts | 12 +- 33 files changed, 449 insertions(+), 137 deletions(-) diff --git a/packages/components/accordion/stories/accordion.stories.ts b/packages/components/accordion/stories/accordion.stories.ts index c0bb327a..8b61cfc7 100644 --- a/packages/components/accordion/stories/accordion.stories.ts +++ b/packages/components/accordion/stories/accordion.stories.ts @@ -47,7 +47,7 @@ export default { dataTest: { control: 'text', description: - 'Set the data-test attribute for the accordion `button-${dataTest}` `title-${dataTest}` `icon-${dataTest}` `subTitle-${dataTest}`' + 'Sets the data-test attribute for the accordion `button-${dataTest}` `title-${dataTest}` `icon-${dataTest}` `subTitle-${dataTest}`' } } } as Meta; diff --git a/packages/components/alert/stories/alert.stories.ts b/packages/components/alert/stories/alert.stories.ts index 17be7060..8d323b4d 100644 --- a/packages/components/alert/stories/alert.stories.ts +++ b/packages/components/alert/stories/alert.stories.ts @@ -14,14 +14,14 @@ export default { component: PuikAlert, argTypes: { title: { - description: 'Set the alert title' + description: 'Sets the alert title' }, description: { - description: 'Set the alert description (also exists as a default slot)' + description: 'Sets the alert description (also exists as a default slot)' }, variant: { control: 'select', - description: 'Set the alert variant', + description: 'Sets the alert variant', options: alertVariants, table: { defaultValue: { @@ -45,7 +45,7 @@ export default { description: 'Label of the button' }, buttonWrapLabel: { - description: 'Set the carriage return of the button label', + description: 'Sets the carriage return of the button label', table: { defaultValue: { summary: false @@ -57,12 +57,12 @@ export default { }, default: { control: 'none', - description: 'Set the alert description' + description: 'Sets the alert description' }, dataTest: { control: 'text', description: - 'Set the data-test attribute for the alert components `title-${dataTest}` `description-${dataTest}` `button-${dataTest}` `close-${dataTest}` `link-${dataTest}`' + 'Sets the data-test attribute for the alert components `title-${dataTest}` `description-${dataTest}` `button-${dataTest}` `close-${dataTest}` `link-${dataTest}`' }, linkLabel: { description: 'Label of the link' diff --git a/packages/components/avatar/stories/avatar.stories.ts b/packages/components/avatar/stories/avatar.stories.ts index 3d8dff04..e6755b6e 100644 --- a/packages/components/avatar/stories/avatar.stories.ts +++ b/packages/components/avatar/stories/avatar.stories.ts @@ -92,7 +92,7 @@ export default { } }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility', + description: 'Sets the aria-label attribute for accessibility', table: { defaultValue: { summary: 'undefined' @@ -152,7 +152,7 @@ export default { dataTest: { control: 'text', description: - 'Set the data-test attribute for the avatar `image-${dataTest}` `icon-${dataTest}` `initials-${dataTest}`' + 'Sets the data-test attribute for the avatar `image-${dataTest}` `icon-${dataTest}` `initials-${dataTest}`' } }, args: { diff --git a/packages/components/badge/stories/badge.stories.ts b/packages/components/badge/stories/badge.stories.ts index 077320c0..faa779b9 100644 --- a/packages/components/badge/stories/badge.stories.ts +++ b/packages/components/badge/stories/badge.stories.ts @@ -14,7 +14,7 @@ export default { }, variant: { control: 'select', - description: 'Set the badge variant', + description: 'Sets the badge variant', options: badgeVariants, table: { type: { @@ -26,7 +26,7 @@ export default { } }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility', + description: 'Sets the aria-label attribute for accessibility', table: { defaultValue: { summary: 'undefined' @@ -38,7 +38,7 @@ export default { }, dataTest: { control: 'text', - description: 'Set the data-test attribute on the badge' + description: 'Sets the data-test attribute on the badge' } }, args: { diff --git a/packages/components/button/stories/button.stories.ts b/packages/components/button/stories/button.stories.ts index b6e4946d..abea0187 100644 --- a/packages/components/button/stories/button.stories.ts +++ b/packages/components/button/stories/button.stories.ts @@ -12,7 +12,7 @@ export default { argTypes: { variant: { control: 'select', - description: 'Set the button variant', + description: 'Sets the button variant', options: buttonVariants, table: { defaultValue: { @@ -25,7 +25,7 @@ export default { }, size: { control: 'select', - description: 'Set the button size', + description: 'Sets the button size', options: buttonSizes, table: { defaultValue: { @@ -37,7 +37,7 @@ export default { } }, fluid: { - description: 'Set the button as fluid', + description: 'Sets the button as fluid', table: { defaultValue: { summary: false @@ -45,7 +45,7 @@ export default { } }, wrapLabel: { - description: 'Set the carriage return of the button label', + description: 'Sets the carriage return of the button label', table: { defaultValue: { summary: false @@ -53,7 +53,7 @@ export default { } }, disabled: { - description: 'Set the button as disabled', + description: 'Sets the button as disabled', table: { defaultValue: { summary: false @@ -61,10 +61,10 @@ export default { } }, leftIcon: { - description: 'Set the button left icon' + description: 'Sets the button left icon' }, rightIcon: { - description: 'Set the button right icon' + description: 'Sets the button right icon' }, default: { control: 'text', @@ -85,7 +85,7 @@ export default { 'Set a data-test attribute to the button `${dataTest}` `left-icon-${dataTest}` `right-icon-${dataTest}`' }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility', + description: 'Sets the aria-label attribute for accessibility', table: { defaultValue: { summary: 'undefined' @@ -97,7 +97,7 @@ export default { }, disabledReason: { control: 'text', - description: 'Set the aria-describedby attribute for accessibility if disabled' + description: 'Sets the aria-describedby attribute for accessibility if disabled' } }, args: { diff --git a/packages/components/card/stories/card.stories.ts b/packages/components/card/stories/card.stories.ts index 8fa4b020..45d4afa4 100644 --- a/packages/components/card/stories/card.stories.ts +++ b/packages/components/card/stories/card.stories.ts @@ -10,7 +10,7 @@ export default { component: PuikCard, argTypes: { variant: { - description: 'Set the card variant', + description: 'Sets the card variant', table: { defaultValue: { summary: 'default' @@ -21,7 +21,7 @@ export default { } }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility', + description: 'Sets the aria-label attribute for accessibility', table: { defaultValue: { summary: 'undefined' diff --git a/packages/components/checkbox/stories/checkbox.stories.ts b/packages/components/checkbox/stories/checkbox.stories.ts index 760f609c..1eceee7a 100644 --- a/packages/components/checkbox/stories/checkbox.stories.ts +++ b/packages/components/checkbox/stories/checkbox.stories.ts @@ -7,11 +7,11 @@ export default { argTypes: { default: { control: 'text', - description: 'Set the label via default slot' + description: 'Sets the label via default slot' }, label: { control: 'text', - description: 'Set the checkbox label' + description: 'Sets the checkbox label' }, ariaLabel: { description: 'If you are planning to set the label via default slot instead of using label prop then in that case you should set the aria-label for better accessibility', @@ -36,7 +36,7 @@ export default { } }, indeterminate: { - description: 'Set the indeterminate checkbox state', + description: 'Sets the indeterminate checkbox state', table: { defaultValue: { summary: false @@ -48,7 +48,7 @@ export default { control: 'none' }, disabled: { - description: 'Set the checkbox as disabled', + description: 'Sets the checkbox as disabled', table: { defaultValue: { summary: false @@ -57,7 +57,7 @@ export default { }, dataTest: { description: - 'Set the data-test attribute for the label and the input `label-${dataTest}` `input-${dataTest}`}`', + 'Sets the data-test attribute for the label and the input `label-${dataTest}` `input-${dataTest}`}`', control: 'text' } }, diff --git a/packages/components/icon/stories/icon.stories.ts b/packages/components/icon/stories/icon.stories.ts index 8061ae47..d5745718 100644 --- a/packages/components/icon/stories/icon.stories.ts +++ b/packages/components/icon/stories/icon.stories.ts @@ -6,10 +6,10 @@ export default { component: PuikIcon, argTypes: { icon: { - description: 'Set the icon name' + description: 'Sets the icon name' }, fontSize: { - description: 'Set the icon font size', + description: 'Sets the icon font size', control: { type: 'range', min: 1, @@ -18,13 +18,13 @@ export default { } }, color: { - description: 'Set the icon color', + description: 'Sets the icon color', control: { type: 'color' } }, nodeType: { - description: 'Set the HTML node type', + description: 'Sets the HTML node type', default: 'div', control: { type: 'radio', @@ -32,7 +32,7 @@ export default { } }, dataTest: { - description: 'Set the data-test attribute' + description: 'Sets the data-test attribute' }, isDisabled: { description: 'If the icon is disable', @@ -41,7 +41,7 @@ export default { } }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility (if this prop is not present the default aria-label will be set to the icon name)', + description: 'Sets the aria-label attribute for accessibility (if this prop is not present the default aria-label will be set to the icon name)', table: { defaultValue: { summary: 'undefined' diff --git a/packages/components/input/stories/input.stories.ts b/packages/components/input/stories/input.stories.ts index 714fe06a..3ae1bae3 100644 --- a/packages/components/input/stories/input.stories.ts +++ b/packages/components/input/stories/input.stories.ts @@ -16,7 +16,7 @@ export default { type: { control: 'select', options: inputTypes, - description: 'Set the type of the input', + description: 'Sets the type of the input', table: { type: { summary: inputTypesSummary @@ -27,10 +27,10 @@ export default { } }, id: { - description: 'Set the id of the input' + description: 'Sets the id of the input' }, srLabel: { - description: 'Set the input label for screen readers', + description: 'Sets the input label for screen readers', table: { defaultValue: { summary: 'undefined' @@ -41,11 +41,11 @@ export default { } }, placeholder: { - description: 'Set the placeholder of the input' + description: 'Sets the placeholder of the input' }, disabled: { control: 'boolean', - description: 'Set the input as disabled', + description: 'Sets the input as disabled', table: { defaultValue: { summary: 'false' @@ -53,13 +53,13 @@ export default { } }, name: { - description: 'Set the name of the input' + description: 'Sets the name of the input' }, autocomplete: { - description: 'Set the autocomplete mode of the input' + description: 'Sets the autocomplete mode of the input' }, required: { - description: 'Set the input as required', + description: 'Sets the input as required', table: { defaultValue: { summary: 'false' @@ -70,7 +70,7 @@ export default { description: 'Set an error for the input' }, success: { - description: 'Set the input in a success state', + description: 'Sets the input in a success state', table: { defaultValue: { summary: 'false' @@ -87,7 +87,7 @@ export default { }, step: { control: 'number', - description: 'Set the incremental step (for number input only)', + description: 'Sets the incremental step (for number input only)', table: { defaultValue: { summary: '1' @@ -97,15 +97,15 @@ export default { precision: { control: 'number', description: - 'Set the precision of the input value (for number input only)' + 'Sets the precision of the input value (for number input only)' }, min: { control: 'number', - description: 'Set the min value of the input (for number input only)' + description: 'Sets the min value of the input (for number input only)' }, max: { control: 'number', - description: 'Set the max value of the input (for number input only)' + description: 'Sets the max value of the input (for number input only)' }, prepend: { description: 'Prepend an icon or text to the input' @@ -116,11 +116,11 @@ export default { }, dataTest: { description: - 'Set the data-test attribute on the input and error text elements `input-${dataTest}` `error-${dataTest}`', + 'Sets the data-test attribute on the input and error text elements `input-${dataTest}` `error-${dataTest}`', control: 'text' }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility', + description: 'Sets the aria-label attribute for accessibility', table: { defaultValue: { summary: 'undefined' diff --git a/packages/components/label/stories/label.stories.ts b/packages/components/label/stories/label.stories.ts index 6cc65bfa..18416399 100644 --- a/packages/components/label/stories/label.stories.ts +++ b/packages/components/label/stories/label.stories.ts @@ -41,7 +41,7 @@ export default { description: 'Default slot to set label text' }, dataTest: { - description: 'Set the data-test attribute' + description: 'Sets the data-test attribute' } } } as Meta; diff --git a/packages/components/link/stories/link.stories.ts b/packages/components/link/stories/link.stories.ts index 00667815..a7bf4136 100644 --- a/packages/components/link/stories/link.stories.ts +++ b/packages/components/link/stories/link.stories.ts @@ -22,7 +22,7 @@ export default { target: { control: 'select', description: - 'Set the link target. If you set it to "_blank" the icon "open in new" is displayed', + 'Sets the link target. If you set it to "_blank" the icon "open in new" is displayed', options: targetVariants, table: { defaultValue: { @@ -34,7 +34,7 @@ export default { } }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility', + description: 'Sets the aria-label attribute for accessibility', table: { defaultValue: { summary: 'undefined' @@ -46,7 +46,7 @@ export default { }, size: { control: 'select', - description: 'Set the link font size', + description: 'Sets the link font size', options: linkSizes, table: { defaultValue: { @@ -84,7 +84,7 @@ export default { description: 'Title displayed in tooltips then your cursor stay in link' }, dataTest: { - description: 'Set the data-test attribute' + description: 'Sets the data-test attribute' } }, args: { diff --git a/packages/components/menu/stories/menu-item-title.stories.ts b/packages/components/menu/stories/menu-item-title.stories.ts index 5a3c0b88..28df1928 100644 --- a/packages/components/menu/stories/menu-item-title.stories.ts +++ b/packages/components/menu/stories/menu-item-title.stories.ts @@ -10,7 +10,7 @@ export default { description: 'Default slot to set title text' }, dataTest: { - description: 'Set the data-test attribute for title `title-${dataTest}`', + description: 'Sets the data-test attribute for title `title-${dataTest}`', control: 'text' } } diff --git a/packages/components/modal/stories/modal.stories.ts b/packages/components/modal/stories/modal.stories.ts index d3296fd8..e7100968 100644 --- a/packages/components/modal/stories/modal.stories.ts +++ b/packages/components/modal/stories/modal.stories.ts @@ -54,7 +54,7 @@ export default { component: PuikModal, argTypes: { title: { - description: 'Set the modal title', + description: 'Sets the modal title', control: 'text', table: { type: { @@ -66,7 +66,7 @@ export default { } }, mainButtonText: { - description: 'Set the text of the main button', + description: 'Sets the text of the main button', control: 'text', table: { type: { @@ -78,7 +78,7 @@ export default { } }, secondButtonText: { - description: 'Set the text of the secondary button', + description: 'Sets the text of the secondary button', control: 'text', table: { type: { @@ -90,7 +90,7 @@ export default { } }, sideButtonText: { - description: 'Set the text of the side button', + description: 'Sets the text of the side button', control: 'text', table: { type: { @@ -103,7 +103,7 @@ export default { }, variant: { description: - 'Set the style of the modal (use the PuikModalVariants enum)', + 'Sets the style of the modal (use the PuikModalVariants enum)', control: 'select', options: modalVariants, table: { @@ -127,7 +127,7 @@ export enum PuikModalVariants { } }, size: { - description: 'Set the size of the modal (use the PuikModalSizes enum)', + description: 'Sets the size of the modal (use the PuikModalSizes enum)', control: 'select', options: modalSizes, table: { @@ -176,7 +176,7 @@ export enum PuikModalSizes { }, dataTest: { description: - 'Set the data-test attribute for modal `title-${dataTest}` `mainButton-${dataTest}` `secondButton-${dataTest}` `sideButton-${dataTest}` `closeButton-${dataTest}`', + 'Sets the data-test attribute for modal `title-${dataTest}` `mainButton-${dataTest}` `secondButton-${dataTest}` `sideButton-${dataTest}` `closeButton-${dataTest}`', control: 'text' }, default: { @@ -540,7 +540,7 @@ export const Large = { parameters: { docs: { description: { - story: 'Set the max-width to `904px`' + story: 'Sets the max-width to `904px`' }, source: { code: ` @@ -600,7 +600,7 @@ export const Medium = { parameters: { docs: { description: { - story: 'Set the max-width to `680px`' + story: 'Sets the max-width to `680px`' }, source: { code: ` @@ -660,7 +660,7 @@ export const Small = { parameters: { docs: { description: { - story: 'Set the max-width to `508px`' + story: 'Sets the max-width to `508px`' }, source: { code: ` diff --git a/packages/components/pagination/stories/pagination.stories.ts b/packages/components/pagination/stories/pagination.stories.ts index f7555ea2..9faabc15 100644 --- a/packages/components/pagination/stories/pagination.stories.ts +++ b/packages/components/pagination/stories/pagination.stories.ts @@ -12,7 +12,7 @@ export default { variant: { control: 'select', options: paginationVariants, - description: 'Set the pagination variant', + description: 'Sets the pagination variant', table: { defaultValue: { summary: PuikPaginationVariants.Medium @@ -24,7 +24,7 @@ export default { }, totalItem: { control: 'number', - description: 'Set the total item count', + description: 'Sets the total item count', table: { type: { summary: 'number' @@ -43,7 +43,7 @@ export default { }, itemsPerPageOptions: { control: 'none', - description: 'Set the items per page options', + description: 'Sets the items per page options', table: { type: { summary: 'number[]' @@ -82,7 +82,7 @@ export default { }, label: { control: 'text', - description: 'Set the label', + description: 'Sets the label', table: { defaultValue: { summary: 'undefined' @@ -94,7 +94,7 @@ export default { }, loaderButtonLabel: { control: 'text', - description: 'Set the text used in button on loader variant', + description: 'Sets the text used in button on loader variant', table: { defaultValue: { summary: 'undefined' @@ -107,7 +107,7 @@ export default { dataTest: { control: 'text', description: - 'Set the data-test attribute `nextButton-${dataTest}` `previousButton-${dataTest}` `label-${dataTest}` `loadMoreButton-${dataTest}` (only for loader variant)' + 'Sets the data-test attribute `nextButton-${dataTest}` `previousButton-${dataTest}` `label-${dataTest}` `loadMoreButton-${dataTest}` (only for loader variant)' } }, args: { diff --git a/packages/components/progress-stepper/stories/progress-stepper-step.stories.ts b/packages/components/progress-stepper/stories/progress-stepper-step.stories.ts index ecfa173f..fbfea0c4 100644 --- a/packages/components/progress-stepper/stories/progress-stepper-step.stories.ts +++ b/packages/components/progress-stepper/stories/progress-stepper-step.stories.ts @@ -24,7 +24,7 @@ export default { }, dataTest: { description: - 'Set the data-test of the progress stepper step `stepButton-${dataTest}` `text-${dataTest}` `additionalText-${dataTest}`', + 'Sets the data-test of the progress stepper step `stepButton-${dataTest}` `text-${dataTest}` `additionalText-${dataTest}`', control: 'text' }, click: { diff --git a/packages/components/radio/stories/radio.stories.ts b/packages/components/radio/stories/radio.stories.ts index ef15b705..2a882b51 100644 --- a/packages/components/radio/stories/radio.stories.ts +++ b/packages/components/radio/stories/radio.stories.ts @@ -19,7 +19,7 @@ export default { description: 'Label of the radio input' }, ariaLabel: { - description: 'Set the aria-label attribute for accessibility', + description: 'Sets the aria-label attribute for accessibility', table: { defaultValue: { summary: 'ariaLabel || label || "undefined"' @@ -30,7 +30,7 @@ export default { } }, ariaDescribedby: { - description: 'Set the aria-describedby attribute for accessibility (id of element that describes the input)', + description: 'Sets the aria-describedby attribute for accessibility (id of element that describes the input)', table: { defaultValue: { summary: 'none' @@ -80,7 +80,7 @@ export default { dataTest: { control: 'text', description: - 'Set the data-test attribute of the input and the label `label-${dataTest}` `input-${dataTest}`' + 'Sets the data-test attribute of the input and the label `label-${dataTest}` `input-${dataTest}`' } }, args: { diff --git a/packages/components/rating-card/src/rating-card.vue b/packages/components/rating-card/src/rating-card.vue index 219c9577..cf4e72bd 100644 --- a/packages/components/rating-card/src/rating-card.vue +++ b/packages/components/rating-card/src/rating-card.vue @@ -1,8 +1,7 @@ @@ -61,9 +61,36 @@ const props = withDefaults(defineProps(), { showTotalRatings: true }); +const booleanishProps = computed(() => { + return { + showTotalRatings: props.showTotalRatings === 'true' ? true : props.showTotalRatings === 'false' ? false : props.showTotalRatings + }; +}); + +const isValidTotalRatingsString = (value: string): boolean => { + try { + const array = JSON.parse(value); + return Array.isArray(array) && array.every(num => typeof num === 'number'); + } catch { + return false; + } +}; + +const totalRatingsArray = computed(() => { + if (typeof props.totalRatings === 'string' && isValidTotalRatingsString(props.totalRatings)) { + return JSON.parse(props.totalRatings); + } else if (typeof props.totalRatings === 'string') { + return props.totalRatings.split(',').map(num => { + const parsed = Number(num.trim()); + return isNaN(parsed) ? null : parsed; + }).filter(n => n !== null) as number[]; + } + return props.totalRatings; +}); + const averageRating = computed(() => { - const total = props.totalRatings.reduce((sum, rating) => sum + rating, 0); - return props.totalRatings.length ? total / props.totalRatings.length : 0; + const total = totalRatingsArray.value.reduce((sum: number, rating: number) => sum + rating, 0); + return totalRatingsArray.value.length ? total / totalRatingsArray.value.length : 0; }); const getStarState = (starIndex: number) => { diff --git a/packages/components/rating-card/stories/rating-card.stories.ts b/packages/components/rating-card/stories/rating-card.stories.ts index 6fdecd2a..d0a3a97e 100644 --- a/packages/components/rating-card/stories/rating-card.stories.ts +++ b/packages/components/rating-card/stories/rating-card.stories.ts @@ -11,7 +11,7 @@ export default { id: { control: 'text', description: - 'Sets the id html attribute of puik-rating-card. If this prop is not configured, an id will be automatically generated by using this pattern : puik-rating-card-{randomNumber}', + 'Sets the id HTML attribute of puik-rating-card. If this prop is not configured, an id will be automatically generated using this pattern: puik-rating-card-{randomNumber}', table: { defaultValue: { summary: 'puik-rating-card-{randomNumber}' @@ -22,8 +22,18 @@ export default { } }, totalRatings: { - description: 'An array of all ratings (set of numbers from 0 to 5 - including decimal values)', - control: { type: 'array' } + description: 'An array of numbers, a stringified version, or a comma-separated string of all ratings (set of numbers from 0 to 5 - including decimal values) - see details below', + control: { type: 'array' }, + table: { + type: { + summary: 'number[] | string', + detail: `Valid patterns: + - Array of numbers, ex: [4, 5, 3, 4, 5, 2.5] + // use in particular to match the string type of attributes (props equivalent) for web components use case : + - JSON string (stingify Array of numbers), ex: "[4, 5, 3, 4, 5, 2.5]" + - Comma-separated string, ex: "4,5,3,4,5,2.5"` + } + } }, variant: { description: 'Sets the rating card display to compact or expanded mode', @@ -39,21 +49,24 @@ export default { } }, showTotalRatings: { - description: 'Displays the number of total ratings', + description: 'Displays the number of total ratings - see details below', control: { type: 'boolean' }, table: { defaultValue: { summary: 'true' }, type: { - summary: 'boolean' + summary: 'booleanish', + detail: ` +// use in particular to match the string type of attributes (props equivalent) for web components use case +export type booleanish = boolean | 'true' | 'false'; + ` } } }, dataTest: { control: 'text', - description: - 'Sets the data-test attribute', + description: 'Sets the data-test attribute', table: { defaultValue: { summary: 'undefined' diff --git a/packages/components/rating-card/test/rating-card.spec.ts b/packages/components/rating-card/test/rating-card.spec.ts index e10ba76e..5c080916 100644 --- a/packages/components/rating-card/test/rating-card.spec.ts +++ b/packages/components/rating-card/test/rating-card.spec.ts @@ -2,6 +2,28 @@ import { mount, ComponentMountingOptions, VueWrapper } from '@vue/test-utils'; import { describe, it, expect } from 'vitest'; import { PuikRatingCard, RatingCardProps, PuikRatingCardVariants } from '@prestashopcorp/puik-components'; +// Helper functions from rating-card.vue component +const isValidTotalRatingsString = (value: string): boolean => { + try { + const array = JSON.parse(value); + return Array.isArray(array) && array.every(num => typeof num === 'number'); + } catch { + return false; + } +}; + +const totalRatingsArray = (totalRatings: number[] | string): number[] => { + if (typeof totalRatings === 'string' && isValidTotalRatingsString(totalRatings)) { + return JSON.parse(totalRatings); + } else if (typeof totalRatings === 'string') { + return totalRatings.split(',').map(num => { + const parsed = Number(num.trim()); + return isNaN(parsed) ? null : parsed; + }).filter(n => n !== null) as number[]; + } + return totalRatings; +}; + describe('RatingCard tests', () => { let wrapper: VueWrapper; const factory = ( @@ -109,4 +131,47 @@ describe('RatingCard tests', () => { }); expect(wrapper.find('.puik-rating-card_total-ratings').exists()).toBe(false); }); + + it('should validate totalRatings prop type using component logic', () => { + const invalidRatings = 'invalid'; + expect(isValidTotalRatingsString(invalidRatings)).toBe(false); + + const validRatings = [3, 4, 5]; + expect(totalRatingsArray(validRatings)).toEqual(validRatings); + + const validStringRatings = '[3, 4, 5]'; + expect(totalRatingsArray(validStringRatings)).toEqual([3, 4, 5]); + + const validCommaSeparatedRatings = '3,4,5'; + expect(totalRatingsArray(validCommaSeparatedRatings)).toEqual([3, 4, 5]); + }); + + it('should handle empty totalRatings array', () => { + factory({ + id: 'test-id', + totalRatings: [] + }); + expect(wrapper.vm.totalRatingsArray).toEqual([]); + expect(wrapper.vm.averageRating).toBe(0); + }); + + it('should handle extremely large totalRatings array', () => { + const largeRatings = new Array(10000).fill(5); + factory({ + id: 'test-id', + totalRatings: largeRatings + }); + expect(wrapper.vm.totalRatingsArray.length).toBe(10000); + expect(wrapper.vm.averageRating).toBe(5); + }); + + it('should have correct aria-label', () => { + const ariaLabel = 'Rating card for product'; + factory({ + id: 'test-id', + totalRatings: [4, 5, 3], + ariaLabel + }); + expect(wrapper.attributes('aria-label')).toBe(ariaLabel); + }); }); diff --git a/packages/components/types.ts b/packages/components/types.ts new file mode 100644 index 00000000..ec0ace65 --- /dev/null +++ b/packages/components/types.ts @@ -0,0 +1,2 @@ +// use in particular to match the string type of attributes (props equivalent) of web components +export type booleanish = boolean | 'true' | 'false'; From b8b64627413f5b8d8de9ee0636710bf8440eeef4 Mon Sep 17 00:00:00 2001 From: Matthias Goudjil Date: Thu, 10 Oct 2024 18:31:32 +0200 Subject: [PATCH 5/6] feat: [new-component][Rating-card] - unbind puik-rating-card_stars-container class attribute --- packages/components/rating-card/src/rating-card.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/components/rating-card/src/rating-card.vue b/packages/components/rating-card/src/rating-card.vue index 77738e01..9ce1d476 100644 --- a/packages/components/rating-card/src/rating-card.vue +++ b/packages/components/rating-card/src/rating-card.vue @@ -13,9 +13,7 @@
Date: Thu, 14 Nov 2024 16:21:31 +0100 Subject: [PATCH 6/6] feat: [Rating-card] -related #382 - add datatest prop for star icons --- packages/components/rating-card/src/rating-card.vue | 2 ++ packages/components/rating-card/stories/rating-card.stories.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/components/rating-card/src/rating-card.vue b/packages/components/rating-card/src/rating-card.vue index 9ce1d476..78816795 100644 --- a/packages/components/rating-card/src/rating-card.vue +++ b/packages/components/rating-card/src/rating-card.vue @@ -24,6 +24,7 @@ color="#FFA000" :fill="getStarState(starIndex).fill" node-type="span" + :data-test="dataTest != undefined ? `${dataTest}-star-icon-${starIndex}` : undefined" />