diff --git a/apps/site/src/components/code/code.inject-components.ts b/apps/site/src/components/code/code.inject-components.ts index 211053527..ff84a74cd 100644 --- a/apps/site/src/components/code/code.inject-components.ts +++ b/apps/site/src/components/code/code.inject-components.ts @@ -69,6 +69,10 @@ export { SettingsIcon, WatchIcon, EmailIcon, + GiftIcon, + WarningIcon, + PadlockIcon, + SuccessIcon, } from '@westpac/ui/icon'; export { GiftPictogram } from '@westpac/ui/pictogram'; diff --git a/apps/site/src/content/design-system/accessibility/colour-vision-impairment/design/What is a colour vision impairment/content.mdoc b/apps/site/src/content/design-system/accessibility/colour-vision-impairment/design/What is a colour vision impairment/content.mdoc new file mode 100644 index 000000000..1aa7ef572 --- /dev/null +++ b/apps/site/src/content/design-system/accessibility/colour-vision-impairment/design/What is a colour vision impairment/content.mdoc @@ -0,0 +1,49 @@ +Within the accessibility pages of this site, you will find the colour impairment demonstration tool, this tool allows you to view the components as someone with a colour vision impairment would perceive them. + +Colour vision impairment is something that impacts people (mostly men) across the board, it is a condition that affects how the cone photoreceptors in the retinas detect the colour frequencies of light. It can stop them from being able to perceive different colours. + +Some famous people who are considered _'colour blind'_: + +- Mark Zuckerberg - Founder of Facebook +- Bill Clinton - 42nd president of the United States +- Jamie Oliver - Celebrity chef + +Colour vision impairments can either be inherited or acquired. Inherited colour impairment is passed down genetically from parents to children (primarily from mother to son). Acquired colour impairment can be the result of chronic illness, accidents, chemicals, medications or age. + +Part of the process used when defining the design system brand colours, is to make sure that foreground and background colour combinations have the appropriate colour contrast luminosity ratios (in compliance with WCAG 2.1 AA). Adhering to this contrast ratio allows all our customers to differentiate our brand colours. We also highlight the situations where our brand colours will not have a high enough contrast ratio to be used together. + +Our colour vision impairment tool allows us to view the design system components as someone with an impairment would see them. It shows how important it is to ensure that when designing, you should never rely on a difference in colour alone to communicate to your users. + +Each of the filters in the colour impairment tool shows how the perception of colour is affected by different conditions, very broadly these are: + +## Protanopes + +- _Protanopia_ - No sensitivity to red light. +- _Protanomaly_ - Reduced sensitivity to red light. + +Protanopes tend to find it difficult to distinguish greens, yellows, oranges, reds and browns from each other. + +## Deuteranopes + +- _Deuteranopia_ - No sensitivity to green light. +- _Deuteranomaly_ - Reduced sensitivity to green light. + +Deuteranopes are likely to confuse colours such as green and yellow, or blue and purple, they may also struggle to distinguish between pink and grey or white. + +## Tritanopes + +- _Tritanopia_ - No sensitivity to blue light. +- _Tritanomaly_ - Reduced sensitivity to blue light. + +Tritanopes tend to find it difficult to see the difference between light blues and greys, dark purples and black, mid-greens and blues and oranges and reds. + +## Monochromacy + +- _Achromatopsia_ - Reduced sensitivity to all colours. +- _Achromatomaly_ - No sensitivity to colour. + +Monochromats see the world in black, white and shades of grey. Less severe cases may perceive small traces of specific colours, when the light conditions are just right. + +## Low-contrast + +People with a vision impairment that effects their perception of contrast will struggle to see the difference between colours that do not have enough contrast between them, ie light grey against white. diff --git a/apps/site/src/content/design-system/components/flexi-cell/code.mdoc b/apps/site/src/content/design-system/components/flexi-cell/code.mdoc index e497a7c6c..9f5182113 100644 --- a/apps/site/src/content/design-system/components/flexi-cell/code.mdoc +++ b/apps/site/src/content/design-system/components/flexi-cell/code.mdoc @@ -3,7 +3,7 @@ ### Default usage ```jsx - + Label Hint @@ -13,7 +13,7 @@ ```jsx - + Label Hint @@ -27,13 +27,15 @@ tag="a" href="#" withBorder - body after={ - $9,999.99 + + $9,999.99 + avail $9,999.99 } + size={{ initial: "default", sm: "large" }} > Credit card Card ending in 1234 @@ -47,12 +49,14 @@ tag="a" href="#" withBorder - body after={ - $9,999.99 + + $9,999.99 + } + size={{ initial: "default", sm: "large" }} > Account 032-123 12345678 @@ -63,23 +67,24 @@ ```jsx - B - - } after={ - Fri 5 Aug + + Fri 5 Aug + } + before={ + + WW + + } + tag="a" + href="#" + size={{ initial: "default", sm: "large" }} > -

Payee

- Payee details + With Circle and Info Button + Payee Details
``` @@ -87,23 +92,22 @@ ```jsx - WW - - } after={ - - - - ))} - -``` - ### Account list usage ```jsx @@ -265,26 +287,25 @@ ]; return ( -
+ <> {MOCK_ACCOUNTS.map(({ title, id, accounts }) => ( -
-

{title}

-
+
+

{title}

{accounts.map(({ name, amount, number }) => ( - + + {amount} - available + available $9,999 } + size={{ initial: 'default', sm: 'large' }} > {name} @@ -293,9 +314,8 @@ ))}
-
))} -
+ ); }; ``` @@ -356,57 +376,54 @@ ]; return ( -
+ <> {MOCK_PAYEES.map(({ title, id, payees }) => ( -
-

{title}

-
- {payees.map(({ name, initials, paidAt, number }) => { - return ( - - - - } - after={ - - {paidAt ? ( - {paidAt} - ) : ( - - )} - - } - > - {paidAt ? ( - <> - - {name} - - {number} - - ) : ( - - - {name} - - {number} - - )} - - ); - })} -
+
+

{title}

+ {payees.map(({ name, initials, number, paidAt }) => + paidAt ? ( + + {initials} + + } + after={ + + + {paidAt} + + + } + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + + ) : ( + + {initials} + + } + after={ } />} + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + + ), + )}
))} -
+ ); }; ``` @@ -459,28 +476,26 @@ ]; return ( -
+
{MOCK_COUNTRIES.map(({ title, id, payees }) => (

{title}

-
+
{payees.map(({ name }) => { return ( + } + size={{ initial: 'default', sm: 'large' }} > - - {name} - + {name} ); })} @@ -503,26 +517,28 @@ }; ``` -### Foreign currency list usage +### Foreign Payee list usage ```jsx () => { - const MOCK_PAYEES = [ + const MOCK_FOREIGNPAYEES = [ { title: 'Recently Paid', id: 'recently-paid', payees: [ { - initials: 'AJ', name: 'Andrew Jones', paidAt: 'Fri 5 Aug', - number: '123-986 463846', + number: '10964567891', + bank: 'BANK OF ANTARCTICA, ANTARCTICA', + code: 'NFBKAS33XXX', }, { - initials: 'JW', name: 'Joss Wight', paidAt: 'Mon 1 Aug', - number: '098-567 465352', + number: '10964567892', + bank: 'LLOYDS OF LONDON, DEVON', + code: 'NFBKAS33XXX', }, ], }, @@ -531,27 +547,31 @@ id: 'a', payees: [ { - initials: 'AO', - name: 'Active OOSH', - number: '857-434 856383', + name: 'American Apparel', + number: '10964567894', + bank: 'BANK OF AMERICA, NEW YORK', + code: 'NFBKAS33XXX', paidAt: undefined, }, { initials: 'AC', - name: 'Alice Cartwright', - number: '950-456 345363', + name: 'Alfred Prince', + number: '10964567895', + bank: 'BANK OF AMERICA, NEW YORK', + code: 'NFBKAS33XXX', paidAt: undefined, }, ], }, { - title: 'B', - id: 'b', + title: 'H', + id: 'h', payees: [ { - initials: 'BN', - name: 'Benjamin North', - number: '098-123 745362', + name: 'Havana Houseboats', + number: '10964567896', + bank: 'BANK OF CUBA, HAVANA', + code: 'NFBKAS33XXX', paidAt: undefined, }, ], @@ -559,66 +579,78 @@ ]; return ( -
- {MOCK_PAYEES.map(({ title, id, payees }) => ( -
-

{title}

-
- {payees.map(({ name, paidAt, number }) => { - return ( - - - - - - - - } - after={ - - {paidAt ? ( - {paidAt} - ) : ( - - )} - - } - > - {paidAt ? ( - <> - - {name} - - {number} - - ) : ( - - - {name} - - {number} - - )} - - ); - })} -
+ <> + {MOCK_FOREIGNPAYEES.map(({ title, id, payees }) => ( +
+

{title}

+ {payees.map(({ name, number, paidAt, bank, code }) => + paidAt ? ( + + + + + + + + } + after={ + + + {paidAt} + + + } + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + {bank} + {code} + + ) : ( + + + + + + + + } + after={ } />} + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + {bank} + {code} + + ), + )}
))} -
+ ); }; ``` @@ -629,131 +661,115 @@ () => { const MOCK_PROMOS = [ { - title: 'This is talking about the bonus.', + title: 'This is talking about the bonus', subtitle: 'This is more about the bonus and all the other exciting things about this.', - stars: true, }, { - title: 'This is a longer heading talking all about the bonus this one wraps.', + title: 'This is a longer heading talking all about the bonus this one wraps', subtitle: 'This is more about the bonus', - stars: false, }, { - title: 'This is talking about the bonus.', + title: 'This is talking about the bonus', subtitle: 'This is more about the bonus and all the other exciting things about this.', - stars: false, - }, - { - title: 'This is a longer heading talking all about the bonus this one wraps.', - subtitle: 'This is more about the bonus', - stars: false, }, ]; return ( -
- {MOCK_PROMOS.map(({ title, subtitle, stars }) => { - return ( - - Target - - } - badge={ - - {stars ? '✭' : 'Corner flag'} - - } - > - MYER - - {title} - - {subtitle} -
- Badge1 - Badge2 -
-
- ); - })} +
+ {MOCK_PROMOS.map(({ title, subtitle }) => ( + + + Graphic Here + + + } + topBadge={({ className }) => ( + + Corner flag + + )} + size={{ initial: 'default', sm: 'large' }} + > + + MYER + + + {title} + + {subtitle} + + Badge 1 + Badge 2 + + + ))}
); }; ``` -### Promo tiles vertical list usage +### Vertical Promo Tiles ```jsx () => { - const MOCK_PROMOS = [ - { - title: 'This is talking about the bonus.', - subtitle: 'This is more about the bonus and all the other exciting things about this.', - stars: true, - }, + const MOCK_VERTICAL_PROMOS = [ { - title: 'This is a longer heading talking all about the bonus this one wraps.', - subtitle: 'This is more about the bonus', - stars: false, + title: 'About the bonus', + subtitle: + 'The bonus and all the other exciting things. This will truncate if it gets too long with some extra text to make it a bit longer.', }, { - title: 'This is talking about the bonus.', - subtitle: 'This is more about the bonus and all the other exciting things about this.', - stars: false, + title: 'Short heading', + subtitle: 'This is more about the bonus.', }, { - title: 'This is a longer heading talking all about the bonus this one wraps.', + title: 'This is a longer heading talking all about the bonus this one wraps', subtitle: 'This is more about the bonus', - stars: false, }, ]; return ( -
-
- {MOCK_PROMOS.map(({ title, subtitle }) => ( - - Badge - - } - > - - - MYER - - {title} - - {subtitle} - - - - - - ))} -
+
+ {MOCK_VERTICAL_PROMOS.map(({ title, subtitle }) => ( + ( + + Corner flag + + )} + size={{ initial: 'default', sm: 'large' }} + > + + + + + + MYER + + + {title} + + {subtitle} + + Badge 1 + Badge 2 + + + ))}
); }; @@ -763,37 +779,51 @@ ```jsx () => { - const MOCK_PRODUCTS = [ - { - title: 'This is talking about the bonus.', - subtitle: 'This is more about the bonus and all the other exciting things about this.', - }, - { - title: 'This is a longer heading talking all about the bonus this one wraps.', - subtitle: 'This is more about the bonus', - }, - { - title: 'This is talking about the bonus.', - subtitle: 'This is more about the bonus and all the other exciting things about this.', - }, - ]; - + const title = 'Westpac specials and product offers'; + const subtitle = 'Discounts and cashback from select merchants & products offers from Westpac'; return ( -
- {MOCK_PRODUCTS.map(({ title, subtitle }) => ( - }> -
-
-
- ))} -
+ <> + + + + } + after={} + size={{ initial: 'default', sm: 'large' }} + > + + + {title} + + {subtitle} + + + + + } + after={} + size={{ initial: 'default', sm: 'large' }} + > + + + {title} + + {subtitle} + + ); }; ``` diff --git a/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.component.tsx b/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.component.tsx index d6abe7182..de5d292f8 100644 --- a/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.component.tsx +++ b/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.component.tsx @@ -1,18 +1,19 @@ import React from 'react'; -import { styles } from './flexi-cell-adornment.styles.js'; +import { styles as adornmentStyles } from './flexi-cell-adornment.styles.js'; import { type FlexiCellAdornmentProps } from './flexi-cell-adornment.types.js'; /** Flexi Cell Adornment: Flexi Cell Adornment */ export const FlexiCellAdornment = ({ children, tag: Tag = 'div', - align = 'center', + align, className, ...props }: FlexiCellAdornmentProps) => { + const styles = adornmentStyles({ align }); return ( - + {children} ); diff --git a/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.styles.ts b/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.styles.ts index 16148a0a6..53bc5631a 100644 --- a/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.styles.ts +++ b/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.styles.ts @@ -2,12 +2,14 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { - base: 'flex flex-col items-end gap-1', + slots: { + base: 'flex flex-none flex-col items-end gap-1', + }, variants: { align: { - center: 'justify-center', - top: 'justify-start', - bottom: 'justify-end', + center: { base: 'justify-center' }, + top: { base: 'justify-start' }, + bottom: { base: 'justify-end' }, }, }, }, diff --git a/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.types.ts b/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.types.ts index a7bea95b2..42ca5d3bb 100644 --- a/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.types.ts +++ b/packages/ui/src/components/flexi-cell/components/flexi-cell-adornment/flexi-cell-adornment.types.ts @@ -8,7 +8,7 @@ export type FlexiCellAdornmentProps = { /** * Children attribute */ - children: ReactNode; + children?: ReactNode; /** * Component's tag */ diff --git a/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.component.tsx b/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.component.tsx index 0fc5f64c9..4617968c7 100644 --- a/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.component.tsx +++ b/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.component.tsx @@ -1,12 +1,19 @@ import React from 'react'; +import { mergeProps, useFocusRing } from 'react-aria'; import { styles } from './flexi-cell-body.styles.js'; import { type FlexiCellBodyProps } from './flexi-cell-body.types.js'; /** Flexi Cell Body: Flexi Cell Body */ -export const FlexiCellBody = ({ children, tag: Tag = 'div', className, ...props }: FlexiCellBodyProps) => { +export const FlexiCellBody = ({ children, tag: Tag = 'div', href, className, ...props }: FlexiCellBodyProps) => { + const { isFocusVisible, focusProps } = useFocusRing(); + return ( - + {children} ); diff --git a/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.styles.ts b/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.styles.ts index c18a490fb..a65a92ce5 100644 --- a/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.styles.ts +++ b/packages/ui/src/components/flexi-cell/components/flexi-cell-body/flexi-cell-body.styles.ts @@ -2,8 +2,18 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { - base: 'flex flex-1 flex-col gap-1', - variants: {}, + base: 'flex flex-1 flex-col gap-1 overflow-hidden', + variants: { + isLink: { + true: 'group/dualaction', + }, + isFocusVisible: { + true: 'focus-outline', + }, + multipleChildren: { + true: { base: '' }, + }, + }, }, { responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] }, ); diff --git a/packages/ui/src/components/flexi-cell/components/flexi-cell-button/flexi-cell-button.component.tsx b/packages/ui/src/components/flexi-cell/components/flexi-cell-button/flexi-cell-button.component.tsx index adbbe8eb9..4f6e62c14 100644 --- a/packages/ui/src/components/flexi-cell/components/flexi-cell-button/flexi-cell-button.component.tsx +++ b/packages/ui/src/components/flexi-cell/components/flexi-cell-button/flexi-cell-button.component.tsx @@ -2,11 +2,13 @@ import React from 'react'; import { Button } from '../../../../components/index.js'; -import { styles } from './flexi-cell-button.styles.js'; +import { styles as flexiButtonStyles } from './flexi-cell-button.styles.js'; import { type FlexiCellButtonProps } from './flexi-cell-button.types.js'; /** Flexi Cell Button: Flexi Cell Button */ -export const FlexiCellButton = ({ className, ...props }: FlexiCellButtonProps) => { - return - - - ))} -
+ <> + + List Item + + + + + + + + + } + tag="a" + href="#" + withBorder + size={{ initial: 'default', sm: 'large' }} + > + + List Item With Flag + + + ); }, }; @@ -333,42 +345,43 @@ const MOCK_ACCOUNTS = [ ], }, ]; -// WIP -export const AccountList: Story = { + +/** + * > Example of how an account list could be made + */ +export const AccountLists: Story = { args: {}, render: () => { return ( -
+ <> {MOCK_ACCOUNTS.map(({ title, id, accounts }) => ( -
-

{title}

-
- {accounts.map(({ name, amount, number }) => ( - - - {amount} - - available - - } - > - - {name} - - {number} - - ))} -
+
+

{title}

+ {accounts.map(({ name, amount, number }) => ( + + + {amount} + + available $9,999 + + } + size={{ initial: 'default', sm: 'large' }} + > + + {name} + + {number} + + ))}
))} -
+ ); }, }; @@ -424,81 +437,83 @@ const MOCK_PAYEES = [ }, ]; +/** + * > Example of how a payee list could be made + */ export const PayeeList: Story = { args: {}, render: () => { return ( -
+ <> {MOCK_PAYEES.map(({ title, id, payees }) => ( -
-

{title}

-
- {payees.map(({ name, initials, paidAt, number }) => { - return ( - - - - } - after={ - - {paidAt ? ( - {paidAt} - ) : ( - - )} - - } - > - {paidAt ? ( - <> - - {name} - - {number} - - ) : ( - - - {name} - - {number} - - )} - - ); - })} -
+
+

{title}

+ {payees.map(({ name, initials, number, paidAt }) => + paidAt ? ( + + {initials} + + } + after={ + + + {paidAt} + + + } + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + + ) : ( + + {initials} + + } + after={ } />} + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + + ), + )}
))} -
+ ); }, }; -const MOCK_COUNTRIES = [ +const MOCK_FOREIGNPAYEES = [ { - title: 'Popular', - id: 'popular', + title: 'Recently Paid', + id: 'recently-paid', payees: [ { - code: 'IN', - name: 'India', - }, - { - code: 'UK', - name: 'United Kingdom', + name: 'Andrew Jones', + paidAt: 'Fri 5 Aug', + number: '10964567891', + bank: 'BANK OF ANTARCTICA, ANTARCTICA', + code: 'NFBKAS33XXX', }, { - code: 'USA', - name: 'United States', + name: 'Joss Wight', + paidAt: 'Mon 1 Aug', + number: '10964567892', + bank: 'LLOYDS OF LONDON, DEVON', + code: 'NFBKAS33XXX', }, ], }, @@ -507,283 +522,333 @@ const MOCK_COUNTRIES = [ id: 'a', payees: [ { - code: 'AI', - name: 'Ascension Islands', - }, - { - code: 'AN', - name: 'Andorra', + name: 'American Apparel', + number: '10964567894', + bank: 'BANK OF AMERICA, NEW YORK', + code: 'NFBKAS33XXX', + paidAt: undefined, }, { - code: 'UA', - name: 'United Arab Emirates', + initials: 'AC', + name: 'Alfred Prince', + number: '10964567895', + bank: 'BANK OF AMERICA, NEW YORK', + code: 'NFBKAS33XXX', + paidAt: undefined, }, + ], + }, + { + title: 'H', + id: 'h', + payees: [ { - code: 'AF', - name: 'Afghanistan', + name: 'Havana Houseboats', + number: '10964567896', + bank: 'BANK OF CUBA, HAVANA', + code: 'NFBKAS33XXX', + paidAt: undefined, }, ], }, ]; -export const CountryList: Story = { +/** + * > Example of how a foreign currency payee list could be made + */ +export const ForeinCurrencyPayeeList: Story = { args: {}, render: () => { return ( -
- {MOCK_COUNTRIES.map(({ title, id, payees }) => ( -
-

{title}

-
- {payees.map(({ name }) => { - return ( - - - - } - > - - {name} - - - ); - })} -
+ <> + {MOCK_FOREIGNPAYEES.map(({ title, id, payees }) => ( +
+

{title}

+ {payees.map(({ name, number, paidAt, bank, code }) => + paidAt ? ( + + + + + + + + } + after={ + + + {paidAt} + + + } + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + {bank} + {code} + + ) : ( + + + + + + + + } + after={ } />} + size={{ initial: 'default', sm: 'large' }} + > + {name} + {number} + {bank} + {code} + + ), + )}
))} -
+ ); }, }; -export const ForeignCurrencyList: Story = { +const ICON_LIST = [ + (props: { className?: string }) => , + (props: { className?: string }) => , + (props: { className?: string }) => , +]; + +/** + * > Example of how product tiles could be made + */ +export const ProductTiles: Story = { args: {}, render: () => { + const title = 'Westpac specials and product offers'; + const subtitle = 'Discounts and cashback from select merchants & products offers from Westpac'; return ( -
- {MOCK_PAYEES.map(({ title, id, payees }) => ( -
-

{title}

-
- {payees.map(({ name, paidAt, number }) => { - return ( - - - - - - - - } - after={ - - {paidAt ? ( - {paidAt} - ) : ( - - )} - - } - > - {paidAt ? ( - <> - - {name} - - {number} - - ) : ( - - - {name} - - {number} - - )} - - ); - })} -
-
+ <> + {ICON_LIST.map(Icon => ( + + + + } + size={{ initial: 'default', sm: 'large' }} + > + + + {title} + + {subtitle} + ))} -
+ + ); + }, +}; + +/** + * > Example of product tiles with the extra icon could be made + */ +export const ProductTilesWithExtraIcon: Story = { + args: {}, + render: () => { + const title = 'Westpac specials and product offers'; + const subtitle = 'Discounts and cashback from select merchants & products offers from Westpac'; + return ( + <> + + + + } + after={} + size={{ initial: 'default', sm: 'large' }} + > + + + {title} + + {subtitle} + + + + + } + after={} + size={{ initial: 'default', sm: 'large' }} + > + + + {title} + + {subtitle} + + ); }, }; const MOCK_PROMOS = [ { - title: 'Get 50% Off on All Products', - subtitle: 'Limited time offer! Save big on our entire range of products.', + title: 'This is talking about the bonus', + subtitle: 'This is more about the bonus and all the other exciting things about this.', stars: true, }, { - title: 'Exclusive Membership Benefits', - subtitle: 'Unlock premium features and discounts with our membership program.', - stars: false, - }, - { - title: 'New Arrival Alert!', - subtitle: 'Discover the latest arrivals and stay ahead of the trend.', + title: 'This is a longer heading talking all about the bonus this one wraps', + subtitle: 'This is more about the bonus', stars: false, }, { - title: 'Weekend Special Sale', - subtitle: "Don't miss out on our weekend sale with massive discounts!", + title: 'This is talking about the bonus', + subtitle: 'This is more about the bonus and all the other exciting things about this.', stars: false, }, ]; +/** + * > Example of horizontal promo tiles + */ export const PromotilesHorizontalList: Story = { args: {}, render: () => { return ( -
- {MOCK_PROMOS.map(({ title, subtitle, stars }) => { - return ( - - Target - - } - badge={ - - {stars ? '✭' : 'Corner flag'} - - } - > - MYER - - {title} - - {subtitle} -
- Badge1 - Badge2 -
-
- ); - })} -
- ); - }, -}; - -export const PromotilesVerticalList: Story = { - args: {}, - render: () => { - return ( -
-
- {MOCK_PROMOS.map(({ title, subtitle }) => ( - - Badge - - } - > - - - MYER - - {title} - - {subtitle} - - - - - - ))} -
+
+ {MOCK_PROMOS.map(({ title, subtitle, stars }) => ( + + + + + + } + topBadge={({ className }) => ( + + {stars ? '✭' : 'Corner flag'} + + )} + size={{ initial: 'default', sm: 'large' }} + > + + MYER + + + {title} + + {subtitle} + + Badge 1 + Badge 2 + + + ))}
); }, }; -const MOCK_PRODUCTS = [ +const MOCK_VERTICAL_PROMOS = [ { - title: 'This is talking about the bonus.', - subtitle: 'This is more about the bonus and all the other exciting things about this.', + title: 'About the bonus', + subtitle: + 'The bonus and all the other exciting things. This will truncate if it gets too long with some extra text to make it a bit longer.', }, { - title: 'This is a longer heading talking all about the bonus this one wraps.', - subtitle: 'This is more about the bonus', + title: 'Short heading', + subtitle: 'This is more about the bonus.', }, { - title: 'This is talking about the bonus.', - subtitle: 'This is more about the bonus and all the other exciting things about this.', + title: 'This is a longer heading talking all about the bonus this one wraps', + subtitle: 'This is more about the bonus', }, ]; -export const ProductTiles: Story = { +/** + * > Example of vertical promo tiles + */ +export const PromotilesVerticalList: Story = { args: {}, render: () => { return ( -
- {MOCK_PRODUCTS.map(({ title, subtitle }) => ( - }> -
-
+
+ {MOCK_VERTICAL_PROMOS.map(({ title, subtitle }) => ( + Corner flag} + size={{ initial: 'default', sm: 'large' }} + > + + + + + + MYER + + + {title} + + {subtitle} + + Badge 1 + Badge 2 + ))}
diff --git a/packages/ui/src/components/flexi-cell/flexi-cell.styles.ts b/packages/ui/src/components/flexi-cell/flexi-cell.styles.ts index 5fe9f0865..dafbfd2cb 100644 --- a/packages/ui/src/components/flexi-cell/flexi-cell.styles.ts +++ b/packages/ui/src/components/flexi-cell/flexi-cell.styles.ts @@ -3,25 +3,31 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { slots: { - base: 'relative flex gap-2 bg-white p-2 transition-colors xsl:p-3', - bodyWrapper: 'flex flex-1 flex-col', - badge: 'absolute right-0 top-0', + base: 'relative flex bg-white transition-colors', + topBadgeWrapper: 'absolute right-[-1px] top-[-1px]', + topBadge: 'rounded-br-none rounded-tl-none', }, variants: { withBorder: { true: { base: 'rounded border border-borderDark', }, - false: {}, }, isLink: { true: { base: 'hover:border-hero', }, - false: {}, + false: '', }, - isFocusVisible: { - true: { base: 'focus-outline' }, + isFocusVisible: { true: { base: 'focus-outline' }, false: {} }, + shouldHoverEffect: { + true: { + base: 'group/noborder', + }, + }, + size: { + default: { base: 'mb-2 gap-2 p-2' }, + large: { base: 'mb-3 gap-3 p-3' }, }, }, }, diff --git a/packages/ui/src/components/flexi-cell/flexi-cell.types.ts b/packages/ui/src/components/flexi-cell/flexi-cell.types.ts index 8adf08a70..0568e15d2 100644 --- a/packages/ui/src/components/flexi-cell/flexi-cell.types.ts +++ b/packages/ui/src/components/flexi-cell/flexi-cell.types.ts @@ -1,38 +1,47 @@ -import { CSSProperties, type HTMLAttributes, type ReactNode } from 'react'; +import { type HTMLAttributes, type ReactNode } from 'react'; +import { VariantProps } from 'tailwind-variants'; + +import { BadgeProps } from '../index.js'; + +import { styles } from './flexi-cell.styles.js'; + +type Variants = VariantProps; type BaseFlexiCellProps = { /** * Renders an element on the right */ after?: ReactNode; - /** - * Renders an element on the top right corner - */ - badge?: ReactNode; - /** - * zIndex for badge - */ - badgeZIndex?: CSSProperties['zIndex']; /** * Renders an element on the left */ before?: ReactNode; - /** - * Injects the FlexiCell.Body inside of the children - */ - body?: boolean; /** * the middle content of FlexiCell */ children?: ReactNode; /** - * href in case it is an "a" tag + * Wraps body with an 'a' tag for dual action styled component + * - Requires href to be provided + * - Tag prop should not be used when using this prop + */ + dualAction?: boolean; + /** + * href in case it is an "a" tag or dualAction */ href?: string; + /** + * Large adds more padding/spacing to the Flex Cell + */ + size?: Variants['size']; /** * The native tag that flexicell will be rendered */ tag?: keyof JSX.IntrinsicElements; + /** + * Renders badge in top right corner based on provided string + */ + topBadge?: (props: BadgeProps) => JSX.Element; /** * Adds an arrow on top right */ @@ -41,10 +50,6 @@ type BaseFlexiCellProps = { * Adds a border radius and a border */ withBorder?: boolean; - /** - * With hover style - */ - withHoverEffect?: boolean; } & HTMLAttributes; type FlexiCellAsLinkProps = { @@ -58,6 +63,17 @@ type FlexiCellAsLinkProps = { tag: 'a'; }; +type DualActionFlexiCellProps = { + /** + * The native tag that the circle will be rendered as + */ + dualAction: true; + /** + * The href for the link + */ + href: string; +}; + type FlexiCellAsAllOtherTagsProps = { href?: never; tag?: Tag; @@ -65,4 +81,6 @@ type FlexiCellAsAllOtherTagsProps = { export type FlexiCellProps< Tag extends keyof Omit = keyof Omit, -> = (FlexiCellAsLinkProps | FlexiCellAsAllOtherTagsProps) & BaseFlexiCellProps & HTMLAttributes; +> = (FlexiCellAsLinkProps | DualActionFlexiCellProps | FlexiCellAsAllOtherTagsProps) & + BaseFlexiCellProps & + HTMLAttributes; diff --git a/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.component.tsx b/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.component.tsx index c5cf66b2f..422e26490 100644 --- a/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.component.tsx +++ b/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.component.tsx @@ -25,10 +25,7 @@ function BaseSelectorCheckboxGroupOption( withBorder = true, withArrow, after, - badge, - badgeZIndex, before, - body = true, checkIcon = 'checkbox', ...props }: SelectorCheckboxGroupOptionProps, @@ -56,15 +53,11 @@ function BaseSelectorCheckboxGroupOption(
} - badge={badge} - badgeZIndex={badgeZIndex} before={before} - body={body} withBorder={withBorder} withArrow={withArrow} tag="label" ref={ref} - withHoverEffect className={styles.base({})} > diff --git a/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.styles.ts b/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.styles.ts index 2ccb3df8c..4038ca8bf 100644 --- a/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.styles.ts +++ b/packages/ui/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.styles.ts @@ -3,13 +3,13 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { slots: { - base: 'group/checkbox-option cursor-pointer', + base: 'group/checkbox-option max-sm:mb-0 max-sm:gap-2 max-sm:p-2 sm:mb-0 sm:gap-3 sm:p-3', icon: 'transition-transform', }, variants: { checkIcon: { arrow: { - icon: 'text-primary group-hover/checkbox-option:translate-x-1', + icon: 'mr-[-6px] text-primary', }, checkbox: {}, }, @@ -29,7 +29,9 @@ export const styles = tv( true: { base: 'opacity-50', }, - false: {}, + false: { + base: 'cursor-pointer hover:border-hero', + }, }, }, compoundVariants: [ @@ -47,6 +49,13 @@ export const styles = tv( icon: 'opacity-100', }, }, + { + checkIcon: 'arrow', + isDisabled: false, + className: { + icon: 'max-sm:group-hover/checkbox-option:translate-x-0.5 sm:group-hover/checkbox-option:translate-x-1', + }, + }, ], }, { responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] }, diff --git a/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx b/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx index b3c38b8c8..4e317e5eb 100644 --- a/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx +++ b/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx @@ -30,7 +30,7 @@ export function SelectorCheckboxGroup(props: SelectorCheckboxGroupProps) { return (
- {label} + {label && {label}} {description && {description}} {errorMessage && state.validationState === 'invalid' && ( diff --git a/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.styles.ts b/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.styles.ts index c4e4ea35b..d52371ac3 100644 --- a/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.styles.ts +++ b/packages/ui/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.styles.ts @@ -2,7 +2,7 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { - base: 'flex flex-col gap-2 md:gap-3', + base: 'flex flex-col gap-2 sm:gap-3', variants: {}, }, { responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] }, diff --git a/packages/ui/src/components/selector/components/selector-label/selector-label.styles.ts b/packages/ui/src/components/selector/components/selector-label/selector-label.styles.ts index 493a73e2b..f5b41f0ea 100644 --- a/packages/ui/src/components/selector/components/selector-label/selector-label.styles.ts +++ b/packages/ui/src/components/selector/components/selector-label/selector-label.styles.ts @@ -1,5 +1,5 @@ import { tv } from 'tailwind-variants'; export const styles = tv({ - base: 'font-medium', + base: 'font-medium max-sm:typography-body-9 sm:typography-body-8', }); diff --git a/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.component.tsx b/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.component.tsx index 253055500..31bf5c3a1 100644 --- a/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.component.tsx +++ b/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.component.tsx @@ -25,10 +25,7 @@ function BaseSelectorRadioGroupOption( withBorder = true, withArrow, after, - badge, - badgeZIndex, before, - body = true, checkIcon = 'checkbox', ...props }: SelectorRadioGroupOptionProps, @@ -50,16 +47,12 @@ function BaseSelectorRadioGroupOption(
} - badge={badge} - badgeZIndex={badgeZIndex} before={before} - body={body} withBorder={withBorder} withArrow={withArrow} tag="label" ref={ref} className={styles.base({})} - withHoverEffect > diff --git a/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.styles.ts b/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.styles.ts index 177a72a5c..2c4caae6e 100644 --- a/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.styles.ts +++ b/packages/ui/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.styles.ts @@ -3,13 +3,13 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { slots: { - base: 'group/radio-option cursor-pointer', + base: 'group/radio-option max-sm:mb-0 max-sm:gap-2 max-sm:p-2 sm:mb-0 sm:gap-3 sm:p-3', icon: 'transition-transform', }, variants: { checkIcon: { arrow: { - icon: 'text-primary group-hover/radio-option:translate-x-1', + icon: 'mr-[-6px] text-primary', }, checkbox: {}, }, @@ -29,7 +29,7 @@ export const styles = tv( true: { base: 'opacity-50', }, - false: {}, + false: { base: 'cursor-pointer hover:border-hero' }, }, }, compoundVariants: [ @@ -47,6 +47,13 @@ export const styles = tv( icon: 'opacity-100', }, }, + { + checkIcon: 'arrow', + isDisabled: false, + className: { + icon: 'max-sm:group-hover/radio-option:translate-x-0.5 sm:group-hover/radio-option:translate-x-1', + }, + }, ], }, { responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] }, diff --git a/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx b/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx index b8f7c0990..4bfac4018 100644 --- a/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx +++ b/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx @@ -39,7 +39,7 @@ export function SelectorRadioGroup({ return (
- {label} + {label && {label}} {description && {description}} {errorMessage && state.validationState === 'invalid' && ( diff --git a/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.styles.ts b/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.styles.ts index e81a7f2c0..4358cb5c0 100644 --- a/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.styles.ts +++ b/packages/ui/src/components/selector/components/selector-radio-group/selector-radio-group.styles.ts @@ -2,7 +2,7 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { - base: 'flex gap-2 md:gap-3', + base: 'flex gap-2 sm:gap-3', variants: { orientation: { vertical: 'flex-col', diff --git a/packages/ui/src/components/selector/selector.stories.tsx b/packages/ui/src/components/selector/selector.stories.tsx index f92d7f00c..645a2ffa1 100644 --- a/packages/ui/src/components/selector/selector.stories.tsx +++ b/packages/ui/src/components/selector/selector.stories.tsx @@ -1,7 +1,7 @@ import { type Meta, StoryFn, type StoryObj } from '@storybook/react'; import { useState } from 'react'; -import { PersonIcon } from '../icon/index.js'; +import { EmailIcon, PersonIcon, SettingsIcon, WatchIcon } from '../icon/index.js'; import { VisuallyHidden } from '../index.js'; import { BusPictogram, ChatPictogram, PizzaPictogram } from '../pictogram/index.js'; @@ -33,7 +33,7 @@ export const Default = () => { { key: 'C', disabled: false }, { key: 'D', disabled: true }, ].map(({ key, disabled }) => ( - + Something {key} ))} @@ -53,7 +53,7 @@ export const Radio = () => { { key: 'C', disabled: false }, { key: 'D', disabled: true }, ].map(({ key, disabled }) => ( - + Something {key} ))} @@ -73,7 +73,7 @@ export const CheckWithArrow = () => { { key: 'C', disabled: false }, { key: 'D', disabled: true }, ].map(({ key, disabled }) => ( - + Something {key} ))} @@ -102,7 +102,7 @@ export const RadioWithState = () => { { key: 'C', disabled: false }, { key: 'D', disabled: true }, ].map(({ key, disabled }) => ( - + Something {key} ))} @@ -132,7 +132,7 @@ export const CheckboxWithState = () => { { key: 'C', disabled: false }, { key: 'D', disabled: true }, ].map(({ key, disabled }) => ( - + Something {key} ))} @@ -153,7 +153,7 @@ export const LongText = () => { { key: 'C', disabled: false }, { key: 'D', disabled: true }, ].map(({ key, disabled }) => ( - + Lorem, ipsum dolor sit amet consectetur adipisicing elit. Maiores architecto eum aperiam consectetur quibusdam. Laboriosam saepe, explicabo odio quis doloribus consequuntur quae et necessitatibus quasi @@ -196,7 +196,7 @@ export const HintText = () => { }, { label: HERE_IS_A_LABEL_C, hint: '', key: 'C', disabled: false }, ].map(({ key, disabled, hint, label }) => ( - + {label} {hint && {hint}} @@ -256,7 +256,7 @@ export const Pictogram = () => { disabled: false, }, ].map(({ key, disabled, hint, label, before }) => ( - + {label} {hint && {hint}} @@ -316,7 +316,7 @@ export const PictogramSizes = () => { disabled: false, }, ].map(({ key, disabled, hint, label, before }) => ( - + {label} {hint && {hint}} @@ -367,7 +367,7 @@ export const IconsSizes = () => { { before: ( - + ), label: HERE_IS_A_LABEL_C, @@ -376,7 +376,7 @@ export const IconsSizes = () => { disabled: false, }, ].map(({ key, disabled, hint, label, before }) => ( - + {label} {hint && {hint}} @@ -395,7 +395,7 @@ export const IconsAndSecondaryLabel = () => { { before: ( - + ), label: HERE_IS_A_LABEL_A, @@ -412,7 +412,7 @@ export const IconsAndSecondaryLabel = () => { { before: ( - + ), label: HERE_IS_A_LABEL_B, @@ -429,7 +429,7 @@ export const IconsAndSecondaryLabel = () => { { before: ( - + ), label: HERE_IS_A_LABEL_C, @@ -448,7 +448,7 @@ export const IconsAndSecondaryLabel = () => { disabled: false, }, ].map(({ key, disabled, hint, label, before, after }) => ( - + {label} {hint && {hint}} @@ -467,11 +467,11 @@ export const RadioWithIconsAndSecondaryLabel = () => { { before: ( - + ), label: HERE_IS_A_LABEL_A, - after: $200,000.00, + after: $10,000.00, hint: ( <> Bank Account @@ -484,7 +484,7 @@ export const RadioWithIconsAndSecondaryLabel = () => { { before: ( - + ), label: HERE_IS_A_LABEL_B, @@ -501,7 +501,7 @@ export const RadioWithIconsAndSecondaryLabel = () => { { before: ( - + ), label: HERE_IS_A_LABEL_C, @@ -520,15 +520,7 @@ export const RadioWithIconsAndSecondaryLabel = () => { disabled: false, }, ].map(({ key, disabled, hint, label, before, after }) => ( - + {label} {hint && {hint}} @@ -547,7 +539,7 @@ export const Disabled = () => { { before: ( - + ), label: HERE_IS_A_LABEL_A, @@ -564,7 +556,7 @@ export const Disabled = () => { { before: ( - + ), label: HERE_IS_A_LABEL_B, @@ -581,7 +573,7 @@ export const Disabled = () => { { before: ( - + ), label: HERE_IS_A_LABEL_C, @@ -600,15 +592,7 @@ export const Disabled = () => { disabled: true, }, ].map(({ key, disabled, hint, label, before, after }) => ( - + {label} {hint && {hint}}