From 0e2c9c509ec42e3e65de9e2d55a171cdbc117630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C4=8Curda?= Date: Mon, 2 Dec 2024 11:27:20 +0100 Subject: [PATCH] Feat(web-react): UNSTABLE_Header is React #DS-1524 --- .../src/components/UNSTABLE_Header/README.md | 36 ++++++++++++++ .../UNSTABLE_Header/UNSTABLE_Header.tsx | 34 +++++++++++++ .../__tests__/UNSTABLE_Header.test.tsx | 36 ++++++++++++++ .../__tests__/useHeaderStyleProps.test.ts | 26 ++++++++++ .../UNSTABLE_Header/demo/HeaderDefault.tsx | 16 +++++++ .../UNSTABLE_Header/demo/HeaderFluid.tsx | 17 +++++++ .../UNSTABLE_Header/demo/HeaderSimple.tsx | 17 +++++++ .../components/UNSTABLE_Header/demo/index.tsx | 20 ++++++++ .../src/components/UNSTABLE_Header/index.html | 1 + .../src/components/UNSTABLE_Header/index.ts | 4 ++ .../stories/UNSTABLE_Header.stories.tsx | 48 +++++++++++++++++++ .../UNSTABLE_Header/useHeaderStyleProps.ts | 32 +++++++++++++ 12 files changed, 287 insertions(+) create mode 100644 packages/web-react/src/components/UNSTABLE_Header/README.md create mode 100644 packages/web-react/src/components/UNSTABLE_Header/UNSTABLE_Header.tsx create mode 100644 packages/web-react/src/components/UNSTABLE_Header/__tests__/UNSTABLE_Header.test.tsx create mode 100644 packages/web-react/src/components/UNSTABLE_Header/__tests__/useHeaderStyleProps.test.ts create mode 100644 packages/web-react/src/components/UNSTABLE_Header/demo/HeaderDefault.tsx create mode 100644 packages/web-react/src/components/UNSTABLE_Header/demo/HeaderFluid.tsx create mode 100644 packages/web-react/src/components/UNSTABLE_Header/demo/HeaderSimple.tsx create mode 100644 packages/web-react/src/components/UNSTABLE_Header/demo/index.tsx create mode 100644 packages/web-react/src/components/UNSTABLE_Header/index.html create mode 100644 packages/web-react/src/components/UNSTABLE_Header/index.ts create mode 100644 packages/web-react/src/components/UNSTABLE_Header/stories/UNSTABLE_Header.stories.tsx create mode 100644 packages/web-react/src/components/UNSTABLE_Header/useHeaderStyleProps.ts diff --git a/packages/web-react/src/components/UNSTABLE_Header/README.md b/packages/web-react/src/components/UNSTABLE_Header/README.md new file mode 100644 index 0000000000..e09ef09a6d --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/README.md @@ -0,0 +1,36 @@ +# UNSTABLE Truncate + +> ⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +> Please use it with caution. + +Truncate is a component that truncates text based on defined number of rows. + +```jsx +import { UNSTABLE_Truncate } from '@lmc-eu/spirit-web-react'; + +{/* Text go here */}; +``` + +## Lines + +You can add the number of lines to which you want to truncate the text using `lines` props + +```jsx +{/* Text go here */} +``` + +## API + +| Name | Type | Default | Required | Description | +| ------------- | ----------------------- | ------- | -------- | -------------------------------------------------- | +| `children` | `string` \| `ReactNode` | `null` | ✓ | Content of the Truncate | +| `elementType` | `ElementType` | `span` | ✕ | Type of element used | +| `lines` | `number` | 3 | ✕ | The number of lines on which the text is truncated | + +The components accept [additional attributes][readme-additional-attributes]. +If you need more control over the styling of a component, you can use [style props][readme-style-props] +and [escape hatches][readme-escape-hatches]. + +[readme-additional-attributes]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#additional-attributes +[readme-escape-hatches]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#escape-hatches +[readme-style-props]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/README.md#style-props diff --git a/packages/web-react/src/components/UNSTABLE_Header/UNSTABLE_Header.tsx b/packages/web-react/src/components/UNSTABLE_Header/UNSTABLE_Header.tsx new file mode 100644 index 0000000000..e1ecf2ec61 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/UNSTABLE_Header.tsx @@ -0,0 +1,34 @@ +'use client'; + +import classNames from 'classnames'; +import React from 'react'; +import { useStyleProps } from '../../hooks'; +import { ChildrenProps, StyleProps } from '../../types'; +import { useHeaderStyleProps } from './useHeaderStyleProps'; + +export type SpiritHeaderProps = { + isFluid?: boolean; + isSimple?: boolean; +} & StyleProps & + ChildrenProps; + +const defaultProps: Partial = { + isFluid: false, + isSimple: false, +}; + +const UNSTABLE_Header = (props: SpiritHeaderProps): JSX.Element => { + const propsWithDefaults = { ...defaultProps, ...props }; + const { children, ...restProps } = propsWithDefaults; + + const { classProps, props: modifiedProps } = useHeaderStyleProps(restProps); + const { styleProps, props: otherProps } = useStyleProps(modifiedProps); + + return ( +
+
{children}
+
+ ); +}; + +export default UNSTABLE_Header; diff --git a/packages/web-react/src/components/UNSTABLE_Header/__tests__/UNSTABLE_Header.test.tsx b/packages/web-react/src/components/UNSTABLE_Header/__tests__/UNSTABLE_Header.test.tsx new file mode 100644 index 0000000000..e5cfc819e8 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/__tests__/UNSTABLE_Header.test.tsx @@ -0,0 +1,36 @@ +import '@testing-library/jest-dom'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest'; +import { restPropsTest } from '../../../../tests/providerTests/restPropsTest'; +import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest'; +import UNSTABLE_Header from '../UNSTABLE_Header'; + +describe('UNSTABLE_Header', () => { + classNamePrefixProviderTest(UNSTABLE_Header, 'UNSTABLE_Header'); + + stylePropsTest(UNSTABLE_Header); + + restPropsTest(UNSTABLE_Header, 'header'); + + it('should have default classname', () => { + render(Content); + + const header = screen.getByRole('banner'); + + expect(header).toHaveClass('UNSTABLE_Header'); + expect(header.firstChild).toHaveClass('UNSTABLE_Header__container'); + }); + + it('should have fluid classname', () => { + render(Content); + + expect(screen.getByRole('banner')).toHaveClass('UNSTABLE_Header--fluid'); + }); + + it('should have simple classname', () => { + render(Content); + + expect(screen.getByRole('banner')).toHaveClass('UNSTABLE_Header--simple'); + }); +}); diff --git a/packages/web-react/src/components/UNSTABLE_Header/__tests__/useHeaderStyleProps.test.ts b/packages/web-react/src/components/UNSTABLE_Header/__tests__/useHeaderStyleProps.test.ts new file mode 100644 index 0000000000..7a0f342587 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/__tests__/useHeaderStyleProps.test.ts @@ -0,0 +1,26 @@ +import { renderHook } from '@testing-library/react'; +import { useHeaderStyleProps } from '../useHeaderStyleProps'; + +describe('useHeaderStyleProps', () => { + it('should return defaults', () => { + const props = {}; + const { result } = renderHook(() => useHeaderStyleProps(props)); + + expect(result.current.classProps.root).toBe('UNSTABLE_Header'); + expect(result.current.classProps.container).toBe('UNSTABLE_Header__container'); + }); + + it('should return isFluid', () => { + const props = { isFluid: true }; + const { result } = renderHook(() => useHeaderStyleProps(props)); + + expect(result.current.classProps.root).toBe('UNSTABLE_Header UNSTABLE_Header--fluid'); + }); + + it('should return isSimple', () => { + const props = { isSimple: true }; + const { result } = renderHook(() => useHeaderStyleProps(props)); + + expect(result.current.classProps.root).toBe('UNSTABLE_Header UNSTABLE_Header--simple'); + }); +}); diff --git a/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderDefault.tsx b/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderDefault.tsx new file mode 100644 index 0000000000..437401a9a7 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderDefault.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { Link } from '../../Link'; +import { ProductLogo } from '../../ProductLogo'; +import { defaultSvgLogo } from '../../ProductLogo/demo/ProductLogoDefault'; +import { UNSTABLE_Header } from '../index'; + +const HeaderDefault = () => { + return ( + + + {defaultSvgLogo} + + + ); +}; +export default HeaderDefault; diff --git a/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderFluid.tsx b/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderFluid.tsx new file mode 100644 index 0000000000..8d6d288544 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderFluid.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Link } from '../../Link'; +import { ProductLogo } from '../../ProductLogo'; +import { defaultSvgLogo } from '../../ProductLogo/demo/ProductLogoDefault'; +import { UNSTABLE_Header } from '..'; + +const HeaderFluid = () => { + return ( + + + {defaultSvgLogo} + + + ); +}; + +export default HeaderFluid; diff --git a/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderSimple.tsx b/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderSimple.tsx new file mode 100644 index 0000000000..110d04cfb0 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/demo/HeaderSimple.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Link } from '../../Link'; +import { ProductLogo } from '../../ProductLogo'; +import { defaultSvgLogo } from '../../ProductLogo/demo/ProductLogoDefault'; +import { UNSTABLE_Header } from '..'; + +const HeaderSimple = () => { + return ( + + + {defaultSvgLogo} + + + ); +}; + +export default HeaderSimple; diff --git a/packages/web-react/src/components/UNSTABLE_Header/demo/index.tsx b/packages/web-react/src/components/UNSTABLE_Header/demo/index.tsx new file mode 100644 index 0000000000..cc64d91b32 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/demo/index.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import DocsSection from '../../../../docs/DocsSections'; +import HeaderDefault from './HeaderDefault'; +import HeaderFluid from './HeaderFluid'; +import HeaderSimple from './HeaderSimple'; + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + + + + + + + + + , +); diff --git a/packages/web-react/src/components/UNSTABLE_Header/index.html b/packages/web-react/src/components/UNSTABLE_Header/index.html new file mode 100644 index 0000000000..39c220fe8c --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/index.html @@ -0,0 +1 @@ +{{> web-react/demo title="Header" parentPageName="Components" isUnstable=true }} diff --git a/packages/web-react/src/components/UNSTABLE_Header/index.ts b/packages/web-react/src/components/UNSTABLE_Header/index.ts new file mode 100644 index 0000000000..6e0d0f6b0e --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/index.ts @@ -0,0 +1,4 @@ +'use client'; + +export { default as UNSTABLE_Header } from './UNSTABLE_Header'; +export * from './useHeaderStyleProps'; diff --git a/packages/web-react/src/components/UNSTABLE_Header/stories/UNSTABLE_Header.stories.tsx b/packages/web-react/src/components/UNSTABLE_Header/stories/UNSTABLE_Header.stories.tsx new file mode 100644 index 0000000000..648c652d77 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/stories/UNSTABLE_Header.stories.tsx @@ -0,0 +1,48 @@ +import { Markdown } from '@storybook/blocks'; +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { Link } from '../../Link'; +import { ProductLogo } from '../../ProductLogo'; +import { defaultSvgLogo } from '../../ProductLogo/demo/ProductLogoDefault'; +import ReadMe from '../README.md'; +import { UNSTABLE_Header } from '..'; + +const meta: Meta = { + title: 'Experimental/UNSTABLE_Header', + component: UNSTABLE_Header, + parameters: { + docs: { + page: () => {ReadMe}, + }, + }, + argTypes: { + isSimple: { + control: 'boolean', + table: { + defaultValue: { summary: 'false' }, + }, + }, + isFluid: { + control: 'boolean', + table: { + defaultValue: { summary: 'false' }, + }, + }, + }, + args: { + children: ( + + {defaultSvgLogo} + + ), + isFluid: false, + isSimple: false, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + name: 'UNSTABLE_Header', +}; diff --git a/packages/web-react/src/components/UNSTABLE_Header/useHeaderStyleProps.ts b/packages/web-react/src/components/UNSTABLE_Header/useHeaderStyleProps.ts new file mode 100644 index 0000000000..80613bc8b6 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_Header/useHeaderStyleProps.ts @@ -0,0 +1,32 @@ +import classNames from 'classnames'; +import { useClassNamePrefix } from '../../hooks'; +import { SpiritHeaderProps } from './UNSTABLE_Header'; + +export interface HeaderStyles { + classProps: { + root: string; + container: string; + }; + props: T; +} + +export const useHeaderStyleProps = (props: SpiritHeaderProps): HeaderStyles => { + const { isFluid, isSimple, ...restProps } = props; + + const headerClass = useClassNamePrefix('UNSTABLE_Header'); + const headerSimpleClass = `${headerClass}--simple`; + const headerFluidClass = `${headerClass}--fluid`; + const rootClassProps = classNames(headerClass, { + [headerSimpleClass]: isSimple, + [headerFluidClass]: isFluid, + }); + const containerClassProps = `${headerClass}__container`; + + return { + classProps: { + root: rootClassProps, + container: containerClassProps, + }, + props: restProps, + }; +};