diff --git a/packages/web-react/scripts/entryPoints.js b/packages/web-react/scripts/entryPoints.js index a00b37a578..a16c5945c7 100644 --- a/packages/web-react/scripts/entryPoints.js +++ b/packages/web-react/scripts/entryPoints.js @@ -48,6 +48,7 @@ const entryPoints = [ { dirs: ['components', 'UNSTABLE_ActionLayout'] }, { dirs: ['components', 'UNSTABLE_Avatar'] }, { dirs: ['components', 'UNSTABLE_Divider'] }, + { dirs: ['components', 'UNSTABLE_EmptyState'] }, { dirs: ['components', 'UNSTABLE_Slider'] }, { dirs: ['components', 'VisuallyHidden'] }, ]; diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/README.md b/packages/web-react/src/components/UNSTABLE_EmptyState/README.md new file mode 100644 index 0000000000..585afa5856 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/README.md @@ -0,0 +1,4 @@ +# UNSTABLE EmptyState + +⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +Please use it with caution. diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.tsx b/packages/web-react/src/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.tsx new file mode 100644 index 0000000000..3cdf3e1109 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.tsx @@ -0,0 +1,24 @@ +import classNames from 'classnames'; +import React, { ReactElement } from 'react'; +import { useStyleProps } from '../../hooks'; +import { SpiritEmptyStateProps } from '../../types/emptyState'; +import { Stack } from '../Stack'; +import { useEmptyStateStyleProps } from './useEmptyStateStyleProps'; + +export const UNSTABLE_EmptyState = (props: SpiritEmptyStateProps): ReactElement => { + const { children, ...restProps } = props; + const { classProps, props: modifiedProps } = useEmptyStateStyleProps(restProps); + const { styleProps, props: otherProps } = useStyleProps(modifiedProps); + + return ( + + {children} + + ); +}; + +export default UNSTABLE_EmptyState; diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/UNSTABLE_EmptyStateSection.tsx b/packages/web-react/src/components/UNSTABLE_EmptyState/UNSTABLE_EmptyStateSection.tsx new file mode 100644 index 0000000000..c9d1504dd1 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/UNSTABLE_EmptyStateSection.tsx @@ -0,0 +1,24 @@ +import classNames from 'classnames'; +import React, { ReactElement } from 'react'; +import { useStyleProps } from '../../hooks'; +import { SpiritEmptyStateProps } from '../../types/emptyState'; +import { Stack } from '../Stack'; +import { useEmptyStateStyleProps } from './useEmptyStateStyleProps'; + +export const UNSTABLE_EmptyStateSection = (props: SpiritEmptyStateProps): ReactElement => { + const { children, ...restProps } = props; + const { classProps, props: modifiedProps } = useEmptyStateStyleProps(restProps); + const { styleProps, props: otherProps } = useStyleProps(modifiedProps); + + return ( + + {children} + + ); +}; + +export default UNSTABLE_EmptyStateSection; diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyState.test.tsx b/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyState.test.tsx new file mode 100644 index 0000000000..b83382ddc3 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyState.test.tsx @@ -0,0 +1,27 @@ +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_EmptyState from '../UNSTABLE_EmptyState'; + +describe('UNSTABLE_EmptyState', () => { + classNamePrefixProviderTest(UNSTABLE_EmptyState, 'UNSTABLE_EmptyState'); + + stylePropsTest(UNSTABLE_EmptyState); + + restPropsTest(UNSTABLE_EmptyState, 'div'); + + beforeEach(() => { + render(Content); + }); + + it('should have default classname', () => { + expect(screen.getByText('Content')).toHaveClass('UNSTABLE_EmptyState'); + }); + + it('should render children', () => { + expect(screen.getByText('Content')).toBeInTheDocument(); + }); +}); diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyStateSection.test.tsx b/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyStateSection.test.tsx new file mode 100644 index 0000000000..554af1129e --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyStateSection.test.tsx @@ -0,0 +1,27 @@ +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_EmptyStateSection } from '..'; + +describe('UNSTABLE_EmptyStateSection', () => { + classNamePrefixProviderTest(UNSTABLE_EmptyStateSection, 'UNSTABLE_EmptyState__section'); + + stylePropsTest(UNSTABLE_EmptyStateSection); + + restPropsTest(UNSTABLE_EmptyStateSection, 'div'); + + beforeEach(() => { + render(Content); + }); + + it('should have default classname', () => { + expect(screen.getByText('Content')).toHaveClass('UNSTABLE_EmptyState__section'); + }); + + it('should render children', () => { + expect(screen.getByText('Content')).toBeInTheDocument(); + }); +}); diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/useEmptyStateStyleProps.test.ts b/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/useEmptyStateStyleProps.test.ts new file mode 100644 index 0000000000..742d5c3c2a --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/__tests__/useEmptyStateStyleProps.test.ts @@ -0,0 +1,12 @@ +import { renderHook } from '@testing-library/react'; +import { useEmptyStateStyleProps } from '../useEmptyStateStyleProps'; + +describe('useEmptyStateStyleProps', () => { + it('should return defaults', () => { + const props = {}; + const { result } = renderHook(() => useEmptyStateStyleProps(props)); + + expect(result.current.classProps.root).toBe('UNSTABLE_EmptyState'); + expect(result.current.classProps.section).toBe('UNSTABLE_EmptyState__section'); + }); +}); diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/demo/EmptyStateDefault.tsx b/packages/web-react/src/components/UNSTABLE_EmptyState/demo/EmptyStateDefault.tsx new file mode 100644 index 0000000000..ce5fb83ab7 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/demo/EmptyStateDefault.tsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { ButtonLink } from '../../Button'; +import { Heading } from '../../Heading'; +import { Link } from '../../Link'; +import { Text } from '../../Text'; +import { UNSTABLE_ActionLayout } from '../../UNSTABLE_ActionLayout'; +import UNSTABLE_EmptyState from '../UNSTABLE_EmptyState'; +import UNSTABLE_EmptyStateSection from '../UNSTABLE_EmptyStateSection'; + +const EmptyStateDefault = () => ( + + +
+ + + + +
+ Placeholder + Replace me with your own component +
+
+
+ + + Headline + + + In publishing and graphic design, lorem ipsum is common placeholder text used to demonstrate the graphic + elements + + + + + + Action + + + Action + + + + + Link to something + +
+); + +export default EmptyStateDefault; diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/demo/index.tsx b/packages/web-react/src/components/UNSTABLE_EmptyState/demo/index.tsx new file mode 100644 index 0000000000..7a0ab5a8ce --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/demo/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import DocsSection from '../../../../docs/DocsSections'; +import EmptyStateDefault from './EmptyStateDefault'; + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + + + , +); diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/index.html b/packages/web-react/src/components/UNSTABLE_EmptyState/index.html new file mode 100644 index 0000000000..23972ef557 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/index.html @@ -0,0 +1 @@ +{{> web-react/demo}} diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/index.ts b/packages/web-react/src/components/UNSTABLE_EmptyState/index.ts new file mode 100644 index 0000000000..cdef182eec --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/index.ts @@ -0,0 +1,5 @@ +export { default as UNSTABLE_EmptyState } from './UNSTABLE_EmptyState'; +export { default as UNSTABLE_EmptyStateSection } from './UNSTABLE_EmptyStateSection'; +export * from './UNSTABLE_EmptyState'; +export * from './UNSTABLE_EmptyStateSection'; +export * from './useEmptyStateStyleProps'; diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/stories/UNSTABLE_EmptyState.stories.tsx b/packages/web-react/src/components/UNSTABLE_EmptyState/stories/UNSTABLE_EmptyState.stories.tsx new file mode 100644 index 0000000000..3d6fedde4a --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/stories/UNSTABLE_EmptyState.stories.tsx @@ -0,0 +1,57 @@ +import { Markdown } from '@storybook/blocks'; +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { ButtonLink } from '../../Button'; +import { Heading } from '../../Heading'; +import { Link } from '../../Link'; +import { Text } from '../../Text'; +import { UNSTABLE_ActionLayout } from '../../UNSTABLE_ActionLayout'; +import ReadMe from '../README.md'; +import { UNSTABLE_EmptyStateSection, UNSTABLE_EmptyState } from '..'; + +const meta: Meta = { + title: 'Experimental/UNSTABLE_EmptyState', + component: UNSTABLE_EmptyState, + parameters: { + docs: { + page: () => {ReadMe}, + }, + }, + argTypes: {}, + args: { + spacing: 'space-700', + children: ( + <> + + + Headline + + + In publishing and graphic design, lorem ipsum is common placeholder text used to demonstrate the graphic + elements + + + + + + Action + + + Action + + + + + Link to something + + + ), + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + name: 'UNSTABLE_EmptyState', +}; diff --git a/packages/web-react/src/components/UNSTABLE_EmptyState/useEmptyStateStyleProps.ts b/packages/web-react/src/components/UNSTABLE_EmptyState/useEmptyStateStyleProps.ts new file mode 100644 index 0000000000..439e6f3d79 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/useEmptyStateStyleProps.ts @@ -0,0 +1,23 @@ +import { useClassNamePrefix } from '../../hooks'; +import { SpiritEmptyStateProps } from '../../types/emptyState'; + +export interface EmptyStateStyles { + classProps: { + root: string; + section: string; + }; + props: T; +} + +export function useEmptyStateStyleProps(props: SpiritEmptyStateProps): EmptyStateStyles { + const emptyStateClass = useClassNamePrefix('UNSTABLE_EmptyState'); + const sectionClass = `${emptyStateClass}__section`; + + return { + classProps: { + root: emptyStateClass, + section: sectionClass, + }, + props, + }; +} diff --git a/packages/web-react/src/types/emptyState.ts b/packages/web-react/src/types/emptyState.ts new file mode 100644 index 0000000000..89f204e710 --- /dev/null +++ b/packages/web-react/src/types/emptyState.ts @@ -0,0 +1,4 @@ +import { ChildrenProps, StyleProps } from './shared'; +import { SpiritStackProps } from './stack'; + +export interface SpiritEmptyStateProps extends ChildrenProps, SpiritStackProps, StyleProps {} diff --git a/tests/e2e/demo-homepages.spec.ts-snapshots/web-chromium-linux.png b/tests/e2e/demo-homepages.spec.ts-snapshots/web-chromium-linux.png index 702601230a..4c83d258f9 100644 Binary files a/tests/e2e/demo-homepages.spec.ts-snapshots/web-chromium-linux.png and b/tests/e2e/demo-homepages.spec.ts-snapshots/web-chromium-linux.png differ diff --git a/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png b/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png index 91b99b2e66..9a7ef6de90 100644 Binary files a/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png and b/tests/e2e/demo-homepages.spec.ts-snapshots/web-react-chromium-linux.png differ