diff --git a/.changeset/cuddly-seals-design.md b/.changeset/cuddly-seals-design.md new file mode 100644 index 000000000..3aeb1425a --- /dev/null +++ b/.changeset/cuddly-seals-design.md @@ -0,0 +1,5 @@ +--- +'@westpac/ui': minor +--- + +Updated types on some components to resolve eslint errors/warnings diff --git a/apps/site/src/content/design-system/components/badge/design/badge-styles/content.mdoc b/apps/site/src/content/design-system/components/badge/design/badge-styles/content.mdoc index 8edd1a28f..3a2376810 100644 --- a/apps/site/src/content/design-system/components/badge/design/badge-styles/content.mdoc +++ b/apps/site/src/content/design-system/components/badge/design/badge-styles/content.mdoc @@ -11,9 +11,9 @@ Badges come in 2 different styles: Default, used to highlight words, and Pill, u

Colours

-
+
{COLORS.map(color => ( - + {color} ))} @@ -21,9 +21,9 @@ Badges come in 2 different styles: Default, used to highlight words, and Pill, u

Soft

-
+
{COLORS.map(color => ( - + {color} ))} @@ -44,9 +44,9 @@ Badges come in 2 different styles: Default, used to highlight words, and Pill, u

Colours

-
+
{COLORS.map(color => ( - + 88 ))} @@ -54,9 +54,9 @@ Badges come in 2 different styles: Default, used to highlight words, and Pill, u

Soft

-
+
{COLORS.map(color => ( - + 88 ))} diff --git a/apps/site/src/content/design-system/development/guides/eslint/design/eslint-configuration/content.mdoc b/apps/site/src/content/design-system/development/guides/eslint/design/eslint-configuration/content.mdoc new file mode 100644 index 000000000..e8a8552ba --- /dev/null +++ b/apps/site/src/content/design-system/development/guides/eslint/design/eslint-configuration/content.mdoc @@ -0,0 +1,26 @@ +When setting up your project we recommend extending `@westpac/eslint-config/nextjs` as seen below: + +```html + +``` + +If you are using this in a non-Next.js project, you may need to turn off certain rules as seen below: + +```html + +``` \ No newline at end of file diff --git a/apps/site/src/content/design-system/development/guides/eslint/index.yaml b/apps/site/src/content/design-system/development/guides/eslint/index.yaml new file mode 100644 index 000000000..8b04edf97 --- /dev/null +++ b/apps/site/src/content/design-system/development/guides/eslint/index.yaml @@ -0,0 +1,8 @@ +name: ESLint +description: >- + We suggest following the Westpac Group ESLint configuration. +design: + - title: + name: ESLint Configuration + slug: eslint-configuration +accessibility: [] diff --git a/packages/ui/.eslintrc.cjs b/packages/ui/.eslintrc.cjs index 60876ad77..c0715e5e4 100644 --- a/packages/ui/.eslintrc.cjs +++ b/packages/ui/.eslintrc.cjs @@ -1,6 +1,11 @@ +const OFF = 0; + module.exports = { root: true, - extends: ['@westpac/eslint-config'], + extends: ['@westpac/eslint-config/nextjs'], + rules: { + '@next/next/no-html-link-for-pages': OFF, + }, overrides: [ { files: ['**/*.stories.tsx', '**/*.stories.ts'], @@ -18,4 +23,4 @@ module.exports = { }, }, }, -}; +}; \ No newline at end of file diff --git a/packages/ui/src/components/accordion/accordion.component.tsx b/packages/ui/src/components/accordion/accordion.component.tsx index 20c93046c..9eedb068e 100644 --- a/packages/ui/src/components/accordion/accordion.component.tsx +++ b/packages/ui/src/components/accordion/accordion.component.tsx @@ -1,10 +1,11 @@ 'use client'; -import { useAccordion } from '@react-aria/accordion'; +import { AriaAccordionProps, useAccordion } from '@react-aria/accordion'; import { filterDOMProps } from '@react-aria/utils'; import { useDOMRef } from '@react-spectrum/utils'; +import { DOMProps, DOMRef } from '@react-types/shared'; import React, { Children, cloneElement, forwardRef, isValidElement } from 'react'; -import { Item, type ItemProps, useTreeState } from 'react-stately'; +import { Item, type ItemProps, TreeProps, useTreeState } from 'react-stately'; import { styles } from './accordion.styles.js'; import { type AccordionProps } from './accordion.types.js'; @@ -12,30 +13,35 @@ import { AccordionItem as AccordionItemContent } from './components/index.js'; function Accordion( { className, rounded = true, look = 'soft', ...props }: AccordionProps, - ref: any, + ref: DOMRef, ) { // react-aria doesn't allow for now to use component children when there is multiple levels // in our case we don't need that functionality and we have to render html tags or components // therefore as a workaround we are setting hasChildItems false for all of them // https://github.com/adobe/react-spectrum/issues/3882 - const finalProps: any = { + const finalProps = { ...props, children: Children.map(props.children, child => { // equal to (if (child == null || typeof child == 'string')) if (!isValidElement(child)) return child; return cloneElement(child, { - ...(child.props as any), + ...child.props, // Adding hasChildItems false by default hasChildItems: false, }); }), }; - const state = useTreeState(finalProps); + const state = useTreeState(finalProps as TreeProps); const domRef = useDOMRef(ref); - const { accordionProps } = useAccordion(finalProps, state, domRef); + const { accordionProps } = useAccordion(finalProps as AriaAccordionProps, state, domRef); return ( -
+
{[...state.collection].map(item => ( key={item.key} item={item} state={state} look={look} /> @@ -46,7 +52,7 @@ function Accordion( } const _Accordion = forwardRef(Accordion) as unknown as { displayName: string } & (( - props: AccordionProps & { ref?: any }, + props: AccordionProps & { ref?: HTMLElement }, ) => ReturnType); _Accordion.displayName = 'Accordion'; diff --git a/packages/ui/src/components/accordion/accordion.stories.tsx b/packages/ui/src/components/accordion/accordion.stories.tsx index 96c0abccd..c80833fd9 100644 --- a/packages/ui/src/components/accordion/accordion.stories.tsx +++ b/packages/ui/src/components/accordion/accordion.stories.tsx @@ -27,7 +27,7 @@ const meta: Meta = { }; export default meta; -type Story = StoryObj; +type Story = StoryObj; /** * > Default usage example @@ -79,34 +79,29 @@ export const LegoLook: Story = { /** * > Controlled example */ -export const Controlled: Story = { - args: { - look: 'lego', - rounded: false, - }, - render: ({ ...props }) => { - const [expandedKeys, setExpandedKeys] = useState>(); - return ( - { - setExpandedKeys(keys); - }} - > - {[ - { key: 'files', title: 'Your files' }, - { key: 'shared', title: 'Shared with you' }, - { key: 'last', title: 'Last item' }, - ].map(({ key, title }) => ( - -

{title}

- -
- ))} -
- ); - }, +export const Controlled = () => { + const [expandedKeys, setExpandedKeys] = useState>(); + return ( + { + setExpandedKeys(keys); + }} + > + {[ + { key: 'files', title: 'Your files' }, + { key: 'shared', title: 'Shared with you' }, + { key: 'last', title: 'Last item' }, + ].map(({ key, title }) => ( + +

{title}

+ +
+ ))} +
+ ); }; /** diff --git a/packages/ui/src/components/accordion/accordion.types.ts b/packages/ui/src/components/accordion/accordion.types.ts index 884b7159b..a1eabac82 100644 --- a/packages/ui/src/components/accordion/accordion.types.ts +++ b/packages/ui/src/components/accordion/accordion.types.ts @@ -6,7 +6,7 @@ import { styles } from './accordion.styles.js'; import { AccordionItemProps } from './components/index.js'; type Variants = VariantProps; -export type AccordionProps = SpectrumAccordionProps & { +export type AccordionProps = SpectrumAccordionProps & { /** * as a collection */ diff --git a/packages/ui/src/components/accordion/components/accordion-item/accordion-item.component.tsx b/packages/ui/src/components/accordion/components/accordion-item/accordion-item.component.tsx index 77267572c..038cd98cc 100644 --- a/packages/ui/src/components/accordion/components/accordion-item/accordion-item.component.tsx +++ b/packages/ui/src/components/accordion/components/accordion-item/accordion-item.component.tsx @@ -1,7 +1,7 @@ import { useAccordionItem } from '@react-aria/accordion'; import { AnimatePresence, LazyMotion, m } from 'framer-motion'; import React, { useRef } from 'react'; -import { mergeProps, useFocusRing, useHover, useLocale } from 'react-aria'; +import { Key, mergeProps, useFocusRing, useHover, useLocale } from 'react-aria'; import { ArrowLeftIcon, ArrowRightIcon } from '../../../icon/index.js'; @@ -10,7 +10,7 @@ import { type AccordionItemProps } from './accordion-item.types.js'; const loadAnimations = () => import('./accordion-item.utils.js').then(res => res.default); -export function AccordionItem({ +export function AccordionItem({ className, tag: Tag = 'div', look = 'soft', @@ -20,8 +20,8 @@ export function AccordionItem({ const { state, item } = props; const { buttonProps, regionProps } = useAccordionItem(props, state, ref); const { isFocusVisible, focusProps } = useFocusRing(); - const isOpen = state.expandedKeys.has(item.key as any); - const isDisabled = state.disabledKeys.has(item.key as any); + const isOpen = state.expandedKeys.has(item.key as Key); + const isDisabled = state.disabledKeys.has(item.key as Key); const { hoverProps } = useHover({ isDisabled }); const { direction } = useLocale(); const styles = accordionItemStyles({ isOpen, isDisabled, look, isFocusVisible }); diff --git a/packages/ui/src/components/accordion/components/accordion-item/accordion-item.types.ts b/packages/ui/src/components/accordion/components/accordion-item/accordion-item.types.ts index 7ad5c28aa..d8be8ba25 100644 --- a/packages/ui/src/components/accordion/components/accordion-item/accordion-item.types.ts +++ b/packages/ui/src/components/accordion/components/accordion-item/accordion-item.types.ts @@ -6,7 +6,7 @@ import { styles } from './accordion-item.styles.js'; type Variants = VariantProps; -export type AccordionItemProps = { +export type AccordionItemProps = { /** * AccordionItem body content */ diff --git a/packages/ui/src/components/autocomplete/autocomplete.component.tsx b/packages/ui/src/components/autocomplete/autocomplete.component.tsx index b4da00ed7..02b7d906c 100644 --- a/packages/ui/src/components/autocomplete/autocomplete.component.tsx +++ b/packages/ui/src/components/autocomplete/autocomplete.component.tsx @@ -92,7 +92,14 @@ export function Autocomplete({ ((!state.isOpen && state.isFocused && searchProps.value.length > 0 && !state.selectedItem) || (state.collection.size === 0 && searchProps.value.length > 0)) ); - }, [state, searchProps, noOptionsMessage]); + }, [ + noOptionsMessage, + state.isOpen, + state.isFocused, + state.selectedItem, + state.collection.size, + searchProps.value.length, + ]); const iconSize = useMemo(() => { switch (size) { @@ -161,7 +168,7 @@ export function Autocomplete({ > diff --git a/packages/ui/src/components/autocomplete/autocomplete.stories.tsx b/packages/ui/src/components/autocomplete/autocomplete.stories.tsx index db5d52816..06b81e5fe 100644 --- a/packages/ui/src/components/autocomplete/autocomplete.stories.tsx +++ b/packages/ui/src/components/autocomplete/autocomplete.stories.tsx @@ -54,24 +54,21 @@ export const Default: Story = { /** * > Controlled usage example */ -export const Controlled: Story = { - args: {}, - render: () => { - const [selectedKey, setSelectedKey] = useState(); - const handleSelectionChange = (key: string | number) => { - setSelectedKey(key); - }; - return ( - - Red Panda - Cat - Dog - Aardvark - Kangaroo - Snake - - ); - }, +export const Controlled = () => { + const [selectedKey, setSelectedKey] = useState(); + const handleSelectionChange = (key: string | number) => { + setSelectedKey(key); + }; + return ( + + Red Panda + Cat + Dog + Aardvark + Kangaroo + Snake + + ); }; /** diff --git a/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.component.tsx b/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.component.tsx index 954759bac..ee85d60c6 100644 --- a/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.component.tsx +++ b/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.component.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { Item } from 'react-stately'; import { AutocompleteItemProps } from './autocomplete-item.types.js'; diff --git a/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.types.ts b/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.types.ts index 7b71970e0..cd33634e8 100644 --- a/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.types.ts +++ b/packages/ui/src/components/autocomplete/components/autocomplete-item/autocomplete-item.types.ts @@ -1,7 +1,7 @@ import { ReactNode } from 'react'; import { type ItemProps } from 'react-stately'; -export type AutocompleteItemProps = ItemProps & { +export type AutocompleteItemProps = ItemProps & { /** * AutocompleteItem body content */ diff --git a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/autocomplete-list-box.types.ts b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/autocomplete-list-box.types.ts index e9fcaf07b..2a172f09b 100644 --- a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/autocomplete-list-box.types.ts +++ b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/autocomplete-list-box.types.ts @@ -2,7 +2,7 @@ import { HTMLAttributes } from 'react'; import { AriaListBoxOptions } from 'react-aria'; import { ListState } from 'react-stately'; -export type AutocompleteListBoxProps = AriaListBoxOptions & { +export type AutocompleteListBoxProps = AriaListBoxOptions & { listBoxRef?: React.RefObject; - state: ListState; + state: ListState; } & HTMLAttributes; diff --git a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.component.tsx b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.component.tsx index ff85c2992..2ff2fe8c0 100644 --- a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.component.tsx +++ b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.component.tsx @@ -1,11 +1,11 @@ import { type Node } from '@react-types/shared'; import * as React from 'react'; -import { useOption } from 'react-aria'; +import { Key, useOption } from 'react-aria'; import { type ListState } from 'react-stately'; import { styles } from './autocomplete-list-box-option.styles.js'; -interface AutocompleteListBoxOptionProps { +interface AutocompleteListBoxOptionProps { item: Node; state: ListState; } @@ -18,7 +18,7 @@ export function AutocompleteListBoxOption({ item, state }: AutocompleteListBoxOp const { optionProps, isDisabled, isSelected, isFocused } = useOption( { - key: item.key as any, + key: item.key as Key, }, state, ref, diff --git a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.types.ts b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.types.ts index bebbcfa33..10c8e7708 100644 --- a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.types.ts +++ b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-option/autocomplete-list-box-option.types.ts @@ -1,7 +1,7 @@ import { type Node } from '@react-types/shared'; import { type ListState } from 'react-stately'; -export type AutocompleteListBoxOptionProps = { +export type AutocompleteListBoxOptionProps = { item: Node; state: ListState; }; diff --git a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.component.tsx b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.component.tsx index 3f3512f02..7542d26ba 100644 --- a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.component.tsx +++ b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.component.tsx @@ -8,7 +8,7 @@ import { type AutocompleteListBoxSectionProps } from './autocomplete-list-box-se /** * @private */ -export function AutocompleteListBoxSection({ section, state }: AutocompleteListBoxSectionProps) { +export function AutocompleteListBoxSection({ section, state }: AutocompleteListBoxSectionProps) { const { itemProps, headingProps, groupProps } = useListBoxSection({ heading: section.rendered, 'aria-label': section['aria-label'], diff --git a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.types.ts b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.types.ts index 7a3375a87..9f5810f1c 100644 --- a/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.types.ts +++ b/packages/ui/src/components/autocomplete/components/autocomplete-list-box/components/autocomplete-list-box-section/autocomplete-list-box-section.types.ts @@ -1,7 +1,7 @@ import { type Node } from '@react-types/shared'; import { ListState } from 'react-stately'; -export type AutocompleteListBoxSectionProps = { +export type AutocompleteListBoxSectionProps = { section: Node; state: ListState; }; diff --git a/packages/ui/src/components/badge/badge.component.tsx b/packages/ui/src/components/badge/badge.component.tsx index d287e0dbc..f8a9f1279 100644 --- a/packages/ui/src/components/badge/badge.component.tsx +++ b/packages/ui/src/components/badge/badge.component.tsx @@ -1,20 +1,19 @@ 'use client'; -import React, { forwardRef } from 'react'; +import React, { Ref, forwardRef } from 'react'; import { styles } from './badge.styles.js'; import { type BadgeProps } from './badge.types.js'; export function BaseBadge( { className, tag: Tag = 'div', color = 'hero', type = 'default', soft = false, children, ...props }: BadgeProps, - ref: any, + ref: Ref, ) { return ( - - {/* styling vertically aligns text in the middle */} -
{children}
+ + {children} ); } -export const Badge = forwardRef(BaseBadge); +export const Badge = forwardRef(BaseBadge); diff --git a/packages/ui/src/components/badge/badge.spec.tsx b/packages/ui/src/components/badge/badge.spec.tsx index f0fd4c5ae..2247ff57c 100644 --- a/packages/ui/src/components/badge/badge.spec.tsx +++ b/packages/ui/src/components/badge/badge.spec.tsx @@ -12,7 +12,7 @@ describe('Badge', () => { const style = styles({ color: 'primary', type: 'pill' }); // TODO: use some variants for test expect(style).toBe( - 'inline-block whitespace-nowrap border text-center border-primary bg-primary text-white typography-body-10 rounded-xl px-[0.4375rem] py-[0.25rem] font-medium leading-none', + 'inline-block whitespace-nowrap border text-center border-primary bg-primary text-white typography-body-10 h-4 rounded-xl px-[0.4375rem] py-[0.25rem] font-medium leading-none', ); }); }); diff --git a/packages/ui/src/components/badge/badge.stories.tsx b/packages/ui/src/components/badge/badge.stories.tsx index fceff6ace..a44677e7a 100644 --- a/packages/ui/src/components/badge/badge.stories.tsx +++ b/packages/ui/src/components/badge/badge.stories.tsx @@ -73,12 +73,14 @@ export const Colors = () => (
{COLORS.map(color => ( - {color} + + {color} + ))}
{COLORS.map(color => ( - + {color} ))} @@ -87,12 +89,14 @@ export const Colors = () => (
{INVERTED_COLORS.map(color => ( - {color} + + {color} + ))}
{INVERTED_COLORS.map(color => ( - + {color} ))} @@ -105,14 +109,14 @@ export const Soft = () => (
{COLORS.map(color => ( - + {color} ))}
{COLORS.map(color => ( - + {color} ))} @@ -126,7 +130,7 @@ export const Soft = () => ( export const Links = () => (
{COLORS.map(color => ( - + {color} 12 @@ -142,7 +146,7 @@ export const Links = () => ( export const Buttons = () => (
{INVERTED_COLORS.map(color => ( - @@ -65,21 +60,6 @@ type Story = StoryObj; */ export const DefaultState: Story = { args: { - state: { - close: () => { - return; - }, - setOpen: () => { - return; - }, - open: () => { - return; - }, - toggle: () => { - return; - }, - isOpen: false, - }, title: 'Heading', primaryLabel: 'Label', secondaryLabel: 'Label', @@ -99,21 +79,6 @@ export const DefaultState: Story = { */ export const NoFooter: Story = { args: { - state: { - close: () => { - return; - }, - setOpen: () => { - return; - }, - open: () => { - return; - }, - toggle: () => { - return; - }, - isOpen: false, - }, title: 'Heading', children: (

diff --git a/packages/ui/src/components/bottom-sheet/components/bottom-sheet-dialog/bottom-sheet-dialog.component.tsx b/packages/ui/src/components/bottom-sheet/components/bottom-sheet-dialog/bottom-sheet-dialog.component.tsx index 7f426ce5d..9a05fab86 100644 --- a/packages/ui/src/components/bottom-sheet/components/bottom-sheet-dialog/bottom-sheet-dialog.component.tsx +++ b/packages/ui/src/components/bottom-sheet/components/bottom-sheet-dialog/bottom-sheet-dialog.component.tsx @@ -1,4 +1,3 @@ -import { clsx } from 'clsx'; import React, { useRef } from 'react'; import { useDialog } from 'react-aria'; diff --git a/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.component.tsx b/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.component.tsx index 03d48a025..c9951643e 100644 --- a/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.component.tsx +++ b/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.component.tsx @@ -1,4 +1,3 @@ -import { clsx } from 'clsx'; import { PanInfo, motion, useAnimation } from 'framer-motion'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { Overlay, useModalOverlay } from 'react-aria'; @@ -52,7 +51,7 @@ export function BottomSheetModal({ state, height, width, children, portalContain return; } controls.start('hidden'); - }, [state.isOpen]); + }, [controls, state.isOpen]); const onDragEnd = useCallback( (_: unknown, info: PanInfo) => { @@ -66,7 +65,7 @@ export function BottomSheetModal({ state, height, width, children, portalContain controls.start('visible'); state.open(); }, - [controls], + [controls, state], ); if (!isBrowser || !state.isOpen) { diff --git a/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.spec.tsx b/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.spec.tsx index 91428fedc..3c6073fda 100644 --- a/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.spec.tsx +++ b/packages/ui/src/components/bottom-sheet/components/bottom-sheet-modal/bottom-sheet-modal.spec.tsx @@ -7,7 +7,7 @@ import { BottomSheetModal } from './bottom-sheet-modal.component.js'; describe('BottomSheetModal', () => { it('renders the Modal', () => { const { result } = renderHook(() => useOverlayTriggerState({})); - render(); + render({undefined}); }); it('shows the content when the state isOpen is true', async () => { diff --git a/packages/ui/src/components/breadcrumb/breadcrumb.component.tsx b/packages/ui/src/components/breadcrumb/breadcrumb.component.tsx index ef639c379..57e0c2c6b 100644 --- a/packages/ui/src/components/breadcrumb/breadcrumb.component.tsx +++ b/packages/ui/src/components/breadcrumb/breadcrumb.component.tsx @@ -4,6 +4,7 @@ import React, { Children, FunctionComponentElement, cloneElement } from 'react'; import { useBreadcrumbs } from 'react-aria'; import { type BreadcrumbProps } from './breadcrumb.types.js'; +import { BreadcrumbItemProps } from './components/breadcrumb-item/breadcrumb-item.types.js'; export function Breadcrumb({ className, children, 'aria-label': ariaLabel = 'Breadcrumb', ...props }: BreadcrumbProps) { const { navProps } = useBreadcrumbs(props); @@ -15,7 +16,9 @@ export function Breadcrumb({ className, children, 'aria-label': ariaLabel = 'Bre {Children.map( children, (child, i) => - cloneElement(child as FunctionComponentElement, { isCurrent: i === childCount - 1 }) ?? <>, + cloneElement(child as FunctionComponentElement, { + isCurrent: i === childCount - 1, + }) ?? <>, )} diff --git a/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx b/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx index 3bbb0e3c5..b22b0cec9 100644 --- a/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx +++ b/packages/ui/src/components/breadcrumb/breadcrumb.stories.tsx @@ -19,13 +19,13 @@ type Story = StoryObj; export const Default: Story = { args: { children: [ - alert('Folder 1')}> + alert('Folder 1')}> About us , - + Innovation , - + Principal investments , ], diff --git a/packages/ui/src/components/breadcrumb/components/breadcrumb-item/breadcrumb-item.component.tsx b/packages/ui/src/components/breadcrumb/components/breadcrumb-item/breadcrumb-item.component.tsx index a2642989a..ad4c87938 100644 --- a/packages/ui/src/components/breadcrumb/components/breadcrumb-item/breadcrumb-item.component.tsx +++ b/packages/ui/src/components/breadcrumb/components/breadcrumb-item/breadcrumb-item.component.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { forwardRef, useRef } from 'react'; +import React, { Ref, RefObject, forwardRef, useRef } from 'react'; import { useBreadcrumbItem } from 'react-aria'; import { ArrowRightIcon } from '../../../icon/index.js'; @@ -18,7 +18,7 @@ export function BaseBreadcrumbItem( tag: Tag = 'span', ...props }: BreadcrumbItemProps, - propRef: any, + propRef: Ref, ) { const ref = useRef(propRef); const FinalTag = (Tag === 'a' && isDisabled) || (Tag === 'a' && isCurrent) ? 'span' : Tag; @@ -30,12 +30,12 @@ export function BaseBreadcrumbItem( isCurrent, elementType: FinalTag, }, - ref, + ref as RefObject, ); return (

  • {children} @@ -49,4 +49,4 @@ export function BaseBreadcrumbItem( ); } -export const BreadcrumbItem = forwardRef(BaseBreadcrumbItem); +export const BreadcrumbItem = forwardRef(BaseBreadcrumbItem); diff --git a/packages/ui/src/components/button-dropdown/button-dropdown.component.tsx b/packages/ui/src/components/button-dropdown/button-dropdown.component.tsx index bae8be6b1..ff637e9d7 100644 --- a/packages/ui/src/components/button-dropdown/button-dropdown.component.tsx +++ b/packages/ui/src/components/button-dropdown/button-dropdown.component.tsx @@ -23,7 +23,7 @@ export function ButtonDropdown({ soft = false, block = false, }: ButtonDropdownProps) { - const ref = useRef(null); + const ref = useRef(null); const panelId = useId(); const styles = buttonDropdownStyles({ block, dropdownSize }); const state = useOverlayTriggerState({ defaultOpen: open }); @@ -35,7 +35,7 @@ export function ButtonDropdown({ (event: globalThis.KeyboardEvent) => { if (state.isOpen && event.key === 'Escape') state.close(); }, - [state.isOpen], + [state], ); useEffect(() => { diff --git a/packages/ui/src/components/button-dropdown/button-dropdown.stories.tsx b/packages/ui/src/components/button-dropdown/button-dropdown.stories.tsx index 28893f05c..94e663e2d 100644 --- a/packages/ui/src/components/button-dropdown/button-dropdown.stories.tsx +++ b/packages/ui/src/components/button-dropdown/button-dropdown.stories.tsx @@ -43,7 +43,7 @@ export const Default: Story = { export const StandardLooks = () => (
    {LOOKS.map(look => ( - +

    Example dropdown @@ -62,7 +62,7 @@ export const StandardLooks = () => ( export const SoftLooks = () => (

    {LOOKS.map(look => ( - +

    Example dropdown diff --git a/packages/ui/src/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.component.tsx b/packages/ui/src/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.component.tsx index 98d4d1856..c8faf099b 100644 --- a/packages/ui/src/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.component.tsx +++ b/packages/ui/src/components/button-dropdown/components/button-dropdown-panel/button-dropdown-panel.component.tsx @@ -26,7 +26,7 @@ export function ButtonDropdownPanel({ className, children, state, block, id, ... ) state.close(); }, - [state.isOpen], + [props.triggerRef, state], ); // React Aria does not handle click as we need when isNonModal is true so this is needed @@ -42,7 +42,7 @@ export function ButtonDropdownPanel({ className, children, state, block, id, ... ) state.close(); }, - [state.isOpen], + [props.triggerRef, state], ); useEffect(() => { @@ -52,7 +52,7 @@ export function ButtonDropdownPanel({ className, children, state, block, id, ... window.document.removeEventListener('focusin', focusHandler); window.document.removeEventListener('click', clickHandler); }; - }, []); + }, [clickHandler, focusHandler]); return (

    {hintMessage && {hintMessage}} - {errorMessage && state.validationState === 'invalid' && ( - - )} + {errorMessage && state.isInvalid && }
    {buttons.map((button, index) => ( diff --git a/packages/ui/src/components/button-group/button-group.stories.tsx b/packages/ui/src/components/button-group/button-group.stories.tsx index 7b96f3960..03c4739e3 100644 --- a/packages/ui/src/components/button-group/button-group.stories.tsx +++ b/packages/ui/src/components/button-group/button-group.stories.tsx @@ -62,6 +62,7 @@ export const Colors = () => (
    {LOOKS.map(look => ( {look}} look={look} buttons={[ @@ -90,6 +91,7 @@ export const Sizes = () => (
    {SIZES.map(size => ( {size}} size={size} buttons={[ @@ -145,6 +147,7 @@ export const Block = () => (
    {SIZES.map(size => ( {size}} size={size} diff --git a/packages/ui/src/components/button/button.component.tsx b/packages/ui/src/components/button/button.component.tsx index 4d89125f0..46ab91593 100644 --- a/packages/ui/src/components/button/button.component.tsx +++ b/packages/ui/src/components/button/button.component.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { forwardRef, useMemo } from 'react'; +import React, { Ref, forwardRef, useMemo } from 'react'; import { mergeProps, useFocusRing } from 'react-aria'; import { styles as buttonStyles } from './button.styles.js'; @@ -22,7 +22,7 @@ function BaseButton( children, ...props }: ButtonProps, - ref: any, + ref: Ref, ) { const { isFocusVisible, focusProps } = useFocusRing(); const iconSize = useMemo(() => getIconSize(size), [size]); diff --git a/packages/ui/src/components/button/button.spec.tsx b/packages/ui/src/components/button/button.spec.tsx index 91f33b810..4d561207f 100644 --- a/packages/ui/src/components/button/button.spec.tsx +++ b/packages/ui/src/components/button/button.spec.tsx @@ -17,7 +17,7 @@ describe('Button', () => { it('renders the style correctly', () => { const style = styles({ look: 'primary', size: 'medium' }); expect(style.base()).toBe( - 'items-center justify-center rounded leading-[1.5] transition-[background] disabled:pointer-events-none disabled:opacity-50 group-[.add-on-after]:rounded-l-none group-[.add-on-before]:rounded-r-none typography-body-9 px-2 py-[0.3125rem] active-theme-rams:before:h-[0.125rem] relative border border-primary bg-primary text-white hover:bg-primary-70 active:bg-primary-50 active-theme-rams:border-b-pop active-theme-rams:before:absolute active-theme-rams:before:bottom-0 active-theme-rams:before:block active-theme-rams:before:w-full active-theme-rams:before:bg-pop', + 'items-center justify-center rounded leading-[1.5] transition-[background] disabled:pointer-events-none disabled:opacity-50 group-first/add-on-before:rounded-r-none group-last/add-on-after:rounded-l-none typography-body-9 px-2 py-[0.3125rem] active-theme-rams:before:h-[0.125rem] relative border border-primary bg-primary text-white hover:bg-primary-70 active:bg-primary-50 active-theme-rams:border-b-pop active-theme-rams:before:absolute active-theme-rams:before:bottom-0 active-theme-rams:before:block active-theme-rams:before:w-full active-theme-rams:before:bg-pop', ); }); diff --git a/packages/ui/src/components/button/button.stories.tsx b/packages/ui/src/components/button/button.stories.tsx index e59e2e30d..7b4457acf 100644 --- a/packages/ui/src/components/button/button.stories.tsx +++ b/packages/ui/src/components/button/button.stories.tsx @@ -35,13 +35,15 @@ export const Colors = () => (

    Default

    {LOOKS.map(look => ( - + ))}

    Soft

    {SOFT_LOOKS.map(look => ( - ))} @@ -59,14 +61,14 @@ export const Sizes = () => (

    {size}

    {LOOKS.map(look => ( - ))}
    {SOFT_LOOKS.map(look => ( - ))} @@ -86,7 +88,7 @@ export const Block = () => (

    {size}

    {SOFT_LOOKS.map(look => ( - ))} @@ -106,14 +108,14 @@ export const Icons = () => (

    Colors

    {LOOKS.map(look => ( - ))}
    {SOFT_LOOKS.map(look => ( - ))} @@ -121,14 +123,14 @@ export const Icons = () => (

    Sizes

    {SIZES.map(size => ( - ))}
    {SIZES.map(size => ( - ))} @@ -149,14 +151,14 @@ export const Icons = () => (

    Colors

    {LOOKS.map(look => ( - ))}
    {SOFT_LOOKS.map(look => ( - ))} @@ -164,14 +166,14 @@ export const Icons = () => (

    Sizes

    {SIZES.map(size => ( - ))}
    {SIZES.map(size => ( - ))} @@ -191,23 +193,23 @@ export const Icons = () => (

    Colors

    {LOOKS.map(look => ( -
    {SOFT_LOOKS.map(look => ( -

    Sizes

    {SIZES.map(size => ( -
    {SIZES.map(size => ( -

    Block

    diff --git a/packages/ui/src/components/button/button.styles.ts b/packages/ui/src/components/button/button.styles.ts index 155f5ad85..089bcb543 100644 --- a/packages/ui/src/components/button/button.styles.ts +++ b/packages/ui/src/components/button/button.styles.ts @@ -6,7 +6,7 @@ import { tv } from 'tailwind-variants'; export const styles = tv( { slots: { - base: 'items-center justify-center rounded leading-[1.5] transition-[background] disabled:pointer-events-none disabled:opacity-50 group-[.add-on-after]:rounded-l-none group-[.add-on-before]:rounded-r-none', + base: 'items-center justify-center rounded leading-[1.5] transition-[background] disabled:pointer-events-none disabled:opacity-50 group-first/add-on-before:rounded-r-none group-last/add-on-after:rounded-l-none', iconBefore: '', iconAfter: '', dropdown: 'ml-[0.4em]', diff --git a/packages/ui/src/components/checkbox-group/checkbox-group.component.tsx b/packages/ui/src/components/checkbox-group/checkbox-group.component.tsx index 6985e3f48..92be5db18 100644 --- a/packages/ui/src/components/checkbox-group/checkbox-group.component.tsx +++ b/packages/ui/src/components/checkbox-group/checkbox-group.component.tsx @@ -91,7 +91,7 @@ export function CheckboxGroup({ const { groupProps, labelProps, errorMessageProps, descriptionProps } = useCheckboxGroup({ ...props, label }, state); const { isFocusVisible, focusProps } = useFocusRing(); const [hiddenOptions, setHiddenOptions] = useState(showAmount > 0); - const firstNewCheckboxRef = useRef(null); + const firstNewCheckboxRef = useRef(null); const revealAmount = checkboxes && checkboxes.length - showAmount; const styles = checkboxStyles({ orientation, isFocusVisible }); const panelId = useId(); @@ -113,9 +113,7 @@ export function CheckboxGroup({
    {hintMessage && {hintMessage}} - {errorMessage && state.validationState === 'invalid' && ( - - )} + {errorMessage && state.isInvalid && }
    {childrenToRender} diff --git a/packages/ui/src/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.tsx b/packages/ui/src/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.tsx index 3ebbca8d7..4d25f66e0 100644 --- a/packages/ui/src/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.tsx +++ b/packages/ui/src/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { forwardRef, useContext, useRef } from 'react'; +import React, { Ref, forwardRef, useContext, useRef } from 'react'; import { VisuallyHidden, useCheckboxGroupItem, useFocusRing } from 'react-aria'; import { Icon } from '../../../icon/icon.component.js'; @@ -31,7 +31,10 @@ function CheckIcon({ copyrightYear = '2024', size, ...props }: IconProps) { ); } -function BaseCheckbox({ className, hint, label, value, ...props }: CheckboxGroupCheckboxProps, ref: any) { +function BaseCheckbox( + { className, hint, label, value, ...props }: CheckboxGroupCheckboxProps, + ref: Ref, +) { const { state, size, orientation } = useContext(CheckboxGroupContext); const localRef = useRef(null); const { inputProps, isDisabled, isSelected } = useCheckboxGroupItem( diff --git a/packages/ui/src/components/collapsible/collapsible.component.tsx b/packages/ui/src/components/collapsible/collapsible.component.tsx index 4f52c3d90..a0dc01718 100644 --- a/packages/ui/src/components/collapsible/collapsible.component.tsx +++ b/packages/ui/src/components/collapsible/collapsible.component.tsx @@ -30,7 +30,7 @@ export function Collapsible({ const handleClick = useCallback(() => { onClick(); setContentOpen(contentOpen => !contentOpen); - }, [contentOpen]); + }, [onClick]); const styles = collapsibleStyles({ open: contentOpen }); diff --git a/packages/ui/src/components/compacta/compacta.component.tsx b/packages/ui/src/components/compacta/compacta.component.tsx index ec8ee8a63..6415f7639 100644 --- a/packages/ui/src/components/compacta/compacta.component.tsx +++ b/packages/ui/src/components/compacta/compacta.component.tsx @@ -146,7 +146,7 @@ export function Compacta({ look="link" size="large" onClick={() => handleToggle(item.id, index)} - ref={(el: HTMLElement) => { + ref={(el: HTMLButtonElement & HTMLAnchorElement & HTMLSpanElement & HTMLDivElement) => { toggleRefs.current[index] = el; }} aria-labelledby={`gel-compacta-title-${item.id}`} diff --git a/packages/ui/src/components/date-picker/date-picker.component.tsx b/packages/ui/src/components/date-picker/date-picker.component.tsx index 07cdad5cf..6e851e3e3 100644 --- a/packages/ui/src/components/date-picker/date-picker.component.tsx +++ b/packages/ui/src/components/date-picker/date-picker.component.tsx @@ -46,7 +46,7 @@ export function DatePicker({ const dateAdapter = useMemo( () => ({ - parse(value = '', createDate: any) { + parse(value = '', createDate: (year: string, month: string, day: string) => Date) { const matches = value.match(/^(\d{1,2})-(\d{1,2})-(\d{4})$/); if (matches) { return createDate(matches[3], matches[2], matches[1]); @@ -103,7 +103,7 @@ export function DatePicker({ ref.current.isDateDisabled = (date: Date) => { return isDateDisabled(date, disableWeekends, disableDaysOfWeek, disableDates); }; - }, [ref, initialized]); + }, [ref, initialized, dateAdapter, localization, value, id, name, disableWeekends, disableDaysOfWeek, disableDates]); useLayoutEffect(() => { if (!ref.current) { diff --git a/packages/ui/src/components/date-picker/date-picker.stories.tsx b/packages/ui/src/components/date-picker/date-picker.stories.tsx index e766ab805..9cec17f18 100644 --- a/packages/ui/src/components/date-picker/date-picker.stories.tsx +++ b/packages/ui/src/components/date-picker/date-picker.stories.tsx @@ -52,32 +52,29 @@ export const Sizes: Story = { /** * > Controlled value */ -export const Controlled: Story = { - args: {}, - render: () => { - const [value, setValue] = useState('2023-08-01'); - return ( - { - console.log(value.target.value); - setValue(value.target.value); - }} - onOpen={() => { - console.log('onOpen'); - }} - onClose={() => { - console.log('onClose'); - }} - onBlur={() => { - console.log('onBlur'); - }} - onFocus={() => { - console.log('onFocus'); - }} - value={value} - /> - ); - }, +export const Controlled = () => { + const [value, setValue] = useState('2023-08-01'); + return ( + { + console.log(value.target.value); + setValue(value.target.value); + }} + onOpen={() => { + console.log('onOpen'); + }} + onClose={() => { + console.log('onClose'); + }} + onBlur={() => { + console.log('onBlur'); + }} + onFocus={() => { + console.log('onFocus'); + }} + value={value} + /> + ); }; /** @@ -104,37 +101,34 @@ export const DisableSpecificDates: Story = { /** * > Form field example */ -export const FormField: Story = { - args: {}, - render: () => { - const [value, setValue] = useState('2023-08-01'); +export const FormField = () => { + const [value, setValue] = useState('2023-08-01'); - return ( - - { - console.log(value.target.value); - setValue(value.target.value); - }} - onOpen={() => { - console.log('onOpen'); - }} - onClose={() => { - console.log('onClose'); - }} - onBlur={() => { - console.log('onBlur'); - }} - onFocus={() => { - console.log('onFocus'); - }} - value={value} - /> - - ); - }, + return ( + + { + console.log(value.target.value); + setValue(value.target.value); + }} + onOpen={() => { + console.log('onOpen'); + }} + onClose={() => { + console.log('onClose'); + }} + onBlur={() => { + console.log('onBlur'); + }} + onFocus={() => { + console.log('onFocus'); + }} + value={value} + /> + + ); }; diff --git a/packages/ui/src/components/date-picker/date-picker.types.ts b/packages/ui/src/components/date-picker/date-picker.types.ts index 8838b3139..a9aafddc9 100644 --- a/packages/ui/src/components/date-picker/date-picker.types.ts +++ b/packages/ui/src/components/date-picker/date-picker.types.ts @@ -4,10 +4,10 @@ import { VariantProps } from 'tailwind-variants'; import { styles } from './date-picker.styles.js'; export type DuetDatePickerElement = Element & { - dateAdapter: any; - identifier: any; + dateAdapter: object; + identifier?: string; isDateDisabled: (date: Date) => boolean; - localization: any; + localization: object; max?: string; min?: string; name?: string; @@ -48,23 +48,33 @@ export type DatePickerProps = { /* * onBlur */ - onBlur?: (...args: any[]) => unknown; + // NOTE: duet library uses custom events build with another library causing these to be hard to type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onBlur?: (...args: any[]) => void; /* * onChange */ - onChange?: (...args: any[]) => unknown; + // NOTE: duet library uses custom events build with another library causing these to be hard to type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onChange?: (...args: any[]) => void; /* * onClose */ - onClose?: (...args: any[]) => unknown; + // NOTE: duet library uses custom events build with another library causing these to be hard to type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onClose?: (...args: any[]) => void; /* * onFocus */ - onFocus?: (...args: any[]) => unknown; + // NOTE: duet library uses custom events build with another library causing these to be hard to type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onFocus?: (...args: any[]) => void; /* * onOpen */ - onOpen?: (...args: any[]) => unknown; + // NOTE: duet library uses custom events build with another library causing these to be hard to type + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onOpen?: (...args: any[]) => void; /* * placeholder */ diff --git a/packages/ui/src/components/date-picker/date-picker.utils.ts b/packages/ui/src/components/date-picker/date-picker.utils.ts index 362604f0e..10cbfd890 100644 --- a/packages/ui/src/components/date-picker/date-picker.utils.ts +++ b/packages/ui/src/components/date-picker/date-picker.utils.ts @@ -1,4 +1,4 @@ -import { EventHandler, RefObject, useEffect } from 'react'; +import { RefObject, useEffect } from 'react'; import { DuetDatePickerElement } from './date-picker.types.js'; @@ -34,7 +34,7 @@ export function formatDate(date: Date, format: string) { export function useListener( ref: RefObject | null, eventName: string, - handler?: EventHandler, + handler?: EventListenerOrEventListenerObject, ) { useEffect(() => { if (ref?.current && handler) { @@ -42,7 +42,7 @@ export function useListener( element.addEventListener(eventName, handler); return () => element.removeEventListener(eventName, handler); } - }, [eventName, handler]); + }, [eventName, handler, ref]); } export function createDate(year: string, month: string, day: string) { diff --git a/packages/ui/src/components/error-message/error-message.component.tsx b/packages/ui/src/components/error-message/error-message.component.tsx index 6b9102c5f..2710789f4 100644 --- a/packages/ui/src/components/error-message/error-message.component.tsx +++ b/packages/ui/src/components/error-message/error-message.component.tsx @@ -11,8 +11,8 @@ export function ErrorMessage({ className, tag: Tag = 'div', icon: Icon, message, return Array.isArray(message) ? (
      - {message.map(msg => ( -
    • + {message.map((msg, index) => ( +
    • {msg}
    • diff --git a/packages/ui/src/components/error-message/error-message.types.ts b/packages/ui/src/components/error-message/error-message.types.ts index d41accadf..a6368a8bc 100644 --- a/packages/ui/src/components/error-message/error-message.types.ts +++ b/packages/ui/src/components/error-message/error-message.types.ts @@ -1,4 +1,4 @@ -import { HTMLAttributes, ReactNode } from 'react'; +import { HTMLAttributes } from 'react'; import { AriaFieldProps } from 'react-aria'; export type ErrorMessageProps = { diff --git a/packages/ui/src/components/field/field.component.tsx b/packages/ui/src/components/field/field.component.tsx index 55b748f6b..438503a3d 100644 --- a/packages/ui/src/components/field/field.component.tsx +++ b/packages/ui/src/components/field/field.component.tsx @@ -33,7 +33,7 @@ export function Field({ return cloneElement(child, fieldProps); } }); - }, [children]); + }, [children, fieldProps]); return ( diff --git a/packages/ui/src/components/flexi-cell/flexi-cell.component.tsx b/packages/ui/src/components/flexi-cell/flexi-cell.component.tsx index dca0acbde..53f197def 100644 --- a/packages/ui/src/components/flexi-cell/flexi-cell.component.tsx +++ b/packages/ui/src/components/flexi-cell/flexi-cell.component.tsx @@ -1,6 +1,6 @@ 'use client'; -import React, { forwardRef } from 'react'; +import React, { Ref, forwardRef } from 'react'; import { mergeProps, useFocusRing } from 'react-aria'; import { ArrowRightIcon } from '../icon/index.js'; @@ -26,7 +26,7 @@ function FlexiCellBase( tabIndex, ...props }: FlexiCellProps, - ref: any, + ref: Ref, ) { const { isFocusVisible, focusProps } = useFocusRing(); @@ -41,7 +41,7 @@ function FlexiCellBase( return ( {MOCK_VERTICAL_PROMOS.map(({ title, subtitle }) => ( Corner flag} > + {/* Disabled as we can't import Image */} + {/* eslint-disable-next-line @next/next/no-img-element */} ; * > Default usage example */ export const DefaultStory: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( diff --git a/packages/ui/src/components/form/form.stories.tsx b/packages/ui/src/components/form/form.stories.tsx index fa5a8dfda..fe0c2210e 100644 --- a/packages/ui/src/components/form/form.stories.tsx +++ b/packages/ui/src/components/form/form.stories.tsx @@ -170,7 +170,7 @@ export const AllSpacings: Story = { return (
      {(['medium', 'large'] as const).map(size => ( -
      +

      Form with Spacing:{size}. Sets spacing between label, hint and form groups.

      This is a hint diff --git a/packages/ui/src/components/header/header.component.tsx b/packages/ui/src/components/header/header.component.tsx index fb4fb6c54..bd8c43fb4 100644 --- a/packages/ui/src/components/header/header.component.tsx +++ b/packages/ui/src/components/header/header.component.tsx @@ -83,7 +83,7 @@ export function Header({ return () => { window.removeEventListener('scroll', handleScroll); }; - }, []); + }, [fixed, handleScroll]); const logoAlignment = logoCenter ? 'center' : 'left'; diff --git a/packages/ui/src/components/header/header.stories.tsx b/packages/ui/src/components/header/header.stories.tsx index 237c36db7..b4a99dce7 100644 --- a/packages/ui/src/components/header/header.stories.tsx +++ b/packages/ui/src/components/header/header.stories.tsx @@ -26,6 +26,8 @@ type Story = StoryObj; * > Default usage example */ export const DefaultStory: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -40,6 +42,8 @@ export const DefaultStory: Story = { * > Example with a button on the right */ export const RightButton: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -58,6 +62,8 @@ export const RightButton: Story = { * > Example of logo centering when XSL */ export const CenterAtXS: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -72,6 +78,8 @@ export const CenterAtXS: Story = { * > Example of logo with onClick */ export const LogoOnClick: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -87,6 +95,8 @@ export const LogoOnClick: Story = { * > Example of header with skiplink */ export const LogoWithSkipLink: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -101,6 +111,8 @@ export const LogoWithSkipLink: Story = { * > Example fixed header. Does not show correctly in Docs view as it will show how it looks when scrolled, check specifc story for non-scrolled view */ export const Fixed: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -115,6 +127,8 @@ export const Fixed: Story = { * > Example of header with arrow button */ export const WithArrow: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -129,6 +143,8 @@ export const WithArrow: Story = { * > Example of header with arrow button with onClick */ export const WithArrowOnClick: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -149,6 +165,8 @@ export const WithArrowOnClick: Story = { * > Example of header with hamburger (only visible below xsl) */ export const WithHamburger: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( @@ -163,6 +181,8 @@ export const WithHamburger: Story = { * > Example of header with hamburger (only visible below xsl) with onClick */ export const WithHamburgerOnClick: Story = { + // for underscored property + // eslint-disable-next-line @typescript-eslint/no-unused-vars render: ({ brand: _, ...rest }, { globals: { theme } }) => { const brand = theme ? theme.toLowerCase() : 'wbc'; return ( diff --git a/packages/ui/src/components/heading/heading.spec.tsx b/packages/ui/src/components/heading/heading.spec.tsx index 3ebe6a6ad..98496bc9e 100644 --- a/packages/ui/src/components/heading/heading.spec.tsx +++ b/packages/ui/src/components/heading/heading.spec.tsx @@ -1,7 +1,6 @@ import { render } from '@testing-library/react'; import { Heading } from './heading.component.js'; -import { styles } from './heading.styles.js'; import { HeadingProps } from './heading.types.js'; describe('Heading', () => { @@ -12,9 +11,9 @@ describe('Heading', () => { it('should have the correct size', () => { const sizes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - sizes.forEach((size: any) => { + sizes.forEach(size => { const { getByTestId } = render( - + Heading , ); @@ -24,7 +23,7 @@ describe('Heading', () => { it('should have the heading tag', () => { const headingLevels = [1, 2, 3, 4, 5, 6]; - headingLevels.forEach((level: any) => { + headingLevels.forEach(level => { const { getByRole } = render( Heading diff --git a/packages/ui/src/components/heading/heading.stories.tsx b/packages/ui/src/components/heading/heading.stories.tsx index 5e74b2a53..062d8eb70 100644 --- a/packages/ui/src/components/heading/heading.stories.tsx +++ b/packages/ui/src/components/heading/heading.stories.tsx @@ -1,4 +1,4 @@ -import { type Meta, StoryFn, type StoryObj } from '@storybook/react'; +import { type Meta, StoryFn } from '@storybook/react'; import { Heading } from './heading.component.js'; import { HeadingProps } from './heading.types.js'; @@ -14,7 +14,6 @@ const meta: Meta = { }; export default meta; -type Story = StoryObj; const sizes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; @@ -22,15 +21,19 @@ const sizes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; * > Default usage example */ export const Default = () => { - return sizes.map((size: any) => Heading size: {size}); + return sizes.map(size => ( + + Heading size: {size} + + )); }; /** * > With tag prop */ export const WithTag = () => { - return sizes.map((size: any) => ( - 1 ? 'h1' : 'h2'} size={size}> + return sizes.map(size => ( + 1 ? 'h1' : 'h2'} size={size as HeadingProps['size']}> Heading tag:{size > 1 ? ' h1' : ' h2'} size: {size} )); @@ -40,8 +43,8 @@ export const WithTag = () => { * > Brand usage example */ export const Brand = () => { - return sizes.map((size: any) => ( - + return sizes.map(size => ( + Heading size: {size} )); @@ -51,8 +54,8 @@ export const Brand = () => { * > With tag and brand prop */ export const WithTagAndBrand = () => { - return sizes.map((size: any) => ( - 1 ? 'h1' : 'h2'} size={size} brandHeading> + return sizes.map(size => ( + 1 ? 'h1' : 'h2'} size={size as HeadingProps['size']} brandHeading> Heading tag:{size > 1 ? ' h1' : ' h2'} size: {size} )); @@ -62,8 +65,8 @@ export const WithTagAndBrand = () => { * > Uppercase usage example */ export const Uppercase = () => { - return sizes.map((size: any) => ( - + return sizes.map(size => ( + Heading size: {size} )); diff --git a/packages/ui/src/components/icon/icon.stories.tsx b/packages/ui/src/components/icon/icon.stories.tsx index faef6fa26..d17cae7ed 100644 --- a/packages/ui/src/components/icon/icon.stories.tsx +++ b/packages/ui/src/components/icon/icon.stories.tsx @@ -9,7 +9,7 @@ import * as AllIcons from './index.js'; const AllIconsExample = (props: AllIcons.IconProps) => { const [search, setSearch] = useState(''); const filteredIcons = useMemo(() => { - return Object.entries(AllIcons).reduce((acc: { Icon: any; key: string }[], [iconName, Icon]) => { + return Object.entries(AllIcons).reduce((acc: { Icon: typeof Icon; key: string }[], [iconName, Icon]) => { if (iconName.toUpperCase().indexOf(search.toUpperCase()) === -1) { return acc; } @@ -21,17 +21,14 @@ const AllIconsExample = (props: AllIcons.IconProps) => { setSearch(value); }, []); - const handleOnClick = useCallback( - async (key: string) => { - try { - await navigator.clipboard.writeText(`<${key} />`); - console.log('Content copied to clipboard'); - } catch (err) { - console.error('Failed to copy: ', err); - } - }, - [props.className], - ); + const handleOnClick = useCallback(async (key: string) => { + try { + await navigator.clipboard.writeText(`<${key} />`); + console.log('Content copied to clipboard'); + } catch (err) { + console.error('Failed to copy: ', err); + } + }, []); return (
      diff --git a/packages/ui/src/components/input-group/components/input-group-add-ons/components/input-group-add-on-default-add-on/input-group-add-on-default-add-on.component.tsx b/packages/ui/src/components/input-group/components/input-group-add-ons/components/input-group-add-on-default-add-on/input-group-add-on-default-add-on.component.tsx index e85f4a40a..b9dba30b9 100644 --- a/packages/ui/src/components/input-group/components/input-group-add-ons/components/input-group-add-on-default-add-on/input-group-add-on-default-add-on.component.tsx +++ b/packages/ui/src/components/input-group/components/input-group-add-ons/components/input-group-add-on-default-add-on/input-group-add-on-default-add-on.component.tsx @@ -6,12 +6,7 @@ import { type InputGroupAddOnDefaultAddOnProps } from './input-group-add-on-defa /** * @private */ -export const InputGroupAddOnDefaultAddOn = ({ - position, - className, - children, - ...props -}: InputGroupAddOnDefaultAddOnProps) => { +export const InputGroupAddOnDefaultAddOn = ({ className, children, ...props }: InputGroupAddOnDefaultAddOnProps) => { return (
      {children} diff --git a/packages/ui/src/components/input-group/components/input-group-add-ons/input-group-add-ons.styles.ts b/packages/ui/src/components/input-group/components/input-group-add-ons/input-group-add-ons.styles.ts index 679433516..761285c16 100644 --- a/packages/ui/src/components/input-group/components/input-group-add-ons/input-group-add-ons.styles.ts +++ b/packages/ui/src/components/input-group/components/input-group-add-ons/input-group-add-ons.styles.ts @@ -9,8 +9,8 @@ export const styles = tv( false: '', }, position: { - before: 'add-on-before group', - after: 'add-on-after group', + before: 'group/add-on-before', + after: ' group/add-on-after', }, }, compoundVariants: [ diff --git a/packages/ui/src/components/input-group/input-group.component.tsx b/packages/ui/src/components/input-group/input-group.component.tsx index f216ddb68..9a8e75828 100644 --- a/packages/ui/src/components/input-group/input-group.component.tsx +++ b/packages/ui/src/components/input-group/input-group.component.tsx @@ -1,6 +1,15 @@ 'use client'; -import React, { Children, ReactNode, cloneElement, isValidElement, useCallback, useId, useMemo } from 'react'; +import React, { + Attributes, + Children, + ReactNode, + cloneElement, + isValidElement, + useCallback, + useId, + useMemo, +} from 'react'; import { ErrorMessage, Hint, Label } from '../index.js'; @@ -37,7 +46,7 @@ export function InputGroup({ ...(supportingText ? [`${id}-supporting-text`] : []), ]; return arr.join(' '); - }, [id, hint, errorMessage, supportingText]); + }, [errorMessage, id, hint, before, after, supportingText]); const { element: beforeElement, @@ -81,10 +90,10 @@ export function InputGroup({ id, 'aria-describedby': ariaDescribedByValue, ...(width !== 'full' ? { width: width } : {}), - } as any); + } as Partial & Attributes); } }); - }, [children, ariaDescribedByValue]); + }, [children, size, id, ariaDescribedByValue, width]); const isFieldset = useMemo(() => Tag === 'fieldset', [Tag]); diff --git a/packages/ui/src/components/input-group/input-group.scenarios.stories.tsx b/packages/ui/src/components/input-group/input-group.scenarios.stories.tsx index 23489ee7b..f7d20c2d4 100644 --- a/packages/ui/src/components/input-group/input-group.scenarios.stories.tsx +++ b/packages/ui/src/components/input-group/input-group.scenarios.stories.tsx @@ -1,4 +1,4 @@ -import { type Meta, StoryFn, type StoryObj } from '@storybook/react'; +import { type Meta, StoryFn } from '@storybook/react'; import { useCallback, useMemo, useState } from 'react'; import { ClearIcon, RefreshIcon, SearchIcon, VisibilityIcon, VisibilityOffIcon } from '../icon/index.js'; @@ -14,161 +14,144 @@ const meta: Meta = { }; export default meta; -type Story = StoryObj; /** * > Number of dependents */ -export const NumberStepper: Story = { - args: {}, - render: () => { - const [numberOfDependents, setNumberOfDependents] = useState(0); - const minusButton = useCallback(() => setNumberOfDependents(state => --state), []); - const plusButton = useCallback(() => setNumberOfDependents(state => ++state), []); - - return ( - -} - after={} - > - - - ); - }, +export const NumberStepper = () => { + const [numberOfDependents, setNumberOfDependents] = useState(0); + const minusButton = useCallback(() => setNumberOfDependents(state => --state), []); + const plusButton = useCallback(() => setNumberOfDependents(state => ++state), []); + + return ( + -} + after={} + > + + + ); }; /** * > Masked characters in field */ -export const MaskedCharacters: Story = { - args: {}, - render: () => { - const [typeInput, setTypeInput] = useState<'password' | 'text'>('password'); - const toggleType = useCallback(() => setTypeInput(state => (state === 'password' ? 'text' : 'password')), []); - - return ( - - ), - }} - > - - - ); - }, +export const MaskedCharacters = () => { + const [typeInput, setTypeInput] = useState<'password' | 'text'>('password'); + const toggleType = useCallback(() => setTypeInput(state => (state === 'password' ? 'text' : 'password')), []); + + return ( + + ), + }} + > + + + ); }; /** * > Search with left icon and clear button */ -export const SearchWithLeftIconAndClearButton: Story = { - args: {}, - render: () => { - const [inputValue, setInputValue] = useState(''); - const clearInput = useCallback(() => setInputValue(''), []); - - return ( - , - }} - > - setInputValue(value)} value={inputValue} /> - - ); - }, +export const SearchWithLeftIconAndClearButton = () => { + const [inputValue, setInputValue] = useState(''); + const clearInput = useCallback(() => setInputValue(''), []); + + return ( + , + }} + > + setInputValue(value)} value={inputValue} /> + + ); }; /** * > Inline field validation flow */ -export const InlineFieldValidationFlow: Story = { - args: {}, - render: () => { - const [inputValue, setInputValue] = useState(''); - const [validating, setValidating] = useState(false); - const [error, setError] = useState(); - const validate = useCallback(() => { - setValidating(true); - setError(undefined); - setTimeout(() => { - if (inputValue !== '647453') { - setError('Routing number not found'); - } - setValidating(false); - }, 1500); - }, [inputValue]); - - return ( - Check} - errorMessage={error} - > - setInputValue(value)} value={inputValue} /> - - ); - }, +export const InlineFieldValidationFlow = () => { + const [inputValue, setInputValue] = useState(''); + const [validating, setValidating] = useState(false); + const [error, setError] = useState(); + const validate = useCallback(() => { + setValidating(true); + setError(undefined); + setTimeout(() => { + if (inputValue !== '647453') { + setError('Routing number not found'); + } + setValidating(false); + }, 1500); + }, [inputValue]); + + return ( + Check} + errorMessage={error} + > + setInputValue(value)} value={inputValue} /> + + ); }; + /** * > Search Currency and frequency */ -export const CurrencyAndFrequency: Story = { - args: {}, - render: () => { - const [inputValue, setInputValue] = useState(''); - - return ( - - - - - - - } - > - setInputValue(value)} value={inputValue} /> - - ); - }, +export const CurrencyAndFrequency = () => { + const [inputValue, setInputValue] = useState(''); + + return ( + + + + + + + } + > + setInputValue(value)} value={inputValue} /> + + ); }; + /** * > Search Textarea with character count */ const MAX_LENGTH = 250; -export const TextareaWithCharacterCount: Story = { - args: {}, - render: () => { - const [inputValue, setInputValue] = useState(''); - const counterText = useMemo(() => { - const lengthLeft = MAX_LENGTH - inputValue.length; - return `${lengthLeft} remaining`; - }, [inputValue]); - - return ( - -