diff --git a/packages/demo/scss/index.scss b/packages/demo/scss/index.scss index 82b5c14ca0..8f7a57db6b 100644 --- a/packages/demo/scss/index.scss +++ b/packages/demo/scss/index.scss @@ -61,6 +61,26 @@ white-space: normal; } +.docs-Placeholder { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + padding: 3rem 1.5rem; + text-align: center; + gap: 2rem; + border: 1px dashed #3eac98; + background: #fff; +} + +.docs-Placeholder__text { + display: flex; + flex-direction: column; + color: #3eac98; + gap: 0.5rem; +} + @media (min-width: 768px) { .docs-TileLink { padding: 1.5rem; diff --git a/packages/web-react/scripts/entryPoints.js b/packages/web-react/scripts/entryPoints.js index 5b6fd38449..a16c5945c7 100644 --- a/packages/web-react/scripts/entryPoints.js +++ b/packages/web-react/scripts/entryPoints.js @@ -45,8 +45,10 @@ const entryPoints = [ { dirs: ['components', 'TextFieldBase'] }, { dirs: ['components', 'Toast'] }, { dirs: ['components', 'Tooltip'] }, + { 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_ActionLayout/README.md b/packages/web-react/src/components/UNSTABLE_ActionLayout/README.md new file mode 100644 index 0000000000..f4aa1a0293 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/README.md @@ -0,0 +1,28 @@ +# UNSTABLE ActionLayout + +⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +Please use it with caution. + +ActionLayout component is a container component that is used to position action components in a predefined layout. + +- For desktop and tablet views, actions are positioned in a horizontal direction with reverse order. +- For mobile view, actions are positioned in a vertical layout and are stretched to the full width of the container. + +```jsx + + + +``` + +## Full Example + +```jsx + + + Primary Action + + + Secondary Action + + +``` diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.tsx b/packages/web-react/src/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.tsx new file mode 100644 index 0000000000..6b0c1e1765 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.tsx @@ -0,0 +1,19 @@ +import classNames from 'classnames'; +import React, { ReactElement } from 'react'; +import { useStyleProps } from '../../hooks'; +import { SpiritActionLayoutProps } from '../../types/actionLayout'; +import { useActionLayoutStyleProps } from './useActionLayoutStyleProps'; + +export const UNSTABLE_ActionLayout = (props: SpiritActionLayoutProps): ReactElement => { + const { children, ...restProps } = props; + const { classProps, props: modifiedProps } = useActionLayoutStyleProps(restProps); + const { styleProps, props: otherProps } = useStyleProps(modifiedProps); + + return ( +
+ {children} +
+ ); +}; + +export default UNSTABLE_ActionLayout; diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/__tests__/UNSTABLE_ActionLayout.test.tsx b/packages/web-react/src/components/UNSTABLE_ActionLayout/__tests__/UNSTABLE_ActionLayout.test.tsx new file mode 100644 index 0000000000..e55477ae2d --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/__tests__/UNSTABLE_ActionLayout.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_ActionLayout from '../UNSTABLE_ActionLayout'; + +describe('UNSTABLE_ActionLayout', () => { + classNamePrefixProviderTest(UNSTABLE_ActionLayout, 'UNSTABLE_ActionLayout'); + + stylePropsTest(UNSTABLE_ActionLayout); + + restPropsTest(UNSTABLE_ActionLayout, 'div'); + + beforeEach(() => { + render(Content); + }); + + it('should render content', () => { + expect(screen.getByText('Content')).toBeInTheDocument(); + }); + + it('should render children', () => { + expect(screen.getByText('Content')).toHaveClass('UNSTABLE_ActionLayout'); + }); +}); diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/__tests__/useActionLayoutStyleProps.test.ts b/packages/web-react/src/components/UNSTABLE_ActionLayout/__tests__/useActionLayoutStyleProps.test.ts new file mode 100644 index 0000000000..bd5a7701be --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/__tests__/useActionLayoutStyleProps.test.ts @@ -0,0 +1,11 @@ +import { renderHook } from '@testing-library/react'; +import { useActionLayoutStyleProps } from '../useActionLayoutStyleProps'; + +describe('useActionLayoutStyleProps', () => { + it('should return defaults', () => { + const props = {}; + const { result } = renderHook(() => useActionLayoutStyleProps(props)); + + expect(result.current.classProps.root).toBe('UNSTABLE_ActionLayout'); + }); +}); diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/demo/ActionLayoutDefault.tsx b/packages/web-react/src/components/UNSTABLE_ActionLayout/demo/ActionLayoutDefault.tsx new file mode 100644 index 0000000000..bf8884d638 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/demo/ActionLayoutDefault.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { ButtonLink } from '../../Button'; +import { UNSTABLE_ActionLayout } from '../index'; + +const ActionLayoutDefault = () => ( + + + Primary Action + + + Secondary Action + + +); + +export default ActionLayoutDefault; diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/demo/index.tsx b/packages/web-react/src/components/UNSTABLE_ActionLayout/demo/index.tsx new file mode 100644 index 0000000000..0f71f08083 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/demo/index.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import DocsSection from '../../../../docs/DocsSections'; +import ActionLayoutDefault from './ActionLayoutDefault'; + +ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( + + + + + , +); diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/index.html b/packages/web-react/src/components/UNSTABLE_ActionLayout/index.html new file mode 100644 index 0000000000..23972ef557 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/index.html @@ -0,0 +1 @@ +{{> web-react/demo}} diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/index.ts b/packages/web-react/src/components/UNSTABLE_ActionLayout/index.ts new file mode 100644 index 0000000000..db68ba9893 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/index.ts @@ -0,0 +1,3 @@ +export { default as UNSTABLE_ActionLayout } from './UNSTABLE_ActionLayout'; +export * from './UNSTABLE_ActionLayout'; +export * from './useActionLayoutStyleProps'; diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/stories/UNSTABLE_ActionLayout.stories.tsx b/packages/web-react/src/components/UNSTABLE_ActionLayout/stories/UNSTABLE_ActionLayout.stories.tsx new file mode 100644 index 0000000000..54d5e781cf --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/stories/UNSTABLE_ActionLayout.stories.tsx @@ -0,0 +1,36 @@ +import { Markdown } from '@storybook/blocks'; +import type { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { ButtonLink } from '../../Button'; +import ReadMe from '../README.md'; +import { UNSTABLE_ActionLayout } from '..'; + +const meta: Meta = { + title: 'Experimental/UNSTABLE_ActionLayout', + component: UNSTABLE_ActionLayout, + parameters: { + docs: { + page: () => {ReadMe}, + }, + }, + argTypes: {}, + args: { + children: ( + <> + + Primary Action + + + Secondary Action + + + ), + }, +}; + +export default meta; +type Story = StoryObj; + +export const Playground: Story = { + name: 'UNSTABLE_ActionLayout', +}; diff --git a/packages/web-react/src/components/UNSTABLE_ActionLayout/useActionLayoutStyleProps.ts b/packages/web-react/src/components/UNSTABLE_ActionLayout/useActionLayoutStyleProps.ts new file mode 100644 index 0000000000..d7dd415cdf --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_ActionLayout/useActionLayoutStyleProps.ts @@ -0,0 +1,20 @@ +import { useClassNamePrefix } from '../../hooks'; +import { SpiritActionLayoutProps } from '../../types/actionLayout'; + +export interface ActionLayoutStyles { + classProps: { + root: string; + }; + props: T; +} + +export function useActionLayoutStyleProps(props: SpiritActionLayoutProps): ActionLayoutStyles { + const actionLayoutClass = useClassNamePrefix('UNSTABLE_ActionLayout'); + + return { + classProps: { + root: actionLayoutClass, + }, + props, + }; +} 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..262303f8d0 --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/README.md @@ -0,0 +1,69 @@ +# UNSTABLE EmptyState + +⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +Please use it with caution. + +EmptyState component should be included in the error pages or empty state pages as the carrier of information and links to elsewhere. + +EmptyState component is a composition of the following components: + +- [UNSTABLE_EmptyState](#unstable-emptystate) + - [UNSTABLE_EmptyStateSection](#unstable-emptystatesection) + +## UNSTABLE EmptyState + +The `UNSTABLE_EmptyState` component is a main container responsible for positioning the [UNSTABLE_EmptyStateSection](#unstable-emptystatesection) components or content. + +```jsx + + + +``` + +### API + +The component is based on the [Stack][stack] component and accepts all its properties. For more information, see the [Stack component API][stack-api]. + +## UNSTABLE EmptyStateSection + +The `UNSTABLE_EmptyStateSection` component is a container for the content of each section. + +```jsx + + + +``` + +### API + +The component is based on the [Stack][stack] component and accepts all its properties. For more information, see the [Stack component API][stack-api]. + +[stack]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/src/components/Stack/README.md +[stack-api]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-react/src/components/Stack/README.md#api + +## Full Example + +```jsx + + + + + + Heading + Description + + + + + Primary Action + + + Secondary Action + + + + + Link to something + + +``` 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..a5a385be3d --- /dev/null +++ b/packages/web-react/src/components/UNSTABLE_EmptyState/demo/EmptyStateDefault.tsx @@ -0,0 +1,54 @@ +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/actionLayout.ts b/packages/web-react/src/types/actionLayout.ts new file mode 100644 index 0000000000..89a7f0dcc3 --- /dev/null +++ b/packages/web-react/src/types/actionLayout.ts @@ -0,0 +1,3 @@ +import { ChildrenProps, StyleProps } from './shared'; + +export interface SpiritActionLayoutProps extends ChildrenProps, StyleProps {} 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/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/README.md b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/README.md new file mode 100644 index 0000000000..c7849cad7d --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/README.md @@ -0,0 +1,24 @@ +# UNSTABLE ActionLayout + +⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +Please use it with caution. + +ActionLayout component is a container component that is used to position action components in a predefined layout. + +- For desktop and tablet views, actions are positioned in a horizontal direction with reverse order. +- For mobile view, actions are positioned in a vertical layout and are stretched to the full width of the container. + +```twig + + + +``` + +## Full Example + +```twig + + Primary Action + Secondary Action + +``` diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.stories.twig b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.stories.twig new file mode 100644 index 0000000000..d27f54607b --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.stories.twig @@ -0,0 +1,9 @@ +{% extends 'layout/plain.html.twig' %} + +{% block content %} + + + {% include '@components/UNSTABLE_ActionLayout/stories/ActionLayoutDefault.twig' %} + + +{% endblock %} diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.twig b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.twig new file mode 100644 index 0000000000..2c8009631a --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.twig @@ -0,0 +1,6 @@ +{# Class names #} +{%- set _rootClassName = _spiritClassPrefix ~ 'UNSTABLE_ActionLayout' -%} + +
+ {% block content %}{% endblock %} +
diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/UNSTABLE_ActionLayoutSnapshotTest.php b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/UNSTABLE_ActionLayoutSnapshotTest.php new file mode 100644 index 0000000000..195b086f24 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/UNSTABLE_ActionLayoutSnapshotTest.php @@ -0,0 +1,9 @@ + + + Primary Button + Secondary Button + diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/__snapshots__/UNSTABLE_ActionLayout.twig.snap.html b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/__snapshots__/UNSTABLE_ActionLayout.twig.snap.html new file mode 100644 index 0000000000..71497e2d33 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/__snapshots__/UNSTABLE_ActionLayout.twig.snap.html @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/__snapshots__/UNSTABLE_EmptyState.twig.snap.html b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/__snapshots__/UNSTABLE_EmptyState.twig.snap.html new file mode 100644 index 0000000000..44f2945203 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/__tests__/__snapshots__/UNSTABLE_EmptyState.twig.snap.html @@ -0,0 +1,39 @@ + + + + + + + +
+
+
+ +
+
+ +
+

+ Headline +

+ +

+ In publishing and graphic design, lorem ipsum is common placeholder text used to demonstrate the graphic + elements +

+
+ +
+ +
+ + +
+ + diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/stories/ActionLayoutDefault.twig b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/stories/ActionLayoutDefault.twig new file mode 100644 index 0000000000..5b16df59d0 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_ActionLayout/stories/ActionLayoutDefault.twig @@ -0,0 +1,4 @@ + + Primary Action + Secondary Action + diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/README.md b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/README.md new file mode 100644 index 0000000000..12246a234a --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/README.md @@ -0,0 +1,66 @@ +# UNSTABLE EmptyState + +⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +Please use it with caution. + +EmptyState component should be included at the error pages or empty state pages as the carrier of an information and links to elsewhere. + +EmptyState component is a composition of the following components: + +- [UNSTABLE_EmptyState](#unstable-emptystate) + - [UNSTABLE_EmptyStateSection](#unstable-emptystatesection) + +## UNSTABLE EmptyState + +The `UNSTABLE_EmptyState` component is a main container responsible for positioning the [UNSTABLE_EmptyStateSection](#unstable-emptystatesection) components or content. + +```twig + + + +``` + +### API + +This component is based on the [Stack][stack] component and accepts all its properties. For more information, see the [Stack component API][stack-api]. + +## UNSTABLE EmptyStateSection + +The `UNSTABLE_EmptyStateSection` component is a container for the content of each section. + +```twig + + + +``` + +### API + +The component is based on the [Stack][stack] component and accepts all its properties. For more information, see the [Stack component API][stack-api]. + +[stack]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-twig/src/Resources/components/Stack/README.md +[stack-api]: https://github.com/lmc-eu/spirit-design-system/blob/main/packages/web-twig/src/Resources/components/Stack/README.md#api + +## Full Example + +```twig + + + + + + Heading + Description + + + + Primary Action + Secondary Action + + + + Link to something + + + +``` diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.stories.twig b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.stories.twig new file mode 100644 index 0000000000..24aa29fa37 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.stories.twig @@ -0,0 +1,9 @@ +{% extends 'layout/plain.html.twig' %} + +{% block content %} + + + {% include '@components/UNSTABLE_EmptyState/stories/EmptyStateDefault.twig' %} + + +{% endblock %} diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.twig b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.twig new file mode 100644 index 0000000000..7b46ff4e7d --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyState.twig @@ -0,0 +1,20 @@ +{# API #} +{%- set props = props | default([]) -%} + +{# Class names #} +{%- set _rootClassName = _spiritClassPrefix ~ 'UNSTABLE_EmptyState' -%} + +{# Miscellaneous #} +{%- set _styleProps = useStyleProps(props) -%} +{%- set _classNames = [ _rootClassName, _styleProps.className ] -%} + +{%- set _renderedContent %} + {% block content %}{% endblock %} +{% endset -%} + +{% embed "@spirit/stack.twig" with { props: props | merge({ + UNSAFE_className: _classNames | join(' '), + UNSAFE_style: _styleProps.style, +}) } %} + {% block content %}{{ _renderedContent }}{% endblock %} +{% endembed %} diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyStateSection.twig b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyStateSection.twig new file mode 100644 index 0000000000..bea351ffd5 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/UNSTABLE_EmptyStateSection.twig @@ -0,0 +1,20 @@ +{# API #} +{%- set props = props | default([]) -%} + +{# Class names #} +{%- set _rootClassName = _spiritClassPrefix ~ 'UNSTABLE_EmptyState__section' -%} + +{# Miscellaneous #} +{%- set _styleProps = useStyleProps(props) -%} +{%- set _classNames = [ _rootClassName, _styleProps.className ] -%} + +{%- set _renderedContent %} + {% block content %}{% endblock %} +{% endset -%} + +{% embed "@spirit/stack.twig" with { props: props | merge({ + UNSAFE_className: _classNames | join(' '), + UNSAFE_style: _styleProps.style, +}) } %} + {% block content %}{{ _renderedContent }}{% endblock %} +{% endembed %} diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyStateSnapshotTest.php b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyStateSnapshotTest.php new file mode 100644 index 0000000000..a3b54d3408 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/__tests__/UNSTABLE_EmptyStateSnapshotTest.php @@ -0,0 +1,9 @@ + + + +
+ +
+
+ + + Headline + + In publishing and graphic design, lorem ipsum is common placeholder text used to demonstrate the graphic elements + + + + Action + Action + + + + Link to something + +
diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/__tests__/__snapshots__/UNSTABLE_EmptyState.twig.snap.html b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/__tests__/__snapshots__/UNSTABLE_EmptyState.twig.snap.html new file mode 100644 index 0000000000..c8e9d2caca --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/__tests__/__snapshots__/UNSTABLE_EmptyState.twig.snap.html @@ -0,0 +1,39 @@ + + + + + + + +
+
+
+ +
+
+ +
+

+ Headline +

+ +

+ In publishing and graphic design, lorem ipsum is common placeholder text used to demonstrate the graphic + elements +

+
+ +
+ +
+ + +
+ + diff --git a/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/stories/EmptyStateDefault.twig b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/stories/EmptyStateDefault.twig new file mode 100644 index 0000000000..47d01c0cd3 --- /dev/null +++ b/packages/web-twig/src/Resources/components/UNSTABLE_EmptyState/stories/EmptyStateDefault.twig @@ -0,0 +1,30 @@ + + +
+ + + + +
+ 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 + +
diff --git a/packages/web-twig/src/Resources/twig-components/unstable_ActionLayout.twig b/packages/web-twig/src/Resources/twig-components/unstable_ActionLayout.twig new file mode 100644 index 0000000000..a71cf46acc --- /dev/null +++ b/packages/web-twig/src/Resources/twig-components/unstable_ActionLayout.twig @@ -0,0 +1 @@ +{% extends '@spirit/UNSTABLE_ActionLayout/UNSTABLE_ActionLayout.twig' %} diff --git a/packages/web-twig/src/Resources/twig-components/unstable_EmptyState.twig b/packages/web-twig/src/Resources/twig-components/unstable_EmptyState.twig new file mode 100644 index 0000000000..0d70950711 --- /dev/null +++ b/packages/web-twig/src/Resources/twig-components/unstable_EmptyState.twig @@ -0,0 +1 @@ +{% extends '@spirit/UNSTABLE_EmptyState/UNSTABLE_EmptyState.twig' %} diff --git a/packages/web-twig/src/Resources/twig-components/unstable_EmptyStateSection.twig b/packages/web-twig/src/Resources/twig-components/unstable_EmptyStateSection.twig new file mode 100644 index 0000000000..d268a32001 --- /dev/null +++ b/packages/web-twig/src/Resources/twig-components/unstable_EmptyStateSection.twig @@ -0,0 +1 @@ +{% extends '@spirit/UNSTABLE_EmptyState/UNSTABLE_EmptyStateSection.twig' %} diff --git a/packages/web/src/scss/components/UNSTABLE_ActionLayout/README.md b/packages/web/src/scss/components/UNSTABLE_ActionLayout/README.md new file mode 100644 index 0000000000..a2078308a7 --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_ActionLayout/README.md @@ -0,0 +1,24 @@ +# UNSTABLE ActionLayout + +⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +Please use it with caution. + +ActionLayout component is a container component that is used to position action components in a predefined layout. + +- For desktop and tablet views, actions are positioned in a horizontal direction with reverse order. +- For mobile view, actions are positioned in a vertical layout and are stretched to the full width of the container. + +```html +
+ +
+``` + +## Full Example + +```html + +``` diff --git a/packages/web/src/scss/components/UNSTABLE_ActionLayout/_UNSTABLE_ActionLayout.scss b/packages/web/src/scss/components/UNSTABLE_ActionLayout/_UNSTABLE_ActionLayout.scss new file mode 100644 index 0000000000..58e6a14a9b --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_ActionLayout/_UNSTABLE_ActionLayout.scss @@ -0,0 +1,15 @@ +@use 'sass:map'; +@use 'theme' as theme; +@use '../../tools/breakpoint'; + +.UNSTABLE_ActionLayout { + display: flex; + flex-direction: column; + gap: theme.$root-gap; + justify-content: center; + width: 100%; + + @include breakpoint.up(map.get(theme.$breakpoints, tablet)) { + flex-direction: row-reverse; + } +} diff --git a/packages/web/src/scss/components/UNSTABLE_ActionLayout/_theme.scss b/packages/web/src/scss/components/UNSTABLE_ActionLayout/_theme.scss new file mode 100644 index 0000000000..207541aafd --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_ActionLayout/_theme.scss @@ -0,0 +1,4 @@ +@use '@tokens' as tokens; + +$breakpoints: tokens.$breakpoints; +$root-gap: tokens.$space-600; diff --git a/packages/web/src/scss/components/UNSTABLE_ActionLayout/index.html b/packages/web/src/scss/components/UNSTABLE_ActionLayout/index.html new file mode 100644 index 0000000000..9ffefd468a --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_ActionLayout/index.html @@ -0,0 +1,14 @@ +{{#> web/layout/plain }} + +

Default

+ +
+ +{{/web/layout/plain }} diff --git a/packages/web/src/scss/components/UNSTABLE_ActionLayout/index.scss b/packages/web/src/scss/components/UNSTABLE_ActionLayout/index.scss new file mode 100644 index 0000000000..8af6f29576 --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_ActionLayout/index.scss @@ -0,0 +1 @@ +@forward 'UNSTABLE_ActionLayout'; diff --git a/packages/web/src/scss/components/UNSTABLE_EmptyState/README.md b/packages/web/src/scss/components/UNSTABLE_EmptyState/README.md new file mode 100644 index 0000000000..7f32e8412a --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_EmptyState/README.md @@ -0,0 +1,56 @@ +# UNSTABLE EmptyState + +⚠️ This component is UNSTABLE. It may significantly change at any point in the future. +Please use it with caution. + +EmptyState component should be included at the error pages or empty state pages as the carrier of an information and links to elsewhere. + +EmptyState component is a composition of the following components: + +- [UNSTABLE_EmptyState](#unstable-emptystate) + - [UNSTABLE_EmptyStateSection](#unstable-emptystatesection) + +## UNSTABLE EmptyState + +The `UNSTABLE_EmptyState` component is a main container responsible for positioning the [UNSTABLE_EmptyStateSection](#unstable-emptystatesection) components or content. + +```html +
+ +
+``` + +This component is based on the [Stack][stack] component and accepts all its variants. For more information about `Stack` usage options, see the [Stack documentation][stack]. + +## UNSTABLE EmptyStateSection + +The `UNSTABLE_EmptyStateSection` component is a container for the content of each section. + +```html +
+ +
+``` + +This component is based on the [Stack][stack] component and accepts all its variants. For more information about `Stack` usage options, see the [Stack documentation][stack]. + +[stack]: https://github.com/lmc-eu/spirit-design-system/blob/dependencies/major-monorepo-storybook/packages/web/src/scss/components/Stack/README.md + +## Full Example + +```html +
+
Placeholder
+
+

Headline

+

Description

+
+
+
+ Action + Action +
+
+ +
+``` diff --git a/packages/web/src/scss/components/UNSTABLE_EmptyState/_UNSTABLE_EmptyState.scss b/packages/web/src/scss/components/UNSTABLE_EmptyState/_UNSTABLE_EmptyState.scss new file mode 100644 index 0000000000..b1b4f4417b --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_EmptyState/_UNSTABLE_EmptyState.scss @@ -0,0 +1,23 @@ +@use 'sass:map'; +@use 'theme' as theme; +@use '../../tools/breakpoint'; + +.UNSTABLE_EmptyState { + display: flex; + flex-direction: column; + align-items: center; + padding: theme.$root-padding; + text-align: center; + + @include breakpoint.up(map.get(theme.$breakpoints, desktop)) { + padding: theme.$root-padding-desktop; + } +} + +.UNSTABLE_EmptyState__section { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + max-width: 400px; +} diff --git a/packages/web/src/scss/components/UNSTABLE_EmptyState/_theme.scss b/packages/web/src/scss/components/UNSTABLE_EmptyState/_theme.scss new file mode 100644 index 0000000000..7b259e65fc --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_EmptyState/_theme.scss @@ -0,0 +1,6 @@ +@use '@tokens' as tokens; + +$breakpoints: tokens.$breakpoints; +$root-padding: tokens.$space-1000 tokens.$space-700; +$root-padding-desktop: tokens.$space-1000 tokens.$space-800; +$buttons-gap: tokens.$space-600; diff --git a/packages/web/src/scss/components/UNSTABLE_EmptyState/index.html b/packages/web/src/scss/components/UNSTABLE_EmptyState/index.html new file mode 100644 index 0000000000..ebead8d278 --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_EmptyState/index.html @@ -0,0 +1,39 @@ +{{#> web/layout/plain }} + +
+

Default

+
+ +
+
+
+ + + + +
+
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 +
+
+ +
+ +
+
+ +{{/web/layout/plain }} diff --git a/packages/web/src/scss/components/UNSTABLE_EmptyState/index.scss b/packages/web/src/scss/components/UNSTABLE_EmptyState/index.scss new file mode 100644 index 0000000000..c604ead06c --- /dev/null +++ b/packages/web/src/scss/components/UNSTABLE_EmptyState/index.scss @@ -0,0 +1 @@ +@forward 'UNSTABLE_EmptyState'; diff --git a/packages/web/src/scss/components/index.scss b/packages/web/src/scss/components/index.scss index 77e4c00ed6..d43de63aef 100644 --- a/packages/web/src/scss/components/index.scss +++ b/packages/web/src/scss/components/index.scss @@ -24,6 +24,8 @@ @forward 'TextField'; @forward 'Toast'; @forward 'Tooltip'; +@forward 'UNSTABLE_ActionLayout'; @forward 'UNSTABLE_Avatar'; @forward 'UNSTABLE_Divider'; +@forward 'UNSTABLE_EmptyState'; @forward 'UNSTABLE_Slider'; diff --git a/tests/e2e/demo-components-compare.spec.ts-snapshots/unstable-actionlayout-chromium-linux.png b/tests/e2e/demo-components-compare.spec.ts-snapshots/unstable-actionlayout-chromium-linux.png new file mode 100644 index 0000000000..b5b8496ece Binary files /dev/null and b/tests/e2e/demo-components-compare.spec.ts-snapshots/unstable-actionlayout-chromium-linux.png differ diff --git a/tests/e2e/demo-components-compare.spec.ts-snapshots/unstable-emptystate-chromium-linux.png b/tests/e2e/demo-components-compare.spec.ts-snapshots/unstable-emptystate-chromium-linux.png new file mode 100644 index 0000000000..136cde82a9 Binary files /dev/null and b/tests/e2e/demo-components-compare.spec.ts-snapshots/unstable-emptystate-chromium-linux.png differ 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