From 6973c1a62818011123de0a797f7983f5bc781da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20H=C3=B8egh?= Date: Wed, 24 Apr 2024 22:47:52 +0200 Subject: [PATCH] feat(Visibility): add `keepInDOM` prop --- .../forms/Form/Visibility/properties.mdx | 19 +---- .../forms/Form/Visibility/Visibility.tsx | 24 +++++- .../forms/Form/Visibility/VisibilityDocs.ts | 74 +++++++++++++++++++ .../Visibility/__tests__/Visibility.test.tsx | 28 +++++++ .../Visibility/stories/Visibility.stories.tsx | 30 ++++++++ 5 files changed, 158 insertions(+), 17 deletions(-) create mode 100644 packages/dnb-eufemia/src/extensions/forms/Form/Visibility/VisibilityDocs.ts diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Visibility/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Visibility/properties.mdx index 67410abb301..9c660ed787d 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Visibility/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Visibility/properties.mdx @@ -2,20 +2,9 @@ showTabs: true --- +import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' +import { VisibilityProperties } from '@dnb/eufemia/src/extensions/forms/Form/Visibility/VisibilityDocs' + ## Properties -| Property | Type | Description | -| --------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------- | -| `visible` | `boolean` | _(optional)_ Control visibility directly by boolean value. | -| `animate` | `boolean` | _(optional)_ Define if the content should animate during show/hide. | -| `element` | `string` or `React.Element` | _(optional)_ Define the type of element. Defaults to `div`. Only for when `animate` is true. | -| `pathDefined` | `string` | _(optional)_ Given data context path must be defined to show children. | -| `pathUndefined` | `string` | _(optional)_ Given data context path must be undefined to show children. | -| `pathTruthy` | `string` | _(optional)_ Given data context path must be truthy to show children. | -| `pathFalsy` | `string` | _(optional)_ Given data context path must be falsy to show children. | -| `pathTrue` | `string` | _(optional)_ Given data context path must be true to show children. | -| `pathFalse` | `string` | _(optional)_ Given data context path must be false to show children. | -| `pathValue` | `string` | _(optional)_ Given data context path must match, as well as the `whenValue` value. | -| `whenValue` | `string` | _(optional)_ The value to match. Should be used together with `pathValue`. | -| `inferData` | `function` | _(optional)_ Will be called to decide by external logic, and show/hide contents based on the return value. | -| `children` | `React.Node` | _(required)_ Contents. | + diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/Visibility.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/Visibility.tsx index 0f6e7b082f6..301dd90ccbd 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/Visibility.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/Visibility.tsx @@ -27,6 +27,8 @@ export type Props = { inferData?: (data: unknown) => boolean /** Animate the visibility change */ animate?: boolean + /** Keep the content in the DOM, even if it's not visible */ + keepInDOM?: boolean element?: HeightAnimationProps['element'] children: React.ReactNode } @@ -43,6 +45,7 @@ function Visibility({ whenValue, inferData, animate, + keepInDOM, children, ...rest }: Props) { @@ -109,13 +112,30 @@ function Visibility({ if (animate) { return ( - + {children} ) } - return check() ? <>{children} : null + if (check()) { + return <>{children} + } + + if (keepInDOM) { + return ( + + ) + } + + return null } Visibility._supportsSpacingProps = 'children' diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/VisibilityDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/VisibilityDocs.ts new file mode 100644 index 00000000000..d62d6297d45 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/VisibilityDocs.ts @@ -0,0 +1,74 @@ +import { PropertiesTableProps } from '../../../../shared/types' + +export const VisibilityProperties: PropertiesTableProps = { + pathDefined: { + doc: 'Given data context path must be defined to show children.', + type: 'string', + status: 'optional', + }, + pathUndefined: { + doc: 'Given data context path must be undefined to show children.', + type: 'string', + status: 'optional', + }, + pathTruthy: { + doc: 'Given data context path must be truthy to show children.', + type: 'string', + status: 'optional', + }, + pathFalsy: { + doc: 'Given data context path must be falsy to show children.', + type: 'string', + status: 'optional', + }, + pathTrue: { + doc: 'Given data context path must be true to show children.', + type: 'string', + status: 'optional', + }, + pathFalse: { + doc: 'Given data context path must be false to show children.', + type: 'string', + status: 'optional', + }, + pathValue: { + doc: 'Given data context path must match, as well as the `whenValue` value.', + type: 'string', + status: 'optional', + }, + whenValue: { + doc: 'The value to match. Should be used together with `pathValue`.', + type: 'string', + status: 'optional', + }, + inferData: { + doc: 'Will be called to decide by external logic, and show/hide contents based on the return value.', + type: 'function', + status: 'optional', + }, + visible: { + doc: 'Control visibility directly by boolean value.', + type: 'boolean', + status: 'optional', + }, + animate: { + doc: 'Define if the content should animate during show/hide.', + type: 'boolean', + status: 'optional', + }, + KeepInDOM: { + doc: "Keep the content in the DOM, even if it's not visible", + type: 'boolean', + status: 'optional', + }, + element: { + doc: 'Define the type of element. Defaults to `div`. Only for when `animate` is true.', + type: 'string or React.Element', + status: 'optional', + }, + children: { + doc: 'Contents.', + type: 'React.Node', + status: 'required', + }, +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/__tests__/Visibility.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/__tests__/Visibility.test.tsx index 92e04767a87..56148d35ae9 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/__tests__/Visibility.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/__tests__/Visibility.test.tsx @@ -29,6 +29,34 @@ describe('Visibility', () => { }) }) + describe('keepInDOM', () => { + it('should keep content in the DOM surrounded with a hidden span', () => { + render( + + Child + + ) + expect(screen.getByText('Child')).toBeInTheDocument() + const element = document.querySelector('.dnb-forms-visibility') + expect(element).toBeInTheDocument() + expect(element).toHaveAttribute('hidden') + expect(element).toHaveTextContent('Child') + }) + + it('use HeightAnimation keepInDOM feature', () => { + render( + + Child + + ) + expect(screen.getByText('Child')).toBeInTheDocument() + const element = document.querySelector('.dnb-forms-visibility') + expect(element).toBeInTheDocument() + expect(element).toHaveClass('dnb-height-animation--hidden') + expect(element).toHaveTextContent('Child') + }) + }) + describe('pathDefined', () => { it('renders children when target path is defined', () => { render( diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/stories/Visibility.stories.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/stories/Visibility.stories.tsx index cba00b72848..a845be67819 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/stories/Visibility.stories.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Visibility/stories/Visibility.stories.tsx @@ -44,3 +44,33 @@ export const Toggle = () => { ) } + +export const KeepInDOM = () => { + const { data } = Form.useData(id, { + showError: true, + isVisible: true, + }) + + return ( + + + + + + + + bottom + + + ) +}