From ec311515b63c3189811f78f7607e4a6db91f086c Mon Sep 17 00:00:00 2001 From: Adam Kudrna Date: Thu, 19 Oct 2023 19:47:08 +0200 Subject: [PATCH] Feat(web-react): Use the new Placement dictionary in `Dropdown` #DS-923 --- .../src/components/Dropdown/Dropdown.tsx | 4 +-- .../src/components/Dropdown/README.md | 4 +-- .../__tests__/useDropdownStyleProps.test.ts | 35 +++++++++++-------- .../Dropdown/stories/Dropdown.stories.tsx | 9 +++-- .../Dropdown/useDropdownStyleProps.ts | 22 ++++-------- packages/web-react/src/types/dropdown.ts | 14 ++------ 6 files changed, 40 insertions(+), 48 deletions(-) diff --git a/packages/web-react/src/components/Dropdown/Dropdown.tsx b/packages/web-react/src/components/Dropdown/Dropdown.tsx index 7ffc11ecf1..574a195152 100644 --- a/packages/web-react/src/components/Dropdown/Dropdown.tsx +++ b/packages/web-react/src/components/Dropdown/Dropdown.tsx @@ -2,14 +2,14 @@ import React, { createElement, useRef, LegacyRef } from 'react'; import classNames from 'classnames'; import DropdownWrapper from './DropdownWrapper'; import { useStyleProps } from '../../hooks'; -import { DropdownPlacements, SpiritDropdownProps } from '../../types'; +import { SpiritDropdownProps } from '../../types'; import { useDropdown } from './useDropdown'; import { useDropdownStyleProps } from './useDropdownStyleProps'; import { useDropdownAriaProps } from './useDropdownAriaProps'; const defaultProps = { - placement: DropdownPlacements.BOTTOM_LEFT, enableAutoClose: true, + placement: 'bottom-left', }; const Dropdown = (props: SpiritDropdownProps) => { diff --git a/packages/web-react/src/components/Dropdown/README.md b/packages/web-react/src/components/Dropdown/README.md index 4e6c593100..9463f667b7 100644 --- a/packages/web-react/src/components/Dropdown/README.md +++ b/packages/web-react/src/components/Dropdown/README.md @@ -22,7 +22,7 @@ import { Dropdown } from '@lmc-eu/spirit-web-react/components'; | `fullWidthMode` | [`DropdownFullwidthMode`][dropdownfullwidthmode] | `off` | ✕ | Full-width mode | | `id` | `string` | `` | ✕ | Component id | | `onAutoClose` . | `(event: Event) => void` | — | ✕ | Callback on close on click outside of Dropdown | -| `placement` | [`DropdownPlacement`][dropdownplacement] | `bottom-left` | ✕ | Alignment of the component | +| `placement` | [Placement dictionary][dictionary-placement] | `bottom-left` | ✕ | Alignment of the component | | `renderTrigger` | `(render: DropdownRenderProps) => ReactNode` | — | ✕ | Properties for trigger render | | `UNSAFE_className` | `string` | — | ✕ | Wrapper custom classname | | `UNSAFE_style` | `CSSProperties` | — | ✕ | Wrapper custom style | @@ -40,6 +40,6 @@ import { Dropdown } from '@lmc-eu/spirit-web-react/components'; | `trigger.ref` | `LegacyRef` | Trigger reference | [dropdown]: https://github.com/lmc-eu/spirit-design-system/tree/main/packages/web/src/scss/components/Dropdown -[dropdownplacement]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/src/types/dropdown.ts#L4 [dropdownbreakpoint]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/src/types/dropdown.ts#L11 [dropdownfullwidthmode]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/src/types/dropdown.ts#L19 +[dictionary-placement]: https://github.com/lmc-eu/spirit-design-system/tree/main/docs/DICTIONARIES.md#placement diff --git a/packages/web-react/src/components/Dropdown/__tests__/useDropdownStyleProps.test.ts b/packages/web-react/src/components/Dropdown/__tests__/useDropdownStyleProps.test.ts index 55b4ef23de..1caf6dd205 100644 --- a/packages/web-react/src/components/Dropdown/__tests__/useDropdownStyleProps.test.ts +++ b/packages/web-react/src/components/Dropdown/__tests__/useDropdownStyleProps.test.ts @@ -1,35 +1,42 @@ import { renderHook } from '@testing-library/react-hooks'; -import { DropdownPlacements } from '../../../types'; +import { PlacementDictionaryType } from '../../../types/shared/dictionaries'; import { useDropdownStyleProps, UseDropdownStyleProps } from '../useDropdownStyleProps'; describe('useDropdownStyleProps', () => { it('should return defaults', () => { - const props = { isOpen: true, placement: 'bottom-left' } as UseDropdownStyleProps; - const { result } = renderHook(() => useDropdownStyleProps(props)); + const { result } = renderHook(() => useDropdownStyleProps()); - expect(result.current.classProps.contentClassName).toBe('Dropdown is-open Dropdown--bottom Dropdown--left'); + expect(result.current.classProps.contentClassName).toBe('Dropdown Dropdown--bottomLeft'); expect(result.current.classProps.wrapperClassName).toBe('DropdownWrapper'); + }); + + it('should render as open', () => { + const props = { + isOpen: true, + } as UseDropdownStyleProps; + const { result } = renderHook(() => useDropdownStyleProps(props)); + + expect(result.current.classProps.contentClassName).toBe('Dropdown Dropdown--bottomLeft is-open'); expect(result.current.classProps.triggerClassName).toBe('is-expanded'); }); - it('should transfer additional props', () => { + it('should change placement', () => { const props = { - isOpen: false, - placement: DropdownPlacements.BOTTOM_LEFT, - transferProp: 'test', - }; + placement: 'top-right' as PlacementDictionaryType, + } as UseDropdownStyleProps; const { result } = renderHook(() => useDropdownStyleProps(props)); - expect(result.current.props).toEqual({ transferProp: 'test' }); + expect(result.current.classProps.contentClassName).toBe('Dropdown Dropdown--topRight'); }); - it('should change placement class', () => { + it('should transfer additional props', () => { const props = { isOpen: false, - placement: DropdownPlacements.TOP_RIGHT, - }; + transferProp: 'test', + } as UseDropdownStyleProps; const { result } = renderHook(() => useDropdownStyleProps(props)); - expect(result.current.classProps.contentClassName).toBe('Dropdown Dropdown--top Dropdown--right'); + expect(result.current.classProps.contentClassName).toBe('Dropdown Dropdown--bottomLeft'); + expect(result.current.props).toEqual({ transferProp: 'test' }); }); }); diff --git a/packages/web-react/src/components/Dropdown/stories/Dropdown.stories.tsx b/packages/web-react/src/components/Dropdown/stories/Dropdown.stories.tsx index 2d49de3993..92c993f36c 100644 --- a/packages/web-react/src/components/Dropdown/stories/Dropdown.stories.tsx +++ b/packages/web-react/src/components/Dropdown/stories/Dropdown.stories.tsx @@ -2,7 +2,9 @@ import React, { Ref } from 'react'; import { Markdown } from '@storybook/blocks'; import type { Meta, StoryObj } from '@storybook/react'; -import { DropdownFullWidthModes, DropdownPlacements } from '../../../types'; +import { Placements } from '../../../constants'; + +import { DropdownFullWidthModes } from '../../../types'; import { Button, Icon, Text } from '../..'; import ReadMe from '../README.md'; import { Dropdown } from '..'; @@ -38,9 +40,9 @@ const meta: Meta = { }, placement: { control: 'select', - options: [...Object.values(DropdownPlacements), undefined], + options: Object.values(Placements), table: { - defaultValue: { summary: DropdownPlacements.BOTTOM_LEFT }, + defaultValue: { summary: Placements.BOTTOM_LEFT }, }, }, }, @@ -66,6 +68,7 @@ const meta: Meta = { ), id: 'DropdownExample', + placement: Placements.BOTTOM_LEFT, }, }; diff --git a/packages/web-react/src/components/Dropdown/useDropdownStyleProps.ts b/packages/web-react/src/components/Dropdown/useDropdownStyleProps.ts index 9f17492744..d80cc87196 100644 --- a/packages/web-react/src/components/Dropdown/useDropdownStyleProps.ts +++ b/packages/web-react/src/components/Dropdown/useDropdownStyleProps.ts @@ -1,6 +1,7 @@ import classNames from 'classnames'; -import { SpiritDropdownProps, DropdownProps, DropdownPlacements } from '../../types'; +import { SpiritDropdownProps, DropdownProps } from '../../types'; import { useClassNamePrefix } from '../../hooks'; +import { kebabCaseToCamelCase } from '../../utils'; export interface UseDropdownStyleProps extends SpiritDropdownProps { /** open state */ @@ -19,24 +20,15 @@ export interface UseDropdownStylePropsReturn { export const useDropdownStyleProps = ( props: UseDropdownStyleProps = { isOpen: false }, ): UseDropdownStylePropsReturn => { - const { isOpen, placement = DropdownPlacements.BOTTOM_LEFT, ...modifiedProps } = props; + const { isOpen, placement = 'bottom-left', ...modifiedProps } = props; + const dropdownClass = useClassNamePrefix('Dropdown'); const dropdownWrapperClass = `${dropdownClass}Wrapper`; - const dropdownBottomClass = `${dropdownClass}--bottom`; - const dropdownTopClass = `${dropdownClass}--top`; - const dropdownLeftClass = `${dropdownClass}--left`; - const dropdownRightClass = `${dropdownClass}--right`; + const dropdownPlacementClass = `${dropdownClass}--${kebabCaseToCamelCase(placement)}`; const expandedClass = isOpen ? 'is-expanded' : ''; const openClass = isOpen ? 'is-open' : ''; - const dropdownPlacementClassNames = { - 'bottom-left': classNames(dropdownBottomClass, dropdownLeftClass), - 'bottom-right': classNames(dropdownBottomClass, dropdownRightClass), - 'top-left': classNames(dropdownTopClass, dropdownLeftClass), - 'top-right': classNames(dropdownTopClass, dropdownRightClass), - }; - const dropdownClassName = classNames(dropdownClass, openClass, { - [dropdownPlacementClassNames[placement]]: placement, - }); + + const dropdownClassName = classNames(dropdownClass, dropdownPlacementClass, openClass); const triggerClassName = classNames(expandedClass); return { diff --git a/packages/web-react/src/types/dropdown.ts b/packages/web-react/src/types/dropdown.ts index 26a5ddd265..4a496d41e9 100644 --- a/packages/web-react/src/types/dropdown.ts +++ b/packages/web-react/src/types/dropdown.ts @@ -1,12 +1,5 @@ import { LegacyRef, ReactNode } from 'react'; -import { Booleanish, ChildrenProps, ClickEvent, StyleProps } from './shared'; - -export const DropdownPlacements = { - BOTTOM_LEFT: 'bottom-left', - BOTTOM_RIGHT: 'bottom-right', - TOP_LEFT: 'top-left', - TOP_RIGHT: 'top-right', -} as const; +import { Booleanish, ChildrenProps, ClickEvent, PlacementDictionaryType, StyleProps } from './shared'; export const DropdownFullWidthModes = { OFF: 'off', @@ -14,9 +7,6 @@ export const DropdownFullWidthModes = { ALL: 'all', } as const; -export type DropdownPlacementKeys = keyof typeof DropdownPlacements; -export type DropdownPlacement = (typeof DropdownPlacements)[DropdownPlacementKeys]; - export type DropdownFullWidthModeKeys = keyof typeof DropdownFullWidthModes; export type DropdownFullWidthMode = (typeof DropdownFullWidthModes)[DropdownFullWidthModeKeys]; @@ -40,7 +30,7 @@ export interface DropdownProps extends ChildrenProps, StyleProps { export interface SpiritDropdownProps extends DropdownProps { enableAutoClose?: boolean; - placement?: DropdownPlacement; + placement?: PlacementDictionaryType; fullWidthMode?: DropdownFullWidthMode; onAutoClose?: (event: Event) => void; }