diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/card.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/card.mdx index 730f7b43971..cf50b26e679 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/card.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/card.mdx @@ -2,7 +2,7 @@ title: 'Card' description: '`Card` is a block section element showing the white box with rounded gray borders, adding spacing automatically.' showTabs: true -status: 'beta' +status: 'new' tabs: - title: Info key: '/info' diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/card/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/card/Examples.tsx index c5891832bcc..f6805a5f3c5 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/card/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/card/Examples.tsx @@ -32,6 +32,22 @@ export const Default = () => { ) } +export const NestedCards = () => { + return ( + + +

First Card

+ +

Second Card

+ +

Third Card (for edge cases only)

+
+
+
+
+ ) +} + export const WithTable = () => { return ( @@ -208,6 +224,16 @@ export const WithHeadingsAndAriaLabel = () => { ) } +export const WithoutPadding = () => { + return ( + + +

no inner space

+
+
+ ) +} + export const WithNestedSection = () => { return ( diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/card/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/card/demos.mdx index 5fe5a7c47c6..3c88104ef8b 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/card/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/card/demos.mdx @@ -20,8 +20,22 @@ import * as Examples from './Examples' ### Stack +The Card components needs to have `stack={true}` or `align="stretch"` in order to stretch its children components. + +For [form components](uilib/extensions/forms/), you should use `stack={true}` to get the correct spacing. + +### Nested Cards + +Nested cards have `responsive={false}` by default and will not behave responsive. + + + +### Without padding + + + ### With nested Section The Card components needs to have `stack={true}` or `align="stretch"` in order to stretch its children components. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/card/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/card/info.mdx index 9682dab71a8..04c4b11c3b4 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/card/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/card/info.mdx @@ -16,8 +16,6 @@ import { Card } from '@dnb/eufemia' It uses [Flex.Item](/uilib/layout/flex/item) under the hood. When one of these properties were given, `stack`, `direction` or `spacing` – the [Flex.Container](/uilib/layout/flex/container) will be used. -**BETA:** The design is not 100% finalised and may change to be officially approved by UX through an RFC. - ```jsx import { Card } from '@dnb/eufemia' import { Form, Field } from '@dnb/eufemia/extensions/forms' diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/country-flag/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/country-flag/info.mdx index 9c0c5baed6e..7c195cfe02f 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/country-flag/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/country-flag/info.mdx @@ -16,7 +16,7 @@ import '@dnb/eufemia/components/country-flag/style/dnb-country-flag-icons.scss' ## Description -The CountryFlag component lets you display a country flag based on a [ISO 3166-1 alpha-2 code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) like `NO` for Norway. +The `CountryFlag` component lets you display a country flag based on a [ISO 3166-1 alpha-2 code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) like `NO` for Norway. In order to use the CountryFlag component, you need to import the flag styles as CSS or SASS. The flag styles are available in the `dnb-country-flag-icons.min.css` and `dnb-country-flag-icons.scss` files. See the import example above. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/Examples.tsx index 8b8fc45386f..b078ef05d86 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/Examples.tsx @@ -361,3 +361,14 @@ export const DatePickerDateFnsRangeIsWeekend = () => ( /> ) + +export const DatePickerCorrectInvalidDate = () => ( + + + +) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/demos.mdx index a57b9af0a20..e7fbbd9dc7d 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/demos.mdx @@ -17,6 +17,7 @@ import { DatePickerCalendar, DatePickerScreenshotTestSizes, DatePickerScreenshotTestDisabled, + DatePickerCorrectInvalidDate, } from 'Docs/uilib/components/date-picker/Examples' import ChangeLocale from 'dnb-design-system-portal/src/core/ChangeLocale' @@ -81,6 +82,10 @@ import enUS from '@dnb/eufemia/shared/locales/en-US' +### Min and Max date correction + + + ### DatePicker with error status (no input) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/properties.mdx index 04e0596cbcd..a5812a1694c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/date-picker/properties.mdx @@ -35,7 +35,6 @@ import { | `link` | _(optional)_ link both calendars, once to the user is navigating between months. Only meant to use if the range is set to `true`. Defaults to `false`. | | `sync` | _(optional)_ sync input values with the calendars views. Once the input values get changed, the calendar changes its views in sync. Defaults to `true`. | | `first_day` | _(optional)_ to define the first day of the week. Defaults to `monday`. | -| `locale` | _(optional)_ to define the locale used in the calendar. Needs to be an `date-fns` **v2** locale object, like `import enLocale from 'date-fns/locale/en-GB'`. Defaults to `nb-NO`. | | `align_picker` | _(optional)_ use `right` to change the calendar alignment direction. Defaults to `left`. | | `only_month` | _(optional)_ use `true` to only show the defined month. Disables the month navigation possibility. Defaults to `false`. | | `hide_last_week` | _(optional)_ use `true` to only show the last week in the current month if it needs to be shown. The result is that there will mainly be shows five (5) weeks (rows) instead of six (6). Defaults to `false`. | diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/dialog/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/dialog/Examples.tsx index 30e54ec3de9..4b557ee8ef4 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/dialog/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/dialog/Examples.tsx @@ -168,8 +168,8 @@ export const DialogExampleProgressIndicator = () => ( maxWidth="12rem" > diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/Examples.tsx index 6a176de3bbd..141d43ee8f1 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/Examples.tsx @@ -9,14 +9,14 @@ import { FormLabel, Checkbox, Switch } from '@dnb/eufemia/src' export const Default = () => ( - Default horizontal FormLabel + Default horizontal FormLabel ) export const Vertical = () => ( - + Vertical FormLabel @@ -25,7 +25,7 @@ export const Vertical = () => ( export const NoForId = () => ( - Without for_id (select me) + Without forId (select me) ) @@ -35,7 +35,7 @@ export const LinkedLabel = () => (
- +
diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/demos.mdx index c1f6db9aa9f..e29266e7e40 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/form-label/demos.mdx @@ -14,7 +14,7 @@ import * as Examples from 'Docs/uilib/components/form-label/Examples' -### Vertical form-label without a `for_id` +### Vertical form-label without a `forId` diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/input/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/input/Examples.tsx index 7516d764bb6..2e390f17d80 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/input/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/input/Examples.tsx @@ -198,7 +198,7 @@ export const InputExampleSubmit = () => ( console.log(event) }} > - Label + Label + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/Examples.tsx new file mode 100644 index 00000000000..63696af81e5 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/Examples.tsx @@ -0,0 +1,221 @@ +/** + * UI lib Component Example + * + */ + +import React from 'react' +import ComponentBox from '../../../../shared/tags/ComponentBox' +import { Provider } from '@dnb/eufemia/src/shared' +import { ListFormat, P, Badge, Anchor } from '@dnb/eufemia/src' +import { listFormat } from '@dnb/eufemia/src/components/list-format/ListFormat' + +export const UsingListFormatFunction = () => { + return ( + + {listFormat( + [ + A, + <> + B + , + <>C, + 'D', + 123, + + Link to Eufemia's Github Repo + , + <> + Text Text + , + ], + { + format: { type: 'disjunction' }, + locale: 'en-US', + }, + )} + + ) +} + +export const WithValue = () => { + return ( + + A, + <> + B + , + <>C, + 'D', + 123, + + Link to Eufemia's Github Repo + , + <> + Text Text + , + ]} + /> + + ) +} + +export const WithChildren = () => { + return ( + + + A + <> + B + + <>C + <>D + 123 + + Link to Eufemia's Github Repo + + <> + Text Text + + + + ) +} + +export const WithCustomFormat = () => { + return ( + + + A, + <> + B + , + <>C, + 'D', + 123, + + Link to Eufemia's Github Repo + , + <> + Text Text + , + ]} + format={{ type: 'disjunction' }} + /> + + + ) +} + +export const Inline = () => { + return ( + +

+ This is before the component{' '} + + Link to Eufemia's Github Repo + , + <> + Text Text + , + ]} + />{' '} + This is after the component +

+
+ ) +} + +export const ListVariants = () => { + return ( + +

Ordered List:

+ +

Unordered List:

+ +
+ ) +} + +export const ListTypes = () => { + return ( + +

Ordered List a:

+ +

Ordered List A:

+ +

Ordered List i:

+ +

Ordered List I:

+ +

Unordered List square:

+ +

Unordered List circle:

+ +

Unordered List unstyled:

+ +
+ ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/demos.mdx new file mode 100644 index 00000000000..a29aed78fcb --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/demos.mdx @@ -0,0 +1,35 @@ +--- +showTabs: true +--- + +import * as Examples from './Examples' + +## Demos + +### Basic usage with `value` + + + +### Basic usage with `children` + + + +### Custom format + + + +### Inline + + + +### List variants + + + +### List types + + + +### Using listFormat function + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/info.mdx new file mode 100644 index 00000000000..df9f3d6fa8a --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/info.mdx @@ -0,0 +1,44 @@ +--- +showTabs: true +--- + +## Import + +```tsx +import { ListFormat } from '@dnb/eufemia' +``` + +## Description + +A ready-to-use list formatter. Use it wherever you have to display a list of strings, numbers, or React components (JSX). + +Good reasons for why we have this is to: + +- Uniform the creation and formatting of lists. +- Supports translation and localization. +- Built on top of web standards. + +The component is designed to maximum display 10-20 items. +If you need to display more items than that, consider a different design, and perhaps using [Pagination](/uilib/components/pagination) and/or [InfinityScroller](/uilib/components/pagination/infinity-scroller). + +When the `variant` property is set to `text` (default), the browser API [Intl.ListFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat) will be used with additional React components (JSX) support. + +When the `variant` is set to a non-`text` variant, it uses [Lists](/uilib/elements/lists/) to render the given list. + +## Formatting only + +You can use the `listFormat` function without using the React Component `ListFormat`, to format strings, numbers, or React components (JSX) as a string. It does not return lists(ol, ul, etc). + +```ts +import { listFormat } from '@dnb/eufemia/components/ListFormat' + +return listFormat(myList, { + format: { type: 'disjunction' }, + locale: 'en-US', +}) +``` + +See the following [demo](/uilib/components/list-format/demos/#using-listformat-function) for a more detailed example. + +The `listFormat` function supports an object with `{ format, locale }` as the second parameter. `format` and `locale` will accept the same values as documented in [properties](/uilib/components/list-format/properties/) of the `ListFormat` component. +The function does not support `variant` and `listType`, as it does not return a list, but rather return a string. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/properties.mdx new file mode 100644 index 00000000000..7c775a37788 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/list-format/properties.mdx @@ -0,0 +1,11 @@ +--- +showTabs: true +--- + +import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' +import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' +import { ListFormatProperties } from '@dnb/eufemia/src/components/list-format/ListFormatDocs' + +## Properties + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/radio/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/components/radio/Examples.tsx index 059d86c3156..b64a9272678 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/radio/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/radio/Examples.tsx @@ -82,7 +82,11 @@ export const RadioExampleGroupStatus = () => ( export const RadioExampleWithoutGroup = () => ( - + { +export function createMockFile(name: string, size: number, type: string) { const file = new File([], name, { type }) Object.defineProperty(file, 'size', { get() { @@ -304,7 +304,7 @@ export const UploadFileMaxSizeBasedOnFileTypeDisabled = () => ( ) export const UploadDisabledFileMaxSize = () => ( - + - - + ### Upload without title and text diff --git a/packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.mdx index dddd0336b7a..ab94ee47013 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/components/upload/info.mdx @@ -56,3 +56,9 @@ By default, the Upload component accepts multiple files. You can use the propert Once the Upload component mounts, it also adds support for dropping files to the entire browser body. **NB:** When you have several mounted components, only the first Upload component will receive the dropped files. + +## The `download` property + +Each file item is displayed as a clickable link with its original file name, which opens the file source in a new browser tab. + +In some situations, it's more suitable to have each link download the file instead of opening it in a new browser tab. To achieve this, set the `download={true}` property on the Upload component. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/EditContainer/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/EditContainer/info.mdx index eb269d0678c..796913dfacc 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/EditContainer/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/EditContainer/info.mdx @@ -29,6 +29,24 @@ render( ) ``` +## Customize the Toolbar + +```tsx +import { Form, Field } from '@dnb/eufemia/extensions/forms' + +render( + + + + + + + + + , +) +``` + ## Accessibility The `EditContainer` component has an `aria-label` attribute, which is set to the `title` property value. It uses a section element to wrap the content, which helps users with screen readers to get the needed announcement. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar.mdx new file mode 100644 index 00000000000..7af0f7e5532 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar.mdx @@ -0,0 +1,23 @@ +--- +title: 'Toolbar' +description: '`Form.Section.Toolbar` is a helper component to be used within an `Form.Section.ViewContainer` and `Form.Section.EditContainer`.' +showTabs: true +tabs: + - title: Info + key: '/info' + - title: Demos + key: '/demos' +breadcrumb: + - text: Forms + href: /uilib/extensions/forms/Form/ + - text: Section + href: /uilib/extensions/forms/Form/Section/ + - text: Toolbar + href: /uilib/extensions/forms/Form/Section/Toolbar/ +--- + +import Info from 'Docs/uilib/extensions/forms/Form/Section/Toolbar/info' +import Demos from 'Docs/uilib/extensions/forms/Form/Section/Toolbar/demos' + + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/Examples.tsx new file mode 100644 index 00000000000..c8ed8c1d207 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/Examples.tsx @@ -0,0 +1,28 @@ +import ComponentBox from '../../../../../../../shared/tags/ComponentBox' +import { Button } from '@dnb/eufemia/src' +import { Form } from '@dnb/eufemia/src/extensions/forms' + +export const ViewAndEditContainer = () => { + return ( + + + + View content + + + + + + + + Edit content + + + + + + + + + ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/demos.mdx new file mode 100644 index 00000000000..3b33440ca48 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/demos.mdx @@ -0,0 +1,12 @@ +--- +showTabs: true +hideInMenu: true +--- + +import * as Examples from './Examples' + +## Demos + +### Using ViewContainer and EditContainer + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/info.mdx new file mode 100644 index 00000000000..3d6fbd4a19b --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/info.mdx @@ -0,0 +1,35 @@ +--- +showTabs: true +hideInMenu: true +--- + +## Description + +`Form.Section.Toolbar` is a helper component to be used within the [Form.Section.ViewContainer](/uilib/extensions/forms/Form/Section/ViewContainer/) and the [Form.Section.EditContainer](/uilib/extensions/forms/Form/Section/EditContainer/). + +## Customize the Toolbar + +You can customize the toolbar by either passing a function as a child or as a JSX element: + +```tsx +import { Form } from '@dnb/eufemia/extensions/forms' + +render( + + + View content + + + + + + + Edit content + + + + + + , +) +``` diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/properties.mdx new file mode 100644 index 00000000000..4c6b34cdf4f --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/Toolbar/properties.mdx @@ -0,0 +1,11 @@ +--- +showTabs: true +hideInMenu: true +--- + +import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' +import { ToolbarProperties } from '@dnb/eufemia/src/extensions/forms/Form/Section/Toolbar/ToolbarDocs' + +## Properties + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/ViewContainer/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/ViewContainer/info.mdx index 0e125c96345..bdbb5b4d18c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/ViewContainer/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Section/ViewContainer/info.mdx @@ -25,6 +25,24 @@ render( ) ``` +## Customize the Toolbar + +```tsx +import { Form, Value } from '@dnb/eufemia/extensions/forms' + +render( + + + + + + + + + , +) +``` + ## Accessibility The `ViewContainer` component has an `aria-label` attribute, which is set to the `title` property value. It uses a section element to wrap the content, which helps users with screen readers to get the needed announcement. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/Examples.tsx index a8327e44591..9cdeec29890 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/Examples.tsx @@ -2,12 +2,12 @@ import ComponentBox from '../../../../../../shared/tags/ComponentBox' import { Button } from '@dnb/eufemia/src' import { Iterate } from '@dnb/eufemia/src/extensions/forms' -export const Default = () => { +export const AnimatedContainer = () => { return ( - Item Content + Item content @@ -17,3 +17,29 @@ export const Default = () => { ) } + +export const ViewAndEditContainer = () => { + return ( + + + + Item view content + + + + + + + + + Item edit content + + + + + + + + + ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/demos.mdx index 72408519158..99760ed3961 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/demos.mdx @@ -7,4 +7,10 @@ import * as Examples from './Examples' ## Demos - +### Using AnimatedContainer + + + +### Using ViewContainer and EditContainer + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/info.mdx index 065e0a078af..8fe19259c82 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/Toolbar/info.mdx @@ -34,17 +34,25 @@ import { Iterate } from '@dnb/eufemia/extensions/forms' render( - Item Content + Item view content + + + Item edit content + + + + + , ) ``` -The function receives the following parameters as an object: +You can also provide a function as a child. The function will provide the following parameters as an object: - `index` the index of the current item in the array. - `value` the value of the current item. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection.mdx index c39bba600a8..68466708218 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection.mdx @@ -2,7 +2,6 @@ title: 'ArraySelection' description: '`Value.ArraySelection` is a wrapper component for displaying string values, with user experience tailored for an array of selected values.' componentType: 'base-value' -hideInMenu: true showTabs: true tabs: - title: Info diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection/Examples.tsx index 31023053022..6a3e4aa8af7 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/ArraySelection/Examples.tsx @@ -97,9 +97,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This + is after the component

) @@ -124,7 +124,7 @@ export const ListVariants = () => { export const ListTypes = () => { return ( - + { variant="ul" listType="circle" /> + ) } diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/Examples.tsx index c41152ae037..10ab533a36b 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/BankAccountNumber/Examples.tsx @@ -46,9 +46,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is + after the component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/Examples.tsx index 7d6068be8b7..be9bac3c6ff 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/Examples.tsx @@ -54,8 +54,8 @@ export const Inline = () => { return (

- This is before the component - + This is before the component{' '} + {' '} This is after the component

diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/properties.mdx index 87697c9aa58..2677ff7dfa6 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Boolean/properties.mdx @@ -8,7 +8,7 @@ import { BooleanProperties } from '@dnb/eufemia/src/extensions/forms/Value/Boole ## Properties -### Field-specific properties +### Value-specific properties diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Currency/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Currency/Examples.tsx index 46df72cb8f2..ae7baf76f4c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Currency/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Currency/Examples.tsx @@ -54,9 +54,8 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is after the component

) @@ -66,9 +65,9 @@ export const InlineAndLabel = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is + after the component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/Examples.tsx index 441dfd1195b..36827ae7b35 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/Examples.tsx @@ -2,34 +2,10 @@ import ComponentBox from '../../../../../../shared/tags/ComponentBox' import { P } from '@dnb/eufemia/src' import { Value } from '@dnb/eufemia/src/extensions/forms' -export const Empty = () => { - return ( - - - - ) -} - -export const Placeholder = () => { - return ( - - - - ) -} - -export const WithValue = () => { - return ( - - - - ) -} - export const VariantShort = () => { return ( - + ) } @@ -37,15 +13,11 @@ export const VariantShort = () => { export const VariantNumeric = () => { return ( - - - ) -} - -export const Label = () => { - return ( - - + ) } @@ -62,9 +34,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is + after the component

) @@ -73,7 +45,7 @@ export const Inline = () => { export const Range = () => { return ( - + ) } diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/demos.mdx index 6f3721771fd..8bc8d0b5bf0 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Date/demos.mdx @@ -6,17 +6,9 @@ import * as Examples from './Examples' ## Demos -### Empty - - - -### Placeholder - - - -### Value +### Label and value - + ### Variant short @@ -26,14 +18,6 @@ import * as Examples from './Examples' -### Label - - - -### Label and value - - - ### Date range diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Email/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Email/Examples.tsx index d6dd117b9ed..1e3150e1521 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Email/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Email/Examples.tsx @@ -49,9 +49,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This + is after the component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Name/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Name/Examples.tsx index 0e4bfc8074d..56470d553de 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Name/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Name/Examples.tsx @@ -55,10 +55,10 @@ export const Inline = () => { }} >

- This is before the component - - - This is after the component + This is before the component{' '} + {' '} + This is after the + component

diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/NationalIdentityNumber/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/NationalIdentityNumber/Examples.tsx index 38081bdaa3a..b78f3e00120 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/NationalIdentityNumber/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/NationalIdentityNumber/Examples.tsx @@ -49,9 +49,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is + after the component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Number/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Number/Examples.tsx index 3d93ee330b9..3a8393e5338 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Number/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Number/Examples.tsx @@ -46,8 +46,7 @@ export const Inline = () => { return (

- This is before the component - + This is before the component {' '} This is after the component

diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/OrganizationNumber/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/OrganizationNumber/Examples.tsx index ef3319dff0c..34b7fd60e94 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/OrganizationNumber/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/OrganizationNumber/Examples.tsx @@ -46,9 +46,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is after + the component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PhoneNumber/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PhoneNumber/Examples.tsx index acecd524fec..34b2c4e3d04 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PhoneNumber/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PhoneNumber/Examples.tsx @@ -56,9 +56,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is after the + component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PostalCodeAndCity/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PostalCodeAndCity/Examples.tsx index f93193aa29c..af7580cfdc6 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PostalCodeAndCity/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/PostalCodeAndCity/Examples.tsx @@ -59,9 +59,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is after + the component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Provider.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Provider.mdx index 3e5454638b9..789ff9b41e5 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Provider.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Provider.mdx @@ -2,7 +2,6 @@ title: 'Provider' description: 'The `Value.Provider` lets you pass generic properties to all nested Value.* components.' componentType: 'base-value' -hideInMenu: true showTabs: true tabs: - title: Info diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry.mdx index 30e9f33a5e5..0313477b8a7 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry.mdx @@ -2,7 +2,6 @@ title: 'SelectCountry' description: '`Value.SelectCountry` will render the selected country.' componentType: 'base-value' -hideInMenu: true showTabs: true tabs: - title: Info diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry/Examples.tsx index 13b78bf884a..19bf6a4abac 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SelectCountry/Examples.tsx @@ -48,9 +48,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is after the + component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection.mdx index 4ebbe475a1e..58185fee709 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection.mdx @@ -2,7 +2,6 @@ title: 'Selection' description: '`Value.Selection` is a component for displaying a string value based on a user selection.' componentType: 'base-value' -hideInMenu: true showTabs: true tabs: - title: Info diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/Examples.tsx index c62e1808618..4889781f1e5 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/Examples.tsx @@ -38,8 +38,7 @@ export const Inline = () => { return (

- This is before the component - + This is before the component {' '} This is after the component

diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/properties.mdx index 7305e005660..5d46057df0a 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Selection/properties.mdx @@ -9,7 +9,7 @@ import { ValueProperties } from '@dnb/eufemia/src/extensions/forms/Value/ValueDo ## Properties -### Field-specific properties +### Value-specific properties diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/String/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/String/Examples.tsx index 054066552e5..9f2c52382d6 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/String/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/String/Examples.tsx @@ -46,9 +46,9 @@ export const Inline = () => { return (

- This is before the component - - This is after the component + This is before the component{' '} + This is after the + component

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SummaryList/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SummaryList/properties.mdx index 20454908506..d4398df79c6 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SummaryList/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/SummaryList/properties.mdx @@ -2,8 +2,6 @@ showTabs: true --- -## showTabs: true - import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' import { SummaryListProperties } from '@dnb/eufemia/src/extensions/forms/Value/SummaryList/SummaryListDocs' diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload.mdx new file mode 100644 index 00000000000..2f5ba725e3e --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload.mdx @@ -0,0 +1,26 @@ +--- +title: 'Upload' +description: '`Value.Upload` is a value component for displaying a list of files.' +componentType: 'feature-value' +showTabs: true +tabs: + - title: Info + key: '/info' + - title: Demos + key: '/demos' + - title: Properties + key: '/properties' +breadcrumb: + - text: Forms + href: /uilib/extensions/forms/ + - text: Value + href: /uilib/extensions/forms/Value/ + - text: Upload + href: /uilib/extensions/forms/Value/Upload/ +--- + +import Info from 'Docs/uilib/extensions/forms/Value/Upload/info' +import Demos from 'Docs/uilib/extensions/forms/Value/Upload/demos' + + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/Examples.tsx new file mode 100644 index 00000000000..97c24738739 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/Examples.tsx @@ -0,0 +1,395 @@ +import ComponentBox from '../../../../../../shared/tags/ComponentBox' +import { Form, Value, Field } from '@dnb/eufemia/src/extensions/forms' +import { Flex, Span } from '@dnb/eufemia/src' +import { createMockFile } from '../../../../../../docs/uilib/components/upload/Examples' + +export const Placeholder = () => { + return ( + + + + ) +} + +export const WithValue = () => { + return ( + + + + ) +} + +export const WithSize = () => { + return ( + + + + ) +} + +export const WithDownload = () => { + return ( + + + + ) +} + +export const WithCustomFormat = () => { + return ( + + + + + + ) +} + +export const FieldUploadSelectionPath = () => { + return ( + + + + + + + + + ) +} + +export const Label = () => { + return ( + + + + ) +} + +export const LabelAndValue = () => { + return ( + + + + ) +} + +export const Inline = () => { + return ( + + + This is before the component{' '} + {' '} + This is after the component + + + ) +} + +export const ListVariants = () => { + return ( + + + + + ) +} + +export const ListTypes = () => { + return ( + + + + + + + + + ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/demos.mdx new file mode 100644 index 00000000000..845ea216ee0 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/demos.mdx @@ -0,0 +1,51 @@ +--- +showTabs: true +--- + +import * as Examples from './Examples' + +## Demos + +### Placeholder + + + +### Value + + + +### With `displaySize` property + + + +### With `download` property + + + +### Custom format + + + +### Label + + + +### Label and value + + + +### Inline + + + +### List variants + + + +### List types + + + +### Field.Upload path + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/info.mdx new file mode 100644 index 00000000000..2bd0a26e60e --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/info.mdx @@ -0,0 +1,14 @@ +--- +showTabs: true +--- + +## Description + +`Value.Upload` is a value component for displaying a list of files. + +There is a corresponding [Field.Upload](/uilib/extensions/forms/feature-fields/more-fields/Upload) component. + +```jsx +import { Value } from '@dnb/eufemia/extensions/forms' +render() +``` diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/properties.mdx new file mode 100644 index 00000000000..a47f5154732 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Value/Upload/properties.mdx @@ -0,0 +1,20 @@ +--- +showTabs: true +--- + +import { UploadProperties } from '@dnb/eufemia/src/extensions/forms/Value/Upload/UploadDocs' +import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' +import { ValueProperties } from '@dnb/eufemia/src/extensions/forms/Value/ValueDocs' + +## Properties + +### Value-specific properties + + + +### General properties + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx index bf29b3dd6d9..31235d5a664 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/Examples.tsx @@ -170,15 +170,21 @@ export const CheckboxWithHelp = () => ( ) export const CheckboxNestingWithLogic = () => ( - - + + - + { @@ -187,10 +193,11 @@ export const CheckboxNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth >
- +
@@ -199,7 +206,6 @@ export const CheckboxNestingWithLogic = () => ( title="Show additional option" /> { @@ -208,7 +214,8 @@ export const CheckboxNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth > ( }} >
- +
+ +
) @@ -303,6 +312,26 @@ export const CheckboxButtonEmpty = () => (
) +export const CheckboxButtonHorizontalOptionsLayout = () => ( + + console.log('onChange', values)} + > + + + + + + + + + +) + export const ButtonLabel = () => ( ( { @@ -485,7 +513,8 @@ export const ButtonNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth >
@@ -497,7 +526,6 @@ export const ButtonNestingWithLogic = () => ( title="Show additional option" /> { @@ -506,7 +534,8 @@ export const ButtonNestingWithLogic = () => ( : false }, }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth > + +#### Button with checkbox variant + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/properties.mdx index 5637b6c6a94..c1d837f46ff 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/ArraySelection/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' import { arraySelectionProperties } from '@dnb/eufemia/src/extensions/forms/Field/ArraySelection/ArraySelectionDocs' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Properties @@ -15,6 +15,6 @@ import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDo ### General properties diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/properties.mdx index cb9a1651248..eadb92e032f 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Boolean/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { BooleanProperties } from '@dnb/eufemia/src/extensions/forms/Field/Boolean/BooleanDocs' ## Properties @@ -15,7 +15,11 @@ import { BooleanProperties } from '@dnb/eufemia/src/extensions/forms/Field/Boole ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Indeterminate/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Indeterminate/properties.mdx index 4f1df6fc421..bacd3bbd3cc 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Indeterminate/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Indeterminate/properties.mdx @@ -3,7 +3,7 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { IndeterminateProperties } from '@dnb/eufemia/src/extensions/forms/Field/Indeterminate/IndeterminateDocs' ## Properties @@ -14,4 +14,4 @@ import { IndeterminateProperties } from '@dnb/eufemia/src/extensions/forms/Field ### General properties - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/Examples.tsx index 2b5f829a1c1..116d955d18f 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/Examples.tsx @@ -1,50 +1,111 @@ import ComponentBox from '../../../../../../shared/tags/ComponentBox' -import { Slider, Grid, Flex } from '@dnb/eufemia/src' +import { Slider, Grid, Flex, Card } from '@dnb/eufemia/src' import { Field, Form } from '@dnb/eufemia/src/extensions/forms' import React from 'react' -export const Empty = () => { +export const Placeholder = () => { return ( - + console.log('onFocus', value)} - onBlur={(value) => console.log('onBlur', value)} + label="Label text" + placeholder="Enter a number..." onChange={(value) => console.log('onChange', value)} /> ) } -export const Placeholder = () => { +export const LabelAndValue = () => { return ( console.log('onChange', value)} /> ) } -export const Label = () => { +export const LabelAndDescription = () => { return ( - - console.log('onChange', value)} - /> + + + + + ) } -export const LabelAndValue = () => { +export const WithStatus = () => { return ( - - console.log('onChange', value)} - /> + + + + + + + + ) +} + +export const HorizontalLayout = () => { + return ( + + + + + + + + ) } @@ -53,7 +114,7 @@ export const ExclusiveMinMax = () => { return ( { console.log('onChange', value)} /> (value === 1 ? ' year' : ' years')} onChange={(value) => console.log('onChange', value)} @@ -89,24 +150,26 @@ export const PrefixAndSuffix = () => { export const Alignment = () => { return ( - console.log('onChange', value)} - /> - console.log('onChange', value)} - /> - console.log('onChange', value)} - /> + + console.log('onChange', value)} + /> + console.log('onChange', value)} + /> + console.log('onChange', value)} + /> + ) } @@ -115,7 +178,7 @@ export const WithHelp = () => { return ( { ) } -export const HorizontalLayout = () => { - return ( - - console.log('onChange', value)} - /> - - ) -} - export const Widths = () => { return ( @@ -149,52 +199,56 @@ export const Widths = () => { - + - + With step controls @@ -206,7 +260,7 @@ export const Disabled = () => { return ( console.log('onChange', value)} disabled @@ -215,51 +269,12 @@ export const Disabled = () => { ) } -export const Info = () => { - return ( - - console.log('onChange', value)} - info="Useful information (?)" - /> - - ) -} - -export const Warning = () => { - return ( - - console.log('onChange', value)} - warning="I'm warning you..." - /> - - ) -} - -export const WithError = () => { - return ( - - console.log('onChange', value)} - error={new Error('This is what is wrong...')} - /> - - ) -} - export const ValidateRequired = () => { return ( console.log('onChange', value)} required /> @@ -271,7 +286,7 @@ export const ValidateMinimum = () => { return ( console.log('onChange', value)} minimum={250} @@ -301,7 +316,7 @@ export const Percentage = () => { console.log('onChange', value)} minimum={90} @@ -314,13 +329,13 @@ export const ValidateMaximumCustomError = () => { return ( console.log('onChange', value)} + defaultValue={200} maximum={250} errorMessages={{ maximum: "You can't enter a number THAR large.. Max 250!", }} + onChange={(value) => console.log('onChange', value)} /> ) @@ -329,11 +344,12 @@ export const ValidateMaximumCustomError = () => { export const WithStepControls = () => ( ) @@ -341,9 +357,10 @@ export const WithStepControls = () => ( export const WithStepControlsError = () => ( @@ -351,7 +368,7 @@ export const WithStepControlsError = () => ( export const WithStepControlsDisabled = () => ( - + ) @@ -375,6 +392,7 @@ export const WithSlider = () => ( }} > + +### Label and description + + + +### With a horizontal layout - +This example uses [Field.Provider](/uilib/extensions/forms/feature-fields/Provider/) to set the `layout` to `horizontal` and `layoutOptions` to `{ width: 'medium' }` for all nested fields. + +The `width` of the horizontal label can be set to `small`, `medium`, `large` or a `rem` value. + + ### Placeholder -### Label +### With a status - +This example demonstrates how the status message width adjusts according to the field width. -### Label and value + - +#### With help + + ### Exclusive minimum and exclusive maximum @@ -36,10 +50,6 @@ You can also use a function as a prefix or suffix. -### Horizontal layout - - - ### With help @@ -56,18 +66,6 @@ You can also use a function as a prefix or suffix. -### Info - - - -### Warning - - - -### Error - - - ### Validation - Required diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/properties.mdx index 5d99e086cdd..9cf3989809c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Number/properties.mdx @@ -5,7 +5,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' import { numberProperties } from '@dnb/eufemia/src/extensions/forms/Field/Number/NumberDocs' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Properties @@ -15,7 +15,7 @@ import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDo ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/Examples.tsx index 191a9e463be..9f3614c0e20 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/Examples.tsx @@ -483,23 +483,24 @@ export const RadioWithAPath = () => ( ) export const RadioNestingWithLogic = () => ( - - + +
- +
( title="Show additional option" /> value === 'showAdditionalOption' || value === 'showMeMore', }} - compensateForGap="auto" + animate + compensateForGap="auto" // makes animation smooth > ( }} >
- +
+ + + + +) + +export const RadioNestingAdvanced = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx index 44af5827822..3bc5bff81ce 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/demos.mdx @@ -124,12 +124,6 @@ As there are many variants, they are split into separate sections. Here is a sum -#### Radio nesting other fields with logic - -You can nest other fields and show them based on your desired logic. - - - #### Radio button with a path to populate the data @@ -138,6 +132,16 @@ You can nest other fields and show them based on your desired logic. +#### Radio nesting other fields with logic + +You can nest other fields and show them based on your desired logic. + + + +#### Radio nesting advanced + + + --- ### Buttons variant diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/properties.mdx index 3238f63420c..494e58b0c48 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Selection/properties.mdx @@ -3,7 +3,7 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { SelectionProperties } from '@dnb/eufemia/src/extensions/forms/Field/Selection/SelectionDocs' ## Properties @@ -14,4 +14,4 @@ import { SelectionProperties } from '@dnb/eufemia/src/extensions/forms/Field/Sel ### General properties - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/Examples.tsx index f6ea1a04c04..2a5b1af16d0 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/Examples.tsx @@ -7,48 +7,103 @@ import { Value, } from '@dnb/eufemia/src/extensions/forms' -export const Empty = () => { +export const Placeholder = () => { return ( console.log('onFocus', value)} - onBlur={(value) => console.log('onBlur', value)} + label="Label text" + placeholder="Enter a text..." onChange={(value) => console.log('onChange', value)} /> ) } -export const Placeholder = () => { +export const LabelAndValue = () => { return ( console.log('onChange', value)} /> ) } -export const Label = () => { +export const LabelAndDescription = () => { return ( - - console.log('onChange', value)} - /> + + + + + ) } -export const LabelAndValue = () => { +export const WithStatus = () => { return ( - - console.log('onChange', value)} - /> + + + + + + + + ) +} + +export const HorizontalLayout = () => { + return ( + + + + + + + + ) } @@ -58,7 +113,7 @@ export const WithHelp = () => { { console.log('onChange', value)} /> @@ -83,50 +138,52 @@ export const Capitalize = () => { ) } -export const HorizontalLayout = () => { - return ( - - console.log('onChange', value)} - /> - - ) -} - export const Widths = () => { return ( - - - - - + + + + + + - - - + + @@ -138,18 +195,20 @@ export const Widths = () => { export const Icons = () => { return ( - console.log('onChange', value)} - /> - console.log('onChange', value)} - /> + + console.log('onChange', value)} + /> + console.log('onChange', value)} + /> + ) } @@ -158,7 +217,7 @@ export const Clear = () => { return ( console.log('onChange', value)} clear /> @@ -170,7 +229,7 @@ export const Disabled = () => { return ( console.log('onChange', value)} disabled @@ -179,38 +238,12 @@ export const Disabled = () => { ) } -export const Info = () => { - return ( - - console.log('onChange', value)} - info="Useful information (?)" - /> - - ) -} - -export const Warning = () => { - return ( - - console.log('onChange', value)} - warning="I'm warning you..." - /> - - ) -} - export const WithMultipleError = () => { return ( { return ( console.log('onChange', value)} required @@ -236,7 +269,7 @@ export const ValidateMinimumLength = () => { return ( console.log('onChange', value)} minLength={8} @@ -249,7 +282,7 @@ export const ValidateMaximumLengthCustomError = () => { return ( console.log('onChange', value)} maxLength={8} @@ -265,7 +298,7 @@ export const ValidatePattern = () => { return ( console.log('onChange', value)} pattern="^foo123" @@ -278,7 +311,7 @@ export const SynchronousExternalValidator = () => { return ( value.length < 4 ? Error('At least 4 characters') : undefined @@ -293,7 +326,7 @@ export const AsynchronousExternalValidator = () => { return ( new Promise((resolve) => @@ -318,7 +351,7 @@ export const SynchronousExternalBlurValidator = () => { return ( value.length < 4 ? Error('At least 4 characters') : undefined @@ -333,7 +366,7 @@ export const AsynchronousExternalBlurValidator = () => { return ( new Promise((resolve) => @@ -395,7 +428,7 @@ export const MultipleLabelAndValue = () => { return ( console.log('onChange', value)} multiline diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/demos.mdx index 75bcd191a8f..8694985c37e 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/demos.mdx @@ -6,33 +6,39 @@ import * as Examples from './Examples' ## Demos -### Empty +### Label and value - + -### Placeholder +### Label and description - + -### Label +### With a horizontal layout - +This example uses [Field.Provider](/uilib/extensions/forms/feature-fields/Provider/) to set the `layout` to `horizontal` and `layoutOptions` to `{ width: 'medium' }` for all nested fields. -### Label and value +The `width` of the horizontal label can be set to `small`, `medium`, `large` or a `rem` value. - + -### Capitalize each word +### Placeholder - + + +### With a status + +This example demonstrates how the status message width adjusts according to the field width. + + #### With help -### Horizontal layout +### Capitalize each word - + ### Icons @@ -46,14 +52,6 @@ import * as Examples from './Examples' -### Info - - - -### Warning - - - ### Validation - Required diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/properties.mdx index b2b07cedcf1..c084239a0c7 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/String/properties.mdx @@ -5,7 +5,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' import { stringProperties } from '@dnb/eufemia/src/extensions/forms/Field/String/StringDocs' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Properties @@ -15,7 +15,7 @@ import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDo ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/Examples.tsx index fb08efd073b..0f49b06699e 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/Examples.tsx @@ -31,14 +31,32 @@ export const ValueOff = () => { ) } -export const NoValue = () => { +export const TextOn = () => { return ( console.log('onChange', value)} + /> + + ) +} + +export const TextOff = () => { + return ( + + console.log('onChange', value)} /> diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/demos.mdx index 67341c0883c..58103d2bd5b 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/demos.mdx @@ -6,17 +6,21 @@ import * as Examples from './Examples' ## Demos -### On state +### Value On -### Off state +### Value Off -### No value +### Text On - + + +### Text Off + + ### Disabled diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/properties.mdx index b49ba93f255..0f61925eb22 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/base-fields/Toggle/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { ToggleProperties } from '@dnb/eufemia/src/extensions/forms/Field/Toggle/ToggleDocs' ## Properties @@ -15,7 +15,11 @@ import { ToggleProperties } from '@dnb/eufemia/src/extensions/forms/Field/Toggle ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/changelog.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/changelog.mdx index fe03c63d274..00dbc910fb1 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/changelog.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/changelog.mdx @@ -13,6 +13,20 @@ breadcrumb: Change log for the Eufemia Forms extension. +## v10.55 + +- Added `transformLabel` to [Value.Composition](/uilib/extensions/forms/Value/Composition/). +- Added [Value.Upload](/uilib/extensions/forms/Value/Upload/) component to render file values. +- Added Iterate support for [Field.PostalCodeAndCity](/uilib/extensions/forms/feature-fields/PostalCodeAndCity/) when using `country` with a path. +- Added `layoutOptions` for enhanced horizontal label layout in [Field.Provider](/uilib/extensions/forms/feature-fields/Provider/). +- Added `EditButton`, `CancelButton` and `DoneButton` to [Form.Section](/uilib/extensions/forms/Form/Section/) containers. +- Added maximum possible value to joint-responsibility & daycare fields in [Block.ChildrenWithAge](/uilib/extensions/forms/blocks/ChildrenWithAge/). +- Fixed vertical gap between [Field.ArraySelection](/uilib/extensions/forms/base-fields/ArraySelection/) toggle buttons with checkbox variant. +- Fixed so [Field.Number](/uilib/extensions/forms/base-fields/Number/) with `percent` and without a value renders correctly. +- Fixed so components having `fieldset` inside still can use spacing. +- Fixed so there's no extra space from Value.\* components when using `inline` property. +- Fixed so errors display underneath fields when nested inside [Field.Selection](/uilib/extensions/forms/base-fields/Selection/) or [Field.ArraySelection](/uilib/extensions/forms/base-fields/ArraySelection/). + ## v10.54 - Deprecated Ajv `validationRule` in [FormError](/uilib/extensions/forms/Form/error-messages/info/#error-messages) and deprecated `errorMessages` keys like `pattern` in favor of Eufemia translation keys like `Field.errorPattern`. For a migration guide, take a look at [release notes for the future major release, v11](/uilib/about-the-lib/releases/eufemia/v11-info/#forms-error-handling). diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component.mdx index 87e419b8c0d..3063e572344 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component.mdx @@ -63,7 +63,6 @@ const MyField = (props) => { const { id, value, - label, handleChange, handleFocus, handleBlur, @@ -71,7 +70,10 @@ const MyField = (props) => { } = useFieldProps(props) return ( - + { ) } -render() +render() ``` The `useFieldProps` provides a standardized way to handle data flow, validation and error messages in a consistent manner. @@ -190,6 +192,7 @@ const myFieldTranslations = { }, }, } + type Translation = (typeof myFieldTranslations)[keyof typeof myFieldTranslations] @@ -207,7 +210,7 @@ const MyField = (props) => { ...props, } - const { id, value, label, handleChange, handleFocus, handleBlur } = + const { id, value, handleChange, handleFocus, handleBlur } = useFieldProps(preparedProps) return ( @@ -215,7 +218,6 @@ const MyField = (props) => { + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock.mdx index 14c627cb905..9ae0f87956c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock.mdx @@ -6,6 +6,8 @@ showTabs: true tabs: - title: Info key: '/info' + - title: Demos + key: '/demos' - title: Properties key: '/properties' breadcrumb: diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock/Examples.tsx index 74ca798045f..b954f4b2cac 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/ValueBlock/Examples.tsx @@ -17,10 +17,8 @@ export const Inline = () => { data-visual-test="value-block-inline" >

- this is before the value - Foo - Bar - this is after the value + this is before the value Foo{' '} + Bar this is after the value

) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/properties.mdx index 8f084a5f553..cc25a2cb627 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/BankAccountNumber/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { BankAccountNumberProperties } from '@dnb/eufemia/src/extensions/forms/Field/BankAccountNumber/BankAccountNumberDocs' ## Properties @@ -15,7 +15,7 @@ import { BankAccountNumberProperties } from '@dnb/eufemia/src/extensions/forms/F ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/properties.mdx index e91b102858c..c84b31d0a5a 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Currency/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { numberProperties } from '@dnb/eufemia/src/extensions/forms/Field/Number/NumberDocs' ## Properties @@ -15,7 +15,7 @@ import { numberProperties } from '@dnb/eufemia/src/extensions/forms/Field/Number ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/Examples.tsx index 88fbe0bc429..d69621c62d7 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/Examples.tsx @@ -1,43 +1,27 @@ import ComponentBox from '../../../../../../shared/tags/ComponentBox' import { Field } from '@dnb/eufemia/src/extensions/forms' -export const Empty = () => { - return ( - - console.log('onChange', value)} /> - - ) -} - -export const Placeholder = () => { - return ( - - console.log('onChange', value)} - /> - - ) -} - -export const Label = () => { +export const LabelAndValue = () => { return ( - + console.log('onChange', value)} /> ) } -export const LabelAndValue = () => { +export const HorizontalLayout = () => { return ( - + console.log('onChange', value)} + label="Label with a long text that will wrap" + layout="horizontal" + layoutOptions={{ + width: 'medium', // can be a rem value + }} /> ) @@ -47,8 +31,8 @@ export const WithHelp = () => { return ( { return ( console.log('onChange', value)} disabled /> @@ -90,8 +74,8 @@ export const ValidationRequired = () => { return ( console.log('onChange', value)} required /> @@ -102,7 +86,7 @@ export const ValidationRequired = () => { export const Range = () => { return ( - + ) } diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/demos.mdx index ba911f25843..77f7380dc9a 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/demos.mdx @@ -6,22 +6,14 @@ import * as Examples from './Examples' ## Demos -### Empty - - - -### Placeholder - - - -### Label - - - ### Label and value +### With a horizontal layout + + + ### Date range diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/properties.mdx index 8f007bf02ad..aa31336c7d4 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Date/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { DateProperties } from '@dnb/eufemia/src/extensions/forms/Field/Date/DateDocs' ## Properties @@ -15,7 +15,7 @@ import { DateProperties } from '@dnb/eufemia/src/extensions/forms/Field/Date/Dat ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/properties.mdx index 6fe0339bd1b..9564b0633b0 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Email/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Properties @@ -17,7 +17,7 @@ import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDo ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/Examples.tsx index 3873e710e4a..08b9826e71b 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/Examples.tsx @@ -23,6 +23,20 @@ export const Label = () => { ) } +export const HorizontalLayout = () => { + return ( + + + + ) +} + export const WithHelp = () => { return ( diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/demos.mdx index 4fc6e3be2db..73331290342 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/demos.mdx @@ -34,6 +34,10 @@ import enUS from '@dnb/eufemia/shared/locales/en-US' +### With a horizontal layout + + + ### With help diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/events.mdx index cf15aafb702..52b4899acb8 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/events.mdx @@ -3,7 +3,7 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/properties.mdx index a49052df6b8..9f2fe64a70e 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Expiry/properties.mdx @@ -4,13 +4,13 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Properties ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/properties.mdx index 48136440543..05e136fc093 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/Name/properties.mdx @@ -4,13 +4,13 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Properties ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx index a85c9c0780e..9f56cda9cca 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/NationalIdentityNumber/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { NationalIdentityNumberProperties } from '@dnb/eufemia/src/extensions/forms/Field/NationalIdentityNumber/NationalIdentityNumberDocs' ## Properties @@ -15,7 +15,7 @@ import { NationalIdentityNumberProperties } from '@dnb/eufemia/src/extensions/fo ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/properties.mdx index 8db85d4f5e7..8a91acd1611 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/OrganizationNumber/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { OrganizationNumberProperties } from '@dnb/eufemia/src/extensions/forms/Field/OrganizationNumber/OrganizationNumberDocs' ## Properties @@ -15,7 +15,7 @@ import { OrganizationNumberProperties } from '@dnb/eufemia/src/extensions/forms/ ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/properties.mdx index af45b67f4fb..7b09b38268e 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PhoneNumber/properties.mdx @@ -4,20 +4,20 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' -import { phoneNumberSpecificProperties } from '@dnb/eufemia/src/extensions/forms/Field/PhoneNumber/PhoneNumberDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { PhoneNumberProperties } from '@dnb/eufemia/src/extensions/forms/Field/PhoneNumber/PhoneNumberDocs' ## Properties ### Field-specific properties - + ### General properties ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx index cae26b66b72..2f6f1b63ac4 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/PostalCodeAndCity/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldBlockProperties } from '@dnb/eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs' +import { FieldBlockProperties } from '@dnb/eufemia/src/extensions/forms/FieldBlock/FieldBlockDocs' import { PostalCodeAndCityProperties } from '@dnb/eufemia/src/extensions/forms/Field/PostalCodeAndCity/PostalCodeAndCityDocs' ## Properties @@ -15,7 +15,7 @@ import { PostalCodeAndCityProperties } from '@dnb/eufemia/src/extensions/forms/F ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/Examples.tsx index f80b8d8ac48..350d848539f 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/Examples.tsx @@ -7,43 +7,9 @@ import { Value, } from '@dnb/eufemia/src/extensions/forms' -export const Empty = () => { - return ( - - console.log('onChange', value, obj)} - onBlur={(value, obj) => console.log('onBlur', value, obj)} - onFocus={(value, obj) => console.log('onFocus', value, obj)} - /> - - ) -} - -export const Placeholder = () => { - return ( - - console.log('onChange', value, obj)} - /> - - ) -} - -export const Label = () => { - return ( - - console.log('onChange', value, obj)} - /> - - ) -} - export const OptionSelected = () => { return ( - + console.log('onChange', value, obj)} @@ -52,13 +18,13 @@ export const OptionSelected = () => { ) } -export const LabelAndOptionSelected = () => { +export const HorizontalLayout = () => { return ( - + console.log('onChange', value, obj)} + layout="horizontal" + layoutOptions={{ width: '6rem' }} /> ) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/demos.mdx index 75ce751d441..df25366f028 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/demos.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/demos.mdx @@ -6,25 +6,13 @@ import * as Examples from './Examples' ## Demos -### Empty - - - -### Placeholder - - - -### Label - - - ### Option selected -### Label and option selected +### With a horizontal layout - + ### With help diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/properties.mdx index e834f25ee45..d52eab3f41a 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/SelectCountry/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { SelectCountryProperties } from '@dnb/eufemia/src/extensions/forms/Field/SelectCountry/SelectCountryDocs' ### Field-specific properties @@ -13,7 +13,7 @@ import { SelectCountryProperties } from '@dnb/eufemia/src/extensions/forms/Field ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/events.mdx index f98612854e2..48c4fe83ca4 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/events.mdx @@ -3,11 +3,11 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + ## Password visibility events diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/properties.mdx index 1216c417fe9..81aa9c01312 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Password/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Properties @@ -20,10 +20,7 @@ import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDo ### General properties - + ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/events.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/events.mdx index cbb99af227b..fe7fe176333 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/events.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/events.mdx @@ -3,8 +3,8 @@ showTabs: true --- import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldEvents } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' ## Events - + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/properties.mdx index 2d1eed6a726..433ef1e53bd 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Slider/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { SliderFieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/Slider/SliderDocs' ## Properties @@ -16,7 +16,7 @@ import { SliderFieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/S ### General properties ']} /> diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/Examples.tsx index 1d0f2e47528..785b9e4a226 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/Examples.tsx @@ -1,6 +1,7 @@ import { Flex } from '@dnb/eufemia/src' import ComponentBox from '../../../../../../../shared/tags/ComponentBox' import { Field, Form } from '@dnb/eufemia/src/extensions/forms' +import { createMockFile } from '../../../../../../../docs/uilib/components/upload/Examples' export const BasicUsage = () => { return ( @@ -62,16 +63,6 @@ export const Customized = () => { } export const WithPath = () => { - const createMockFile = (name: string, size: number, type: string) => { - const file = new File([], name, { type }) - Object.defineProperty(file, 'size', { - get() { - return size - }, - }) - return file - } - return ( ) ``` +There is a corresponding [Value.Upload](/uilib/extensions/forms/Value/Upload) component. + ## The data and file format The returned data is an array of objects containing a file object and a unique ID. The file object contains the file itself and some additional properties like an unique ID. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/properties.mdx index 5c6e4a259ea..eabce28c4b4 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/feature-fields/more-fields/Upload/properties.mdx @@ -4,7 +4,7 @@ showTabs: true import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable' import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' -import { fieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' +import { FieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/FieldDocs' import { UploadFieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/Upload/UploadDocs' ## Properties @@ -16,9 +16,9 @@ import { UploadFieldProperties } from '@dnb/eufemia/src/extensions/forms/Field/U ### General properties ']} - omit={['layout', 'onBlurValidator', 'contentWidth']} + omit={['layout', 'layoutOptions', 'onBlurValidator', 'contentWidth']} /> ## Translations diff --git a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/stack/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/stack/properties.mdx index 7032c52fbbe..31b4f75bf6a 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/stack/properties.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/stack/properties.mdx @@ -2,11 +2,9 @@ showTabs: true --- +import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable' +import { FlexStackProperties } from '@dnb/eufemia/src/components/flex/StackDocs' + ## Properties -| Property | Type | Description | -| ---------------------------------------------- | -------- | --------------------------------------------------------------------- | -| `direction` | `string` | _(optional)_ Defaults to `vertical`. | -| `align` | `string` | _(optional)_ Defaults to `stretch`. | -| [Flex.Container](/uilib/layout/flex/container) | Various | _(optional)_ Flex.Container properties. | -| [Space](/uilib/layout/space/properties) | Various | _(optional)_ Spacing properties like `top` or `bottom` are supported. | + diff --git a/packages/dnb-design-system-portal/src/shared/menu/MainMenu.js b/packages/dnb-design-system-portal/src/shared/menu/MainMenu.js index 6e23808bdd0..e999ecbc075 100644 --- a/packages/dnb-design-system-portal/src/shared/menu/MainMenu.js +++ b/packages/dnb-design-system-portal/src/shared/menu/MainMenu.js @@ -100,55 +100,55 @@ function MainMenu() { +
    + + {items['design-system']?.description} + + Updated: {packageJson.changelogVersion} + + + } + icon={DesignSystemSvg} + /> + + + + + +
-
    - - {items['design-system']?.description} - - Updated: {packageJson.changelogVersion} - - - } - icon={DesignSystemSvg} - /> - - - - - -
diff --git a/packages/dnb-eufemia/src/components/anchor/Anchor.tsx b/packages/dnb-eufemia/src/components/anchor/Anchor.tsx index 864f416e5a2..140b0297530 100644 --- a/packages/dnb-eufemia/src/components/anchor/Anchor.tsx +++ b/packages/dnb-eufemia/src/components/anchor/Anchor.tsx @@ -126,6 +126,7 @@ export function AnchorInstance(localProps: AnchorAllProps) { const showLaunchIcon = _opensNewTab && !className?.includes('dnb-anchor--no-icon') && + !className?.includes('dnb-anchor--no-launch-icon') && !omitClass const showTooltip = (tooltip || _opensNewTab) && !allProps.title diff --git a/packages/dnb-eufemia/src/components/anchor/__tests__/Anchor.test.tsx b/packages/dnb-eufemia/src/components/anchor/__tests__/Anchor.test.tsx index 4416f5a7e6f..c0e4ccff1d7 100644 --- a/packages/dnb-eufemia/src/components/anchor/__tests__/Anchor.test.tsx +++ b/packages/dnb-eufemia/src/components/anchor/__tests__/Anchor.test.tsx @@ -117,6 +117,21 @@ describe('Anchor element', () => { ).not.toBeInTheDocument() }) + it('has no "__launch-icon" class when adding class dnb-anchor--no-launch-icon', () => { + render( + + text + + ) + expect( + document.querySelector('.dnb-anchor--launch-icon') + ).not.toBeInTheDocument() + }) + it('has no tooltip when title was given', () => { render( diff --git a/packages/dnb-eufemia/src/components/autocomplete/Autocomplete.js b/packages/dnb-eufemia/src/components/autocomplete/Autocomplete.js index cc5fa553fe0..37f26b72068 100644 --- a/packages/dnb-eufemia/src/components/autocomplete/Autocomplete.js +++ b/packages/dnb-eufemia/src/components/autocomplete/Autocomplete.js @@ -1968,10 +1968,10 @@ class AutocompleteInstance extends React.PureComponent { {label && ( , 'ref' | 'wrap' | 'size' | 'title'> function Card(props: Props) { + const nestedContext = useContext(CardContext) + const { className, stack, @@ -44,7 +47,7 @@ function Card(props: Props) { align, divider = 'space', rowGap, - responsive = true, + responsive = !nestedContext?.isNested, filled, title, children, @@ -91,22 +94,24 @@ function Card(props: Props) { return ( - - {title && ( - - {title} - - )} - {children} - + + + {title && ( + + {title} + + )} + {children} + + ) } diff --git a/packages/dnb-eufemia/src/components/card/CardContext.ts b/packages/dnb-eufemia/src/components/card/CardContext.ts new file mode 100644 index 00000000000..abf799306be --- /dev/null +++ b/packages/dnb-eufemia/src/components/card/CardContext.ts @@ -0,0 +1,11 @@ +import React from 'react' + +export interface CardContextState { + isNested?: boolean +} + +const CardContext = React.createContext( + undefined +) + +export default CardContext diff --git a/packages/dnb-eufemia/src/components/card/CardDocs.ts b/packages/dnb-eufemia/src/components/card/CardDocs.ts index 34f68863a65..32e85eba4dd 100644 --- a/packages/dnb-eufemia/src/components/card/CardDocs.ts +++ b/packages/dnb-eufemia/src/components/card/CardDocs.ts @@ -41,12 +41,12 @@ export const CardProperties: PropertiesTableProps = { type: 'React.Node', status: 'required', }, - '[Flex.Container](/uilib/layout/flex/container)': { + '[Flex.Container](/uilib/layout/flex/container/properties)': { doc: 'Flex.Container properties.', type: 'Various', status: 'optional', }, - '[Flex.Item](/uilib/layout/flex/item)': { + '[Flex.Item](/uilib/layout/flex/item/properties)': { doc: 'Flex.Item properties.', type: 'Various', status: 'optional', diff --git a/packages/dnb-eufemia/src/components/card/__tests__/Card.screenshot.test.ts b/packages/dnb-eufemia/src/components/card/__tests__/Card.screenshot.test.ts index 05a0ee7a60f..b0cce62c30c 100644 --- a/packages/dnb-eufemia/src/components/card/__tests__/Card.screenshot.test.ts +++ b/packages/dnb-eufemia/src/components/card/__tests__/Card.screenshot.test.ts @@ -57,6 +57,13 @@ describe.each(['ui', 'sbanken'])('Card for %s', (themeName) => { }) expect(screenshot).toMatchImageSnapshot() }) + + it('have to match nested cards', async () => { + const screenshot = await makeScreenshot({ + selector: '[data-visual-test="layout-card-nested"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) }) describe.each(['ui', 'sbanken'])( @@ -69,6 +76,7 @@ describe.each(['ui', 'sbanken'])( }, url: '/uilib/components/card/demos', } + it('have to match border', async () => { const screenshot = await makeScreenshot({ ...params, @@ -103,5 +111,12 @@ describe.each(['ui', 'sbanken'])( }) expect(screenshot).toMatchImageSnapshot() }) + + it('have to match nested cards', async () => { + const screenshot = await makeScreenshot({ + selector: '[data-visual-test="layout-card-nested"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) } ) diff --git a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-sbanken-have-to-match-nested-cards.snap.png b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-sbanken-have-to-match-nested-cards.snap.png new file mode 100644 index 00000000000..ff04ac4c618 Binary files /dev/null and b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-sbanken-have-to-match-nested-cards.snap.png differ diff --git a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-ui-have-to-match-nested-cards.snap.png b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-ui-have-to-match-nested-cards.snap.png new file mode 100644 index 00000000000..9259467f394 Binary files /dev/null and b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-for-ui-have-to-match-nested-cards.snap.png differ diff --git a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-sbanken-have-to-match-nested-cards.snap.png b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-sbanken-have-to-match-nested-cards.snap.png new file mode 100644 index 00000000000..b790f320a06 Binary files /dev/null and b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-sbanken-have-to-match-nested-cards.snap.png differ diff --git a/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-ui-have-to-match-nested-cards.snap.png b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-ui-have-to-match-nested-cards.snap.png new file mode 100644 index 00000000000..cde267ddd31 Binary files /dev/null and b/packages/dnb-eufemia/src/components/card/__tests__/__image_snapshots__/card-small-screen-for-ui-have-to-match-nested-cards.snap.png differ diff --git a/packages/dnb-eufemia/src/components/card/style/dnb-card.scss b/packages/dnb-eufemia/src/components/card/style/dnb-card.scss index 9d6362ddc3f..49d9720e8f0 100644 --- a/packages/dnb-eufemia/src/components/card/style/dnb-card.scss +++ b/packages/dnb-eufemia/src/components/card/style/dnb-card.scss @@ -113,4 +113,9 @@ & > .dnb-flex-container--align-stretch > .dnb-button { align-self: flex-start; } + + // Nested Cards + & .dnb-card { + --outline-width: 0.125rem; + } } diff --git a/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-sbanken.scss b/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-sbanken.scss index eab76bb3e18..13b4362e48f 100644 --- a/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-sbanken.scss +++ b/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-sbanken.scss @@ -2,4 +2,9 @@ --card-outline-color: var(--border-color, var(--sb-color-gray-light)); --card-outline-width: 0.0625rem; --card-background-color: var(--sb-color-white); + + // Nested Cards + & .dnb-card { + --rounded-corner: 0.375rem; + } } diff --git a/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-ui.scss b/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-ui.scss index e9f94381029..c8905d31d58 100644 --- a/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-ui.scss +++ b/packages/dnb-eufemia/src/components/card/style/themes/dnb-card-theme-ui.scss @@ -2,4 +2,11 @@ --card-outline-color: var(--border-color, var(--color-lavender)); --card-outline-width: 0.25rem; --card-background-color: var(--color-white); + + // Nested Cards + & .dnb-card { + --card-outline-color: var(--color-black-8); + --outline-width: 0.0625rem; + --rounded-corner: 0.375rem; + } } diff --git a/packages/dnb-eufemia/src/components/checkbox/stories/Checkbox.stories.tsx b/packages/dnb-eufemia/src/components/checkbox/stories/Checkbox.stories.tsx index 6d76bf911a0..19d6a37e177 100644 --- a/packages/dnb-eufemia/src/components/checkbox/stories/Checkbox.stories.tsx +++ b/packages/dnb-eufemia/src/components/checkbox/stories/Checkbox.stories.tsx @@ -118,7 +118,7 @@ export const CheckboxSandbox = () => ( - + Vertical FormLabel for a Checkbox component: diff --git a/packages/dnb-eufemia/src/components/country-flag/CountryFlagDocs.ts b/packages/dnb-eufemia/src/components/country-flag/CountryFlagDocs.ts index 97e8f55d12f..2556236beea 100644 --- a/packages/dnb-eufemia/src/components/country-flag/CountryFlagDocs.ts +++ b/packages/dnb-eufemia/src/components/country-flag/CountryFlagDocs.ts @@ -1,6 +1,11 @@ import { PropertiesTableProps } from '../../shared/types' export const CountryFlagProperties: PropertiesTableProps = { + iso: { + doc: '[ISO 3166-1 alpha-2 code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) representing the country, such as `NO` for Norway. Defaults to `NO`.', + type: 'string', + status: 'optional', + }, size: { doc: 'The size of the component. Can be `auto`, `small`, `medium`, `large` or `x-large`. Defaults to `auto` (1em).', type: 'string', diff --git a/packages/dnb-eufemia/src/components/date-picker/DatePicker.d.ts b/packages/dnb-eufemia/src/components/date-picker/DatePicker.d.ts deleted file mode 100644 index be63034bff9..00000000000 --- a/packages/dnb-eufemia/src/components/date-picker/DatePicker.d.ts +++ /dev/null @@ -1,284 +0,0 @@ -import * as React from 'react'; -import type { FormLabelLabelDirection } from '../FormLabel'; -import type { - FormStatusProps, - FormStatusState, - FormStatusText -} from '../FormStatus'; -import type { GlobalStatusConfigObject } from '../GlobalStatus'; -import type { InputInputElement, InputSize } from '../Input'; -import type { SkeletonShow } from '../Skeleton'; -import type { SpacingProps } from '../space/types'; -type DatePickerDate = Date | string; -type DatePickerStartDate = Date | string; -type DatePickerEndDate = Date | string; -type DatePickerMonth = Date | string; -type DatePickerStartMonth = Date | string; -type DatePickerEndMonth = Date | string; -type DatePickerMinDate = Date | string; -type DatePickerMaxDate = Date | string; -type DatePickerAddonElement = string | React.ReactNode; -type DatePickerShortcuts = any[] | ((...args: any[]) => any); -type DatePickerSuffix = - | string - | ((...args: any[]) => any) - | React.ReactNode; -type DatePickerDirection = 'auto' | 'top' | 'bottom'; -type DatePickerAlignPicker = 'auto' | 'left' | 'right'; - -// Make it possible to join React.Event interfaces with DatePickerEvent type. -export type DatePickerEvent = T & { - date?: string; - start_date?: string; - end_date?: string; - partialStartDate?: string; - partialEndDate?: string; -}; -export interface DatePickerProps - extends Omit< - React.HTMLProps, - 'ref', - 'onBlur' - >, - SpacingProps { - id?: string; - title?: string; - /** - * Defines the pre-filled date by either a JavaScript DateInstance or (ISO 8601) like `date="2019-05-05"`. - */ - date?: DatePickerDate; - /** - * To set the pre-filled starting date. Is used if `range={true}` is set to `true`. Defaults to `null`, showing the `mask_placeholder`. - */ - start_date?: DatePickerStartDate; - /** - * To set the pre-filled ending date. Is used if `range={true}` is set to `true`. Defaults to `null`, showing the `mask_placeholder`. - */ - end_date?: DatePickerEndDate; - /** - * To display what month should be shown in the first calendar by default. Defaults to the `date` respective `start_date`. - */ - month?: DatePickerMonth; - /** - * To display what month should be shown in the first calendar by default. Defaults to the `date` respective `start_date`. - */ - start_month?: DatePickerStartMonth; - /** - * To display what month should be shown in the second calendar by default. Defaults to the `date` respective `start_date`. - */ - end_month?: DatePickerEndMonth; - /** - * To limit a date range to a minimum `start_date`. Defaults to `null`. - */ - min_date?: DatePickerMinDate; - /** - * To limit a date range to a maximum `end_date`. Defaults to `null`. - */ - max_date?: DatePickerMaxDate; - /** - * Corrects the input date value to be the same as either `min_date` or `max_date`, when the user types in a date that is either before or after one of these. Defaults to `false`. - */ - correct_invalid_date?: boolean; - /** - * To define the order of the masked placeholder input fields. Defaults to `dd/mm/yyyy` - */ - mask_order?: string; - /** - * To display the placeholder on input. Defaults to `dd/mm/åååå`. - */ - mask_placeholder?: string; - /** - * Defines how the prop dates (`date`, `start_date` and `end_date`) should be parsed, e.g. `yyyy/MM/dd`. Defaults to `yyyy-MM-dd`. - */ - date_format?: string; - /** - * Defines how the returned date, as a string, should be formatted as. Defaults to `yyyy-MM-dd`. - */ - return_format?: string; - /** - * If set to `true`, the navigation will be hidden. Defaults to `false`. - */ - hide_navigation?: boolean; - hide_navigation_buttons?: boolean; - /** - * If set to `true`, the week days will be hidden. Defaults to `false`. - */ - hide_days?: boolean; - /** - * Use `true` to only show the defined month. Disables the month navigation possibility. Defaults to `false`. - */ - only_month?: boolean; - /** - * Use `true` to only show the last week in the current month if it needs to be shown. The result is that there will mainly be shows five (5) weeks (rows) instead of six (6). Defaults to `false`. - */ - hide_last_week?: boolean; - /** - * Once the date picker gets opened, there is a focus handling to ensure good accessibility. This can be disabled with this property. Defaults to `false`. - */ - disable_autofocus?: boolean; - enable_keyboard_nav?: boolean; - /** - * If the input fields with the mask should be visible. Defaults to `false`. - */ - show_input?: boolean; - /** - * If set to `true`, a submit button will be shown. You can change the default text by using `submit_button_text="Ok"`. Defaults to `false`. If the `range` prop is `true`, then the submit button is shown. - */ - show_submit_button?: boolean; - /** - * If set to `true`, a cancel button will be shown. You can change the default text by using `cancel_button_text="Avbryt"` Defaults to `false`. If the `range` prop is `true`, then the cancel button is shown. - */ - show_cancel_button?: boolean; - /** - * If set to `true`, a reset button will be shown. You can change the default text by using `reset_button_text="Tilbakestill"` Defaults to `false`. - */ - show_reset_button?: boolean; - submit_button_text?: string; - cancel_button_text?: string; - reset_button_text?: string; - reset_date?: boolean; - /** - * To define the first day of the week. Defaults to `monday`. - */ - first_day?: string; - /** - * To define the locale used in the calendar. Needs to be an `date-fns` "v2" locale object, like `import enLocale from 'date-fns/locale/en-GB'`. Defaults to `nb-NO`. - */ - locale?: Record; - /** - * If the date picker should support a range of two dates (starting and ending date). Defaults to `false`. - */ - range?: boolean; - /** - * Link both calendars, once to the user is navigating between months. Only meant to use if the range is set to `true`. Defaults to `false`. - */ - link?: boolean; - /** - * Sync input values with the calendars views. Once the input values get changed, the calendar changes its views in sync. Defaults to `true`. - */ - sync?: boolean; - /** - * A prepending label in sync with the date input field. - */ - label?: React.ReactNode; - /** - * Use `label_direction="vertical"` to change the label layout direction. Defaults to `horizontal`. - */ - label_direction?: FormLabelLabelDirection; - /** - * Use `true` to make the label only readable by screen readers. - */ - label_sr_only?: boolean; - /** - * Gives you the possibility to use a plain/vanilla `` HTML element by defining it as a string `input_element="input"`, a React element, or a render function `input_element={(internalProps) => ()}`. Can also be used in circumstances where the `react-text-mask` should not be used, e.g. in testing environments. Defaults to custom masked input. - */ - input_element?: InputInputElement; - /** - * Gives you the possibility to inject a React element showing up over the footer. Use it to customize `shortcuts`. - */ - addon_element?: DatePickerAddonElement; - /** - * Gives you the possibility to set predefined dates and date ranges so the user can select these by one click. Define either a JSON or an object with the defined shortcuts. More info is below. - */ - shortcuts?: DatePickerShortcuts; - disabled?: boolean; - /** - * If set to `true`, then the date-picker input field will be 100% in `width`. - */ - stretch?: boolean; - /** - * If set to `true`, an overlaying skeleton with animation will be shown. - */ - skeleton?: SkeletonShow; - /** - * The sizes you can choose is `small` (1.5rem), `default` (2rem), `medium` (2.5rem) and `large` (3rem) are supported component sizes. Defaults to `default` / `null`. - */ - size?: InputSize; - /** - * Text with a status message. The style defaults to an error message. You can use `true` to only get the status color, without a message. - */ - status?: FormStatusText; - /** - * Defines the state of the status. Currently, there are two statuses `[error, info]`. Defaults to `error`. - */ - status_state?: FormStatusState; - /** - * Use an object to define additional FormStatus properties. - */ - status_props?: FormStatusProps; - status_no_animation?: boolean; - /** - * The configuration used for the target GlobalStatus. - */ - globalStatus?: GlobalStatusConfigObject; - /** - * Text describing the content of the DatePicker more than the label. You can also send in a React component, so it gets wrapped inside the DatePicker component. - */ - suffix?: DatePickerSuffix; - /** - * To open the date-picker by default. Defaults to `false`. - */ - opened?: boolean; - /** - * Provide a short Tooltip content that shows up on the picker button. - */ - tooltip?: React.ReactNode; - tabIndex?: number; - prevent_close?: boolean; - no_animation?: boolean; - direction?: DatePickerDirection; - /** - * Use `right` to change the calendar alignment direction. Defaults to `left`. - */ - align_picker?: DatePickerAlignPicker; - className?: string; - /** - * Will be called right before every new calendar view gets rendered. See the example above. - */ - on_days_render?: (...args: any[]) => any; - /** - * Will be called on a date change event. Returns an `object`. See Returned Object below. - */ - on_change?: (...args: any[]) => any; - /** - * Will be called on every input and date picker interaction. Returns an `object`. See Returned Object below. - */ - on_type?: (...args: any[]) => any; - /** - * Will be called once date-picker is visible. - */ - on_show?: (...args: any[]) => any; - /** - * Will be called once date-picker is hidden. - */ - on_hide?: (...args: any[]) => any; - /** - * Will be called once a user presses the submit button. - */ - on_submit?: (...args: any[]) => any; - /** - * Will be called once a user presses the cancel button. - */ - on_cancel?: (...args: any[]) => any; - /** - * Will be called once a user presses the reset button. - */ - on_reset?: (...args: any[]) => any; - /** - * Will be called once the input gets focus. - */ - onFocus?: (event: React.FocusEventHandler) => void; - /** - * Will be called once the input lose focus. - */ - onBlur?: ( - event: DatePickerEvent> - ) => void; -} -export default class DatePicker extends React.Component< - DatePickerProps, - any -> { - static defaultProps: object; - render(): JSX.Element; -} diff --git a/packages/dnb-eufemia/src/components/date-picker/DatePicker.tsx b/packages/dnb-eufemia/src/components/date-picker/DatePicker.tsx new file mode 100644 index 00000000000..36f30909126 --- /dev/null +++ b/packages/dnb-eufemia/src/components/date-picker/DatePicker.tsx @@ -0,0 +1,850 @@ +/** + * Web DatePicker Component + * + */ + +import React, { + HTMLProps, + useCallback, + useContext, + useEffect, + useRef, + useState, +} from 'react' + +import classnames from 'classnames' +import { + warn, + makeUniqueId, + extendPropsWithContext, + detectOutsideClick, + getStatusState, + combineDescribedBy, + validateDOMAttributes, + DetectOutsideClickClass, +} from '../../shared/component-helper' +import AlignmentHelper from '../../shared/AlignmentHelper' +import { createSpacingClasses } from '../space/SpacingHelper' +import { skeletonDOMAttributes } from '../skeleton/SkeletonHelper' + +// date-fns +import format from 'date-fns/format' + +import Context, { Locale } from '../../shared/Context' +import Suffix from '../../shared/helpers/Suffix' +import FormLabel from '../form-label/FormLabel' +import FormStatus, { + FormStatusProps, + FormStatusState, + FormStatusText, +} from '../form-status/FormStatus' +import DatePickerProvider, { + DatePickerChangeEvent, + type ReturnObject, +} from './DatePickerProvider' +import DatePickerRange from './DatePickerRange' +import DatePickerInput from './DatePickerInput' +import DatePickerAddon, { DatePickerAddonProps } from './DatePickerAddon' +import DatePickerFooter from './DatePickerFooter' +import { SpacingProps } from '../space/types' +import { InputInputElement, InputSize } from '../Input' +import { SkeletonShow } from '../Skeleton' +import { GlobalStatusConfigObject } from '../GlobalStatus' +import { pickFormElementProps } from '../../shared/helpers/filterValidProps' +import { CalendarDay, DatePickerCalendarProps } from './DatePickerCalendar' +import { DatePickerContextValues, DateType } from './DatePickerContext' +import { DatePickerDates } from './hooks/useDates' +import { useTranslation } from '../../shared' + +export type DatePickerEventAttributes = { + day?: string + year?: string + start?: string + end?: string +} & Record + +// Takes the return object from DatePickerProvider and extends it with the event +export type DatePickerEvent = ReturnObject + +export type DisplayPickerEvent = ( + | React.MouseEvent + | MouseEvent + | KeyboardEvent +) & + DatePickerDates & { + focusOnHide?: boolean | string + event?: React.MouseEvent + } + +export type DatePickerProps = Omit< + React.HTMLProps, + 'ref' | 'children' | 'label' | 'size' | 'onBlur' | 'onFocus' | 'start' +> & + SpacingProps & { + /** + * Defines the pre-filled date by either a JavaScript DateInstance or (ISO 8601) like `date="2019-05-05"`. + */ + date?: DateType + /** + * To set the pre-filled starting date. Is used if `range={true}` is set to `true`. Defaults to `null`, showing the `mask_placeholder`. + */ + start_date?: DateType + /** + * To set the pre-filled ending date. Is used if `range={true}` is set to `true`. Defaults to `null`, showing the `mask_placeholder`. + */ + end_date?: DateType + /** + * To display what month should be shown in the first calendar by default. Defaults to the `date` respective `start_date`. + */ + month?: DateType + /** + * To display what month should be shown in the first calendar by default. Defaults to the `date` respective `start_date`. + */ + start_month?: DateType + /** + * To display what month should be shown in the second calendar by default. Defaults to the `date` respective `start_date`. + */ + end_month?: DateType + /** + * To limit a date range to a minimum `start_date`. Defaults to `null`. + */ + min_date?: DateType + /** + * To limit a date range to a maximum `end_date`. Defaults to `null`. + */ + max_date?: DateType + /** + * Corrects the input date value to be the same as either `min_date` or `max_date`, when the user types in a date that is either before or after one of these. Defaults to `false`. + */ + correct_invalid_date?: boolean + /** + * To define the order of the masked placeholder input fields. Defaults to `dd/mm/yyyy` + */ + mask_order?: string + /** + * To display the placeholder on input. Defaults to `dd/mm/åååå`. + */ + mask_placeholder?: string + /** + * Defines how the prop dates (`date`, `start_date` and `end_date`) should be parsed, e.g. `yyyy/MM/dd`. Defaults to `yyyy-MM-dd`. + */ + date_format?: string + /** + * Defines how the returned date, as a string, should be formatted as. Defaults to `yyyy-MM-dd`. + */ + return_format?: string + /** + * If set to `true`, the navigation will be hidden. Defaults to `false`. + */ + hide_navigation?: boolean + hide_navigation_buttons?: boolean + /** + * If set to `true`, the week days will be hidden. Defaults to `false`. + */ + hide_days?: boolean + /** + * Use `true` to only show the defined month. Disables the month navigation possibility. Defaults to `false`. + */ + only_month?: boolean + /** + * Use `true` to only show the last week in the current month if it needs to be shown. The result is that there will mainly be shows five (5) weeks (rows) instead of six (6). Defaults to `false`. + */ + hide_last_week?: boolean + /** + * Once the date picker gets opened, there is a focus handling to ensure good accessibility. can be disabled with property. Defaults to `false`. + */ + disable_autofocus?: boolean + enable_keyboard_nav?: boolean + /** + * If the input fields with the mask should be visible. Defaults to `false`. + */ + show_input?: boolean + /** + * If set to `true`, a submit button will be shown. You can change the default text by using `submit_button_text="Ok"`. Defaults to `false`. If the `range` prop is `true`, then the submit button is shown. + */ + show_submit_button?: boolean + /** + * If set to `true`, a cancel button will be shown. You can change the default text by using `cancel_button_text="Avbryt"` Defaults to `false`. If the `range` prop is `true`, then the cancel button is shown. + */ + show_cancel_button?: boolean + /** + * If set to `true`, a reset button will be shown. You can change the default text by using `reset_button_text="Tilbakestill"` Defaults to `false`. + */ + show_reset_button?: boolean + submit_button_text?: string + cancel_button_text?: string + reset_button_text?: string + reset_date?: boolean + /** + * To define the first day of the week. Defaults to `monday`. + */ + first_day?: string + /** + * @deprecated set locale with `Provider` instead. + */ + locale?: Locale + /** + * If the date picker should support a range of two dates (starting and ending date). Defaults to `false`. + */ + range?: boolean + /** + * Link both calendars, once to the user is navigating between months. Only meant to use if the range is set to `true`. Defaults to `false`. + */ + link?: boolean + /** + * Sync input values with the calendars views. Once the input values get changed, the calendar changes its views in sync. Defaults to `true`. + */ + sync?: boolean + /** + * A prepending label in sync with the date input field. + */ + label?: React.ReactNode + /** + * Use `label_direction="vertical"` to change the label layout direction. Defaults to `horizontal`. + */ + label_direction?: 'vertical' | 'horizontal' + /** + * Use `true` to make the label only readable by screen readers. + */ + label_sr_only?: boolean + /** + * Gives you the possibility to use a plain/vanilla `` HTML element by defining it as a string `input_element="input"`, a React element, or a render function `input_element={(internalProps) => ()}`. Can also be used in circumstances where the `react-text-mask` not should be used, e.g. in testing environments. Defaults to custom masked input. + */ + input_element?: InputInputElement + /** + * Gives you the possibility to inject a React element showing up over the footer. Use it to customize `shortcuts`. + */ + addon_element?: React.ReactNode + /** + * Gives you the possibility to set predefined dates and date ranges so the user can select these by one click. Define either a JSON or an object with the defined shortcuts. More info is below. + */ + shortcuts?: DatePickerAddonProps['shortcuts'] + disabled?: boolean + /** + * If set to `true`, then the date-picker input field will be 100% in `width`. + */ + stretch?: boolean + /** + * If set to `true`, an overlaying skeleton with animation will be shown. + */ + skeleton?: SkeletonShow + /** + * The sizes you can choose is `small` (1.5rem), `default` (2rem), `medium` (2.5rem) and `large` (3rem) are supported component sizes. Defaults to `default` / `null`. + */ + size?: InputSize + /** + * Text with a status message. The style defaults to an error message. You can use `true` to only get the status color, without a message. + */ + status?: FormStatusText + /** + * Defines the state of the status. Currently, there are two statuses `[error, info]`. Defaults to `error`. + */ + status_state?: FormStatusState + /** + * Use an object to define additional FormStatus properties. + */ + status_props?: FormStatusProps + status_no_animation?: boolean + /** + * The configuration used for the target GlobalStatus. + */ + globalStatus?: GlobalStatusConfigObject + /** + * Text describing the content of the DatePicker more than the label. You can also send in a React component, so it gets wrapped inside the DatePicker component. + */ + suffix?: React.ReactNode + /** + * To open the date-picker by default. Defaults to `false`. + */ + opened?: boolean + /** + * Provide a short Tooltip content that shows up on the picker button. + */ + tooltip?: React.ReactNode + tabIndex?: number + prevent_close?: boolean + no_animation?: boolean + direction?: 'auto' | 'top' | 'bottom' + /** + * Use `right` to change the calendar alignment direction. Defaults to `left`. + */ + align_picker?: 'auto' | 'left' | 'right' + className?: string + /** + * Will be called right before every new calendar view gets rendered. See the example above. + */ + on_days_render?: ( + days: Array, + nr?: DatePickerCalendarProps['nr'] + ) => void + /** + * Will be called on a date change event. Returns an `object`. See Returned Object below. + */ + on_change?: ( + event: DatePickerEvent> + ) => void + /** + * Will be called on every input and date picker interaction. Returns an `object`. See Returned Object below. + */ + on_type?: ( + event: DatePickerEvent> + ) => void + /** + * Will be called once date-picker is visible. + */ + on_show?: (event: DatePickerEvent) => void + /** + * Will be called once date-picker is hidden. + */ + on_hide?: (event: DatePickerEvent) => void + /** + * Will be called once a user presses the submit button. + */ + on_submit?: ( + event: DatePickerEvent> + ) => void + /** + * Will be called once a user presses the cancel button. + */ + on_cancel?: ( + event: DatePickerEvent> + ) => void + /** + * Will be called once a user presses the reset button. + */ + on_reset?: ( + event: DatePickerEvent> + ) => void + /** + * Will be called once the input gets focus. + */ + onFocus?: ( + event: DatePickerEvent> + ) => void + /** + * Will be called once the input lose focus. + */ + onBlur?: ( + event: DatePickerEvent> + ) => void + } + +const defaultProps: DatePickerProps = { + mask_order: 'dd/mm/yyyy', + mask_placeholder: 'dd/mm/åååå', // have to be same setup as "mask" - but can be like + date_format: 'yyyy-MM-dd', // in v1 of date-fns we were more flexible in terms of the format + return_format: 'yyyy-MM-dd', // used in date-fns v1 + hide_navigation: false, + hide_navigation_buttons: false, + hide_days: false, + only_month: false, + hide_last_week: false, + disable_autofocus: false, + enable_keyboard_nav: false, + show_input: false, + submit_button_text: 'Ok', + cancel_button_text: 'Avbryt', + reset_button_text: 'Tilbakestill', + reset_date: true, + first_day: 'monday', + range: false, + link: false, + sync: true, + status_state: 'error', + opened: false, + no_animation: false, + direction: 'auto', +} + +function DatePicker(externalProps: DatePickerProps) { + const props = { ...defaultProps, ...externalProps } + + const { + prevent_close, + on_hide, + on_show, + on_submit, + on_cancel, + on_reset, + no_animation, + show_input, + align_picker, + show_submit_button, + show_cancel_button, + range, + hide_days, + hide_navigation, + opened: propsOpened, + end_date, + } = props + + const [opened, setOpened] = useState(propsOpened) + const [hidden, setHidden] = useState(!opened) + const [startDate, setStartDate] = useState() + const [endDate, setEndDate] = useState() + + const showInput = props.show_input + + const context = useContext(Context) + const blurDelay = 201 // some ms more than "dropdownSlideDown 200ms" + const id = props.id || makeUniqueId() + + const innerRef = useRef() + const triangleRef = useRef() + const submitButtonRef = useRef() + const getReturnObject = + useRef() + const hideTimeout = useRef() + const outsideClick = useRef() + + const translation = useTranslation().DatePicker + + if (end_date && !range) { + warn( + `The DatePicker got a "end_date". You have to set range={true} as well!.` + ) + } + + const removeOutsideClickHandler = useCallback(() => { + if (outsideClick.current) { + outsideClick.current.remove() + } + }, []) + + const hidePicker = useCallback( + (args?: DisplayPickerEvent) => { + if (prevent_close) { + return // stop here + } + + if (args && args.event && args.event.persist) { + args.event.persist() + } + + setOpened(false) + + // Double check and compare return + on_hide?.({ + ...getReturnObject.current(args), + }) + + hideTimeout.current = setTimeout( + () => { + setHidden(true) + if (args?.['focusOnHide']) { + try { + submitButtonRef.current.focus({ + preventScroll: true, + }) + } catch (e) { + warn(e) + } + } + }, + no_animation ? 1 : blurDelay + ) // wait until animation is over + + removeOutsideClickHandler() + }, + [no_animation, prevent_close, on_hide, removeOutsideClickHandler] + ) + + const setOutsideClickHandler = useCallback(() => { + outsideClick.current = detectOutsideClick( + innerRef.current, + ({ event }: { event: MouseEvent | KeyboardEvent }) => { + hidePicker({ ...event, focusOnHide: event?.['code'] }) + } + ) + }, [hidePicker]) + + const setTrianglePosition = useCallback(() => { + const triangleWidth = 16 + if (show_input && triangleRef.current && innerRef.current) { + try { + const shellWidth = innerRef.current + .querySelector('.dnb-input__shell') + .getBoundingClientRect().width + + const buttonWidth = innerRef.current + .querySelector('.dnb-input__submit-button__button') + .getBoundingClientRect().width + + if (align_picker === 'right') { + const distance = buttonWidth / 2 - triangleWidth / 2 + triangleRef.current.style.marginRight = `${distance / 16}rem` + } else { + const distance = shellWidth - buttonWidth / 2 - triangleWidth / 2 + triangleRef.current.style.marginLeft = `${distance / 16}rem` + } + } catch (e) { + warn(e) + } + } + }, [show_input, align_picker]) + + const showPicker = useCallback( + (event?: DisplayPickerEvent) => { + if (hideTimeout.current) { + clearTimeout(hideTimeout.current) + } + + setOpened(true) + setHidden(false) + + on_show?.({ ...getReturnObject.current(event) }) + + setTrianglePosition() + setOutsideClickHandler() + }, + [setTrianglePosition, setOutsideClickHandler, on_show] + ) + + useEffect(() => { + if (propsOpened) { + showPicker() + } + + return () => { + clearTimeout(hideTimeout.current) + removeOutsideClickHandler() + } + }, [propsOpened, removeOutsideClickHandler, showPicker]) + + const onPickerChange = useCallback( + ({ + hidePicker: shouldHidePicker = true, + ...args + }: DatePickerChangeEvent< + | React.MouseEvent + | React.KeyboardEvent + >) => { + if (shouldHidePicker && !show_submit_button && !show_cancel_button) { + hidePicker() + } + + setStartDate(args.startDate) + setEndDate(args.endDate) + }, + [hidePicker, show_submit_button, show_cancel_button] + ) + + const onSubmitHandler = useCallback( + (event: React.MouseEvent) => { + hidePicker(event) + on_submit?.({ + ...getReturnObject.current({ event }), + }) + }, + [hidePicker, on_submit] + ) + + const onCancelHandler = useCallback( + ( + event: DatePickerChangeEvent> + ) => { + hidePicker() + on_cancel?.({ ...getReturnObject.current(event) }) + }, + [hidePicker, on_cancel] + ) + + const onResetHandler = useCallback( + ( + event: DatePickerChangeEvent> + ) => { + hidePicker() + on_reset?.({ ...getReturnObject.current(event) }) + }, + [hidePicker, on_reset] + ) + + const togglePicker = useCallback( + (args: React.MouseEvent) => { + !opened ? showPicker(args) : hidePicker(args) + }, + [opened, showPicker, hidePicker] + ) + + const formatSelectedDateTitle = useCallback(() => { + const { selected_date, start, end } = translation + + let currentDate = startDate ? format(startDate, 'PPPP') : null + + if (range && startDate && endDate) { + currentDate = `${start} ${currentDate} - ${end} ${format( + endDate, + 'PPPP' + )}` + } + + return currentDate ? selected_date.replace(/%s/, currentDate) : '' + }, [range, translation, startDate, endDate]) + + // use only the props from context, who are available here anyway + const extendedProps = extendPropsWithContext( + props, + defaultProps, + { skeleton: context?.skeleton }, + context.getTranslation(props).DatePicker, + pickFormElementProps(context?.FormRow), // Deprecated – can be removed in v11 + pickFormElementProps(context?.formElement), + context.DatePicker + ) + + const { + label, + title, + label_direction, + label_sr_only, + only_month, + hide_last_week, + disable_autofocus, + hide_navigation_buttons, + first_day, + reset_date, + link, + sync, + input_element, + addon_element, + shortcuts, + disabled, + stretch, + skeleton, + size, + status, + status_state, + status_props, + status_no_animation, + globalStatus, + suffix, + mask_order, + mask_placeholder, + submit_button_text, + cancel_button_text, + reset_button_text, + show_reset_button, + className, + tooltip, + ...restProps + } = extendedProps + + let attributes = null + + { + const { + locale, + id, + month, + date, + start_date, + end_date, + min_date, + max_date, + enable_keyboard_nav, + hide_navigation, + return_format, + date_format, + hide_days, + correct_invalid_date, + opened, + direction, + range, + ...rest + } = restProps + attributes = rest + } + + const shouldHideDays = only_month ? true : hide_days + const shouldHideNavigation = only_month + ? hide_navigation_buttons + ? false + : true + : hide_navigation + + const showStatus = getStatusState(status) + + const pickerParams = {} as HTMLProps + + if (showStatus || suffix) { + pickerParams['aria-describedby'] = combineDescribedBy( + pickerParams, + showStatus ? id + '-status' : null, + suffix ? id + '-suffix' : null + ) + } + + const submitParams = { + ['aria-expanded']: opened, + ref: submitButtonRef, + tabIndex: extendedProps.tabIndex, + tooltip, + } + + const selectedDateTitle = formatSelectedDateTitle() + + const mainParams = { + className: classnames( + 'dnb-date-picker', + status && `dnb-date-picker__status--${status_state}`, + label_direction && `dnb-date-picker--${label_direction}`, + opened && 'dnb-date-picker--opened', + hidden && 'dnb-date-picker--hidden', + showInput && 'dnb-date-picker--show-input', + (range || + show_submit_button || + show_cancel_button || + show_reset_button) && + 'dnb-date-picker--show-footer', + align_picker && `dnb-date-picker--${align_picker}`, + stretch && `dnb-date-picker--stretch`, + 'dnb-form-component', + size && `dnb-date-picker--${size}`, + createSpacingClasses(props), + className + ), + lang: context.locale, + } as HTMLProps + + const remainingDOMProps = validateDOMAttributes(props, attributes) + const remainingSubmitProps = validateDOMAttributes(null, submitParams) + const remainingPickerProps = validateDOMAttributes( + null, + skeletonDOMAttributes(pickerParams, skeleton, context) + ) + + return ( + (getReturnObject.current = fn)} + hidePicker={hidePicker} + > + + {label && ( + + )} + + + + + + + + + + + +

+ {selectedDateTitle} +

+
+
+ ) +} + +export default DatePicker + +DatePicker._supportsSpacingProps = true diff --git a/packages/dnb-eufemia/src/components/date-picker/DatePickerAddon.d.ts b/packages/dnb-eufemia/src/components/date-picker/DatePickerAddon.d.ts deleted file mode 100644 index ae407d644b1..00000000000 --- a/packages/dnb-eufemia/src/components/date-picker/DatePickerAddon.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react'; -export type DatePickerAddonShortcuts = any[] | ((...args: any[]) => any); -export type DatePickerAddonRenderElement = - | React.ReactNode - | ((...args: any[]) => any); -export interface DatePickerAddonProps - extends React.HTMLProps { - /** - * Gives you the possibility to set predefined dates and date ranges so the user can select these by one click. Define either a JSON or an object with the defined shortcuts. More info is below. - */ - shortcuts?: DatePickerAddonShortcuts; - renderElement?: DatePickerAddonRenderElement; -} -export default class DatePickerAddon extends React.Component< - DatePickerAddonProps, - any -> { - static defaultProps: object; - render(): JSX.Element; -} diff --git a/packages/dnb-eufemia/src/components/date-picker/DatePickerAddon.js b/packages/dnb-eufemia/src/components/date-picker/DatePickerAddon.js deleted file mode 100644 index 2566a53de68..00000000000 --- a/packages/dnb-eufemia/src/components/date-picker/DatePickerAddon.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Web DatePicker Component - * - */ - -import React from 'react' -import PropTypes from 'prop-types' -import { convertStringToDate } from './DatePickerCalc' -import Button from '../button/Button' -import DatePickerContext from './DatePickerContext' - -export default class DatePickerAddon extends React.PureComponent { - static contextType = DatePickerContext - - static propTypes = { - shortcuts: PropTypes.oneOfType([PropTypes.array, PropTypes.func]), - renderElement: PropTypes.oneOfType([PropTypes.node, PropTypes.func]), - } - - static defaultProps = { - shortcuts: null, - renderElement: null, - } - - state = { - _listenForPropChanges: true, - } - - setDate({ shortcut, event }) { - this.setState({ - _listenForPropChanges: false, - }) - - const start_date = shortcut.date || shortcut.start_date - const end_date = shortcut.end_date - const startDate = - typeof start_date === 'function' - ? start_date(this.getCurrentDates()) - : start_date - ? convertStringToDate(start_date) - : null - const endDate = - typeof end_date === 'function' - ? end_date(this.getCurrentDates()) - : end_date - ? convertStringToDate(end_date) - : null - - this.callOnChange({ - startDate, - endDate: endDate || startDate, - event, - }) - - if (shortcut.close_on_select) { - this.context.hidePicker(event) - } - } - - getCurrentDates() { - const { startDate, endDate } = this.context - return { - date: startDate, - start_date: startDate, - end_date: endDate, - } - } - - callOnChange({ startDate, endDate, event = null } = {}) { - this.context.updateState({ - startDate, - endDate, - changeMonthViews: true, - }) - this.context.callOnChangeHandler({ startDate, endDate, event }) - } - - render() { - const { shortcuts, renderElement } = this.props - - const shortcutsArray = shortcuts - ? typeof shortcuts === 'string' - ? JSON.parse(shortcuts) - : shortcuts - : [] - const hasShortcuts = shortcutsArray && shortcutsArray.length > 0 - - if (!hasShortcuts && !renderElement) { - return <> - } - - const shortcutElements = hasShortcuts && ( - <> - {shortcutsArray.map(({ title, ...shortcut }, i) => { - return ( - + ) +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/DoneButton.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/DoneButton.tsx new file mode 100644 index 00000000000..5299cbd3b43 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/DoneButton.tsx @@ -0,0 +1,49 @@ +import React, { useCallback, useContext } from 'react' +import SectionContainerContext from '../containers/SectionContainerContext' +import ToolbarContext from '../Toolbar/ToolbarContext' +import { useTranslation } from '../../../hooks' +import { Button } from '../../../../../components' +import { check } from '../../../../../icons' +import FieldBoundaryContext from '../../../DataContext/FieldBoundary/FieldBoundaryContext' + +export default function DoneEditButton() { + const { onDone, setShowError } = useContext(ToolbarContext) || {} + + const { switchContainerMode } = useContext(SectionContainerContext) || {} + const { hasError, hasVisibleError, setShowBoundaryErrors } = + useContext(FieldBoundaryContext) || {} + + const translation = useTranslation().SectionEditContainer + + const doneHandler = useCallback(() => { + if (hasError) { + setShowBoundaryErrors?.(true) + if (hasVisibleError) { + setShowError(true) + } + } else { + setShowError(false) + setShowBoundaryErrors?.(false) + switchContainerMode?.('view') + onDone?.() + } + }, [ + hasError, + hasVisibleError, + onDone, + setShowBoundaryErrors, + setShowError, + switchContainerMode, + ]) + + return ( + + ) +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainer.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainer.tsx index 77198c67d16..29187573a1f 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainer.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainer.tsx @@ -6,11 +6,12 @@ import { Props as FlexContainerProps } from '../../../../../components/flex/Cont import { Lead } from '../../../../../elements' import FieldBoundaryProvider from '../../../DataContext/FieldBoundary/FieldBoundaryProvider' import SectionContainerContext from '../containers/SectionContainerContext' -import EditToolbarTools from './EditToolbarTools' +import Toolbar from '../Toolbar/Toolbar' +import DoneButton from './DoneButton' +import CancelButton from './CancelButton' import SectionContainer, { SectionContainerProps, } from '../containers/SectionContainer' -import Toolbar from '../containers/Toolbar' import { Path } from '../../../types' export type Props = { @@ -47,6 +48,10 @@ function EditContainer(props: AllProps) { [containerMode, initialContainerMode, switchContainerMode] ) + const hasToolbar = React.Children.toArray(children).some((child) => { + return child?.['type'] === Toolbar + }) + return ( {title && {title}} {children} - - - + {hasToolbar ? null : ( + + + + + )} ) } +EditContainer.DoneButton = DoneButton +EditContainer.CancelButton = CancelButton EditContainer._supportsSpacingProps = true export default EditContainer diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainerDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainerDocs.ts index 34124d78e21..bb5c00b69d6 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainerDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditContainerDocs.ts @@ -12,7 +12,7 @@ export const EditContainerProperties: PropertiesTableProps = { status: 'optional', }, - '[FlexVertical](/uilib/layout/flex/container/)': { + '[FlexVertical](/uilib/layout/flex/container/properties)': { doc: 'All Flex.Vertical properties.', type: 'Various', status: 'optional', diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditToolbarTools.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditToolbarTools.tsx deleted file mode 100644 index a71d87c0128..00000000000 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/EditToolbarTools.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React, { useCallback, useContext, useState } from 'react' -import { Button, Flex, FormStatus } from '../../../../../components' -import useTranslation from '../../../hooks/useTranslation' -import SectionContainerContext from '../containers/SectionContainerContext' -import FieldBoundaryContext from '../../../DataContext/FieldBoundary/FieldBoundaryContext' -import { check, close } from '../../../../../icons' -import useContainerDataStore from './useContainerDataStore' - -export type Props = { - onDone?: () => void - onCancel?: () => void -} - -export default function EditToolbarTools(props: Props) { - const { onDone, onCancel } = props - const { restoreOriginalData } = useContainerDataStore() - - const { switchContainerMode, initialContainerMode } = - useContext(SectionContainerContext) || {} - const { - hasVisibleError, - hasSubmitError, - hasError, - setShowBoundaryErrors, - } = useContext(FieldBoundaryContext) || {} - - const translation = useTranslation().SectionEditContainer - - const [showError, setShowError] = useState(false) - - const cancelHandler = useCallback(() => { - if (hasSubmitError || (initialContainerMode === 'auto' && hasError)) { - setShowBoundaryErrors?.(Date.now()) - if (hasVisibleError) { - setShowError(true) - } - } else { - setShowError(false) - setShowBoundaryErrors?.(false) - restoreOriginalData() - switchContainerMode?.('view') - onCancel?.() - } - }, [ - hasSubmitError, - initialContainerMode, - hasError, - setShowBoundaryErrors, - hasVisibleError, - restoreOriginalData, - switchContainerMode, - onCancel, - ]) - const doneHandler = useCallback(() => { - if (hasError) { - setShowBoundaryErrors?.(Date.now()) - if (hasVisibleError) { - setShowError(true) - } - } else { - setShowError(false) - setShowBoundaryErrors?.(false) - switchContainerMode?.('view') - onDone?.() - } - }, [ - hasError, - setShowBoundaryErrors, - hasVisibleError, - switchContainerMode, - onDone, - ]) - - return ( - <> - - - - - - - - {translation.errorInSection} - - - ) -} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/CancelButton.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/CancelButton.test.tsx new file mode 100644 index 00000000000..9a4e022acec --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/CancelButton.test.tsx @@ -0,0 +1,214 @@ +import React from 'react' +import { render, fireEvent } from '@testing-library/react' +import { DataContext, Field } from '../../../../' +import FieldBoundaryContext from '../../../../DataContext/FieldBoundary/FieldBoundaryContext' +import ToolbarContext from '../../Toolbar/ToolbarContext' +import SectionContainerContext from '../../containers/SectionContainerContext' +import Toolbar from '../../Toolbar' +import CancelButton from '../CancelButton' +import nbNO from '../../../../constants/locales/nb-NO' + +const nb = nbNO['nb-NO'].SectionEditContainer + +describe('CancelButton', () => { + it('calls "switchContainerMode"', () => { + const switchContainerMode = jest.fn() + + render( + + + + + + ) + + fireEvent.click(document.querySelector('button')) + + expect(switchContainerMode).toHaveBeenCalledTimes(1) + expect(switchContainerMode).toHaveBeenCalledWith('view') + }) + + it('to have button with correct text', () => { + render( + + + + + + ) + + const button = document.querySelector('button') + expect(button).toHaveTextContent(nb.cancelButton) + }) + + it('should not call "setShowError" when hasSubmitError is true and hasVisibleError is false', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(0) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=true" when hasSubmitError and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(true) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=true" when hasError and hasVisibleError is true and initialContainerMode is "auto"', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(true) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=false" when hasSubmitError is false and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(false) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(false) + }) + + it('will restore the original value', () => { + const onSubmit = jest.fn() + let submitData = null + + render( + + + + {({ internalDataRef }) => { + submitData = internalDataRef.current + return null + }} + + + + + + + + ) + + fireEvent.change(document.querySelector('input'), { + target: { value: 'changed value' }, + }) + expect(submitData).toEqual({ foo: 'changed value' }) + + fireEvent.click(document.querySelector('button')) + expect(submitData).toEqual({ foo: 'original value' }) + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/DoneButton.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/DoneButton.test.tsx new file mode 100644 index 00000000000..499954eecf6 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/DoneButton.test.tsx @@ -0,0 +1,140 @@ +import React from 'react' +import { render, fireEvent } from '@testing-library/react' +import FieldBoundaryContext from '../../../../DataContext/FieldBoundary/FieldBoundaryContext' +import SectionContainerContext from '../../containers/SectionContainerContext' +import Toolbar from '../../Toolbar' +import DoneButton from '../DoneButton' +import nbNO from '../../../../constants/locales/nb-NO' +import ToolbarContext from '../../Toolbar/ToolbarContext' + +const nb = nbNO['nb-NO'].SectionEditContainer + +describe('DoneButton', () => { + it('calls "switchContainerMode"', () => { + const switchContainerMode = jest.fn() + + render( + + + + + + ) + + fireEvent.click(document.querySelector('button')) + + expect(switchContainerMode).toHaveBeenCalledTimes(1) + expect(switchContainerMode).toHaveBeenCalledWith('view') + }) + + it('should not call "setShowError" when hasError is true and hasVisibleError is false', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(0) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=true" when hasError and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(true) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=false" when hasError is false and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(false) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(false) + }) + + it('to have button with correct text', () => { + render( + + + + + + ) + + const button = document.querySelector('button') + expect(button).toHaveTextContent(nb.doneButton) + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/EditContainer.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/EditContainer.test.tsx new file mode 100644 index 00000000000..8f27f88916f --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/EditContainer/__tests__/EditContainer.test.tsx @@ -0,0 +1,40 @@ +import React from 'react' +import { render } from '@testing-library/react' +import { Form } from '../../../..' +import nbNO from '../../../../constants/locales/nb-NO' +import Toolbar from '../../Toolbar' + +const nb = nbNO['nb-NO'] + +describe('EditContainer', () => { + it('should render default toolbar', () => { + render( + + + Edit Content + + + ) + + expect(document.querySelectorAll('button')).toHaveLength(2) + expect(document.querySelectorAll('button')[0]).toHaveTextContent( + nb.SectionEditContainer.doneButton + ) + expect(document.querySelectorAll('button')[1]).toHaveTextContent( + nb.SectionEditContainer.cancelButton + ) + }) + + it('should render custom toolbar', () => { + render( + + + Edit Content + no button + + + ) + + expect(document.querySelectorAll('button')).toHaveLength(0) + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/Section.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Section.tsx index 1778086ba7e..ae593c8371d 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/Section.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Section.tsx @@ -9,16 +9,15 @@ import EditContainer from './EditContainer' import type { Props as DataContextProps } from '../../DataContext/Provider' import type { ContainerMode } from './containers/SectionContainer' -import type { - FieldBlockProps, - Path, - FieldProps, - OnChange, -} from '../../types' +import type { Path, FieldProps, OnChange } from '../../types' import type { JsonObject } from '../../utils/json-pointer' +import type { SharedFieldBlockProps } from '../../FieldBlock' +import Toolbar from './Toolbar' export type OverwritePropsDefaults = { - [key: Path]: (FieldProps & FieldBlockProps) | OverwritePropsDefaults + [key: Path]: + | (FieldProps & SharedFieldBlockProps) + | OverwritePropsDefaults } export type SectionProps = { /** @@ -138,6 +137,7 @@ function SectionComponent(props: LocalProps) { ) } +SectionComponent.Toolbar = Toolbar SectionComponent.ViewContainer = ViewContainer SectionComponent.EditContainer = EditContainer diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/Toolbar.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/Toolbar.tsx new file mode 100644 index 00000000000..912c00a2252 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/Toolbar.tsx @@ -0,0 +1,54 @@ +import React, { useContext, useEffect, useState } from 'react' +import classnames from 'classnames' +import { useTranslation } from '../../../hooks' +import ToolbarContext from './ToolbarContext' +import FieldBoundaryContext from '../../../DataContext/FieldBoundary/FieldBoundaryContext' +import { Hr } from '../../../../../elements' +import { Flex, FormStatus } from '../../../../../components' +import Space, { SpaceAllProps } from '../../../../../components/Space' + +export type Props = SpaceAllProps & { + onEdit?: () => void + onDone?: () => void + onCancel?: () => void +} + +export default function Toolbar(props: Props) { + const { errorInSection } = useTranslation().SectionEditContainer + const { children, className, onEdit, onDone, onCancel, ...rest } = props + + const { hasError, hasVisibleError } = + useContext(FieldBoundaryContext) || {} + const [showError, setShowError] = useState(false) + + useEffect(() => { + if (showError && !hasError) { + setShowError(false) + } + }, [hasError, showError]) + + return ( + +
+ + + + {children} + + + + + {errorInSection} + +
+ ) +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/ToolbarContext.ts b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/ToolbarContext.ts new file mode 100644 index 00000000000..15ad6867e14 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/ToolbarContext.ts @@ -0,0 +1,14 @@ +import React from 'react' + +export interface ToolbarContextState { + setShowError: (showError: boolean) => void + onEdit?: () => void + onDone?: () => void + onCancel?: () => void +} + +const ToolbarContext = React.createContext< + ToolbarContextState | undefined +>(undefined) + +export default ToolbarContext diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/ToolbarDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/ToolbarDocs.ts new file mode 100644 index 00000000000..87f80b42c71 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/ToolbarDocs.ts @@ -0,0 +1,5 @@ +import { PropertiesTableProps } from '../../../../../shared/types' + +export const ToolbarProperties: PropertiesTableProps = {} + +export const ToolbarEvents: PropertiesTableProps = {} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/__tests__/Toolbar.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/__tests__/Toolbar.test.tsx new file mode 100644 index 00000000000..0d38dd91faa --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/__tests__/Toolbar.test.tsx @@ -0,0 +1,57 @@ +import React from 'react' +import { render } from '@testing-library/react' +import SectionContainerContext from '../../containers/SectionContainerContext' +import Toolbar from '../Toolbar' +import EditButton from '../../ViewContainer/EditButton' +import nbNO from '../../../../constants/locales/nb-NO' + +const nb = nbNO['nb-NO'].SectionViewContainer + +describe('Toolbar', () => { + it('supports spacing props', () => { + render( + + content + + ) + + expect( + document.querySelector('.dnb-forms-section-toolbar') + ).toHaveClass('dnb-space__top--large') + }) + + it('has buttons/tools by default', () => { + render( + + + + ) + + expect(document.querySelector('button')).not.toBeInTheDocument() + }) + + it('has hr element', () => { + render( + + + + ) + + expect(document.querySelector('hr')).toBeInTheDocument() + }) + + it('has render given children', () => { + render( + + + + + + ) + + const buttons = document.querySelectorAll('button') + + expect(buttons).toHaveLength(1) + expect(buttons[0]).toHaveTextContent(nb.editButton) + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/index.ts b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/index.ts new file mode 100644 index 00000000000..cfe3c97b338 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/Toolbar/index.ts @@ -0,0 +1,2 @@ +export { default } from './Toolbar' +export * from './Toolbar' diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/EditButton.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/EditButton.tsx new file mode 100644 index 00000000000..7aa91e7b607 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/EditButton.tsx @@ -0,0 +1,30 @@ +import React, { useCallback, useContext } from 'react' +import SectionContainerContext from '../containers/SectionContainerContext' +import ToolbarContext from '../Toolbar/ToolbarContext' +import { useTranslation } from '../../../hooks' +import { Button } from '../../../../../components' +import { edit } from '../../../../../icons' + +export default function EditButton() { + const sectionContainerContext = useContext(SectionContainerContext) + const { onEdit } = useContext(ToolbarContext) || {} + const { switchContainerMode } = sectionContainerContext || {} + + const translation = useTranslation().SectionViewContainer + + const editHandler = useCallback(() => { + switchContainerMode?.('edit') + onEdit?.() + }, [onEdit, switchContainerMode]) + + return ( + + ) +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainer.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainer.tsx index a14d4c4dde5..39c2037b3f6 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainer.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainer.tsx @@ -4,11 +4,11 @@ import { convertJsxToString } from '../../../../../shared/component-helper' import { Flex } from '../../../../../components' import { Props as FlexContainerProps } from '../../../../../components/flex/Container' import { Lead } from '../../../../../elements' -import ViewToolbarTools from './ViewToolbarTools' +import Toolbar from '../Toolbar/Toolbar' import SectionContainer, { SectionContainerProps, } from '../containers/SectionContainer' -import Toolbar from '../containers/Toolbar' +import EditButton from './EditButton' export type Props = { title?: React.ReactNode @@ -21,6 +21,10 @@ function ViewContainer(props: AllProps) { const { children, className, title, onEdit, ...restProps } = props || {} const ariaLabel = useMemo(() => convertJsxToString(title), [title]) + const hasToolbar = React.Children.toArray(children).some((child) => { + return child?.['type'] === Toolbar + }) + return ( {title && {title}} {children} - - - + {hasToolbar ? null : ( + + + + )} ) } - +ViewContainer.EditButton = EditButton ViewContainer._supportsSpacingProps = true export default ViewContainer diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainerDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainerDocs.ts index 101f1881824..94d7f6b53ba 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainerDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewContainerDocs.ts @@ -11,7 +11,7 @@ export const ViewContainerProperties: PropertiesTableProps = { type: 'string', status: 'optional', }, - '[FlexVertical](/uilib/layout/flex/container/)': { + '[FlexVertical](/uilib/layout/flex/container/properties)': { doc: 'All Flex.Vertical properties.', type: 'Various', status: 'optional', diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewToolbarTools.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewToolbarTools.tsx deleted file mode 100644 index 0a86e6c84a5..00000000000 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/ViewToolbarTools.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React, { useCallback, useContext } from 'react' -import { Button, Flex } from '../../../../../components' -import useTranslation from '../../../hooks/useTranslation' -import SectionContainerContext from '../containers/SectionContainerContext' -import { edit } from '../../../../../icons' - -export type Props = { - onEdit?: () => void -} - -export default function ViewToolbarTools(props: Props) { - const { onEdit } = props - const sectionContainerContext = useContext(SectionContainerContext) - const { switchContainerMode } = sectionContainerContext ?? {} - - const translation = useTranslation().SectionViewContainer - - const editHandler = useCallback(() => { - switchContainerMode?.('edit') - onEdit?.() - }, [onEdit, switchContainerMode]) - - return ( - - - - ) -} diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/__tests__/EditButton.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/__tests__/EditButton.test.tsx new file mode 100644 index 00000000000..c182a9cae41 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/__tests__/EditButton.test.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import { fireEvent, render } from '@testing-library/react' +import SectionContainerContext from '../../containers/SectionContainerContext' +import Toolbar from '../../Toolbar/Toolbar' +import EditButton from '../EditButton' +import nbNO from '../../../../constants/locales/nb-NO' + +const nb = nbNO['nb-NO'].SectionViewContainer + +describe('EditButton', () => { + it('to have buttons with correct text', () => { + render( + + + + ) + + const button = document.querySelector('button') + expect(button).toHaveTextContent(nb.editButton) + }) + + it('calls "switchContainerMode" when edit button is clicked', () => { + const switchContainerMode = jest.fn() + + render( + + + + + + ) + + const button = document.querySelector('button') + fireEvent.click(button) + + expect(switchContainerMode).toHaveBeenCalledTimes(1) + expect(switchContainerMode).toHaveBeenCalledWith('edit') + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/__tests__/ViewContainer.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/__tests__/ViewContainer.test.tsx index 35ba0b17b61..ea33841db72 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/__tests__/ViewContainer.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/ViewContainer/__tests__/ViewContainer.test.tsx @@ -4,6 +4,7 @@ import ViewContainer from '../ViewContainer' import { Form } from '../../../..' import nbNO from '../../../../constants/locales/nb-NO' import SectionContainerContext from '../../containers/SectionContainerContext' +import Toolbar from '../../Toolbar' const nb = nbNO['nb-NO'].SectionViewContainer @@ -33,7 +34,7 @@ describe('ViewContainer', () => { expect(element).not.toHaveClass('dnb-height-animation--hidden') }) - it('calls "switchContainerMode" when remove button is clicked', () => { + it('calls "switchContainerMode" when edit button is clicked', () => { const switchContainerMode = jest.fn() render( @@ -111,4 +112,32 @@ describe('ViewContainer', () => { expect(screen.getByText(edit)).toBeInTheDocument() }) + + it('should render default toolbar', () => { + render( + + + Edit Content + + + ) + + expect(document.querySelectorAll('button')).toHaveLength(1) + expect(document.querySelectorAll('button')[0]).toHaveTextContent( + nb.editButton + ) + }) + + it('should render custom toolbar', () => { + render( + + + Edit Content + no button + + + ) + + expect(document.querySelectorAll('button')).toHaveLength(0) + }) }) diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-edit-container.snap.png b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-edit-container.snap.png index 3465c63a025..8564a8bf562 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-edit-container.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-edit-container.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-view-container.snap.png b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-view-container.snap.png index 51a4b1e3833..a1a343b7e57 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-view-container.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-basic-view-container.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-edit-container.snap.png b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-edit-container.snap.png index bade12b9b06..e7012b6e381 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-edit-container.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-edit-container.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-view-container.snap.png b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-view-container.snap.png index 722f34535a3..666f1da95f8 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-view-container.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Form/Section/__tests__/__image_snapshots__/formsection-have-to-match-view-container.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/containers/SectionContainer.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/containers/SectionContainer.tsx index b86126d1e4e..b2c52927db5 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/containers/SectionContainer.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/containers/SectionContainer.tsx @@ -6,7 +6,7 @@ import React, { useRef, } from 'react' import classnames from 'classnames' -import { Flex, HeightAnimation } from '../../../../../components' +import { Card, HeightAnimation } from '../../../../../components' import SectionContainerContext, { SectionContainerContextState, } from './SectionContainerContext' @@ -123,16 +123,17 @@ function SectionContainer(props: Props & FlexContainerProps) { duration={450} keepInDOM // Ensure fields get mounted so they will sync with the data context > - {children} - + ) } diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/containers/Toolbar.tsx b/packages/dnb-eufemia/src/extensions/forms/Form/Section/containers/Toolbar.tsx deleted file mode 100644 index 39fc6a8782b..00000000000 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/containers/Toolbar.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' -import classnames from 'classnames' -import { Hr } from '../../../../../elements' -import { Flex, Space } from '../../../../../components' -import { SpaceAllProps } from '../../../../../components/Space' - -export type Props = SpaceAllProps - -export default function Toolbar(props: Props) { - const { children, className, ...rest } = props || {} - - return ( - -
- - - {children} - -
- ) -} - -Toolbar._supportsSpacingProps = true diff --git a/packages/dnb-eufemia/src/extensions/forms/Form/Section/style/dnb-form-section.scss b/packages/dnb-eufemia/src/extensions/forms/Form/Section/style/dnb-form-section.scss index 44b49d14596..a129448c786 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Form/Section/style/dnb-form-section.scss +++ b/packages/dnb-eufemia/src/extensions/forms/Form/Section/style/dnb-form-section.scss @@ -11,36 +11,23 @@ flex-direction: column; } + &--variant-basic { + --border-color: transparent; + } + &__inner { flex: 1; outline: none; // for JavaSCript focus margin-bottom: var(--space); - padding: var(--padding, 1rem); - - .dnb-forms-section-block--variant-basic &, - &:not([class*='dnb-flex-container--spacing']) { - --padding: 0; + &:has(.dnb-flex-container--spacing-small) { + --space: var(--spacing-small); } - - &[class*='dnb-flex-container--spacing'] { - &.dnb-flex-container--spacing { - &-small { - --space: var(--spacing-small); - } - &-medium { - --space: var(--spacing-medium); - } - &-large { - --space: var(--spacing-large); - } - } - - border-radius: 0.375rem; - - .dnb-forms-section-block--variant-outline & { - box-shadow: inset 0 0 0 2px var(--block-outline-color); - } + &:has(.dnb-flex-container--spacing-medium) { + --space: var(--spacing-medium); + } + &:has(.dnb-flex-container--spacing-large) { + --space: var(--spacing-large); } transition: diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayDocs.ts index 2b59dd228f3..e5912f3d3f7 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayDocs.ts @@ -1,5 +1,5 @@ import { PropertiesTableProps } from '../../../../shared/types' -import { dataValueProperties } from '../../hooks/DataValueDocs' +import { DataValueWritePropsProperties } from '../../hooks/DataValueWritePropsDocs' export const ArrayProperties: PropertiesTableProps = { value: { @@ -52,9 +52,9 @@ export const ArrayProperties: PropertiesTableProps = { type: 'unknown', status: 'optional', }, - validator: dataValueProperties.validator, - validateInitially: dataValueProperties.validateInitially, - continuousValidation: dataValueProperties.continuousValidation, + validator: DataValueWritePropsProperties.validator, + validateInitially: DataValueWritePropsProperties.validateInitially, + continuousValidation: DataValueWritePropsProperties.continuousValidation, containerMode: { doc: 'Defines the container mode for all nested containers. Can be `view`, `edit` or `auto`. When using `auto`, it will automatically open if there is an error in the container. When a new item is added, the item before it will change to `view` mode, if it had no validation errors. Defaults to `auto`.', type: 'string', @@ -65,7 +65,7 @@ export const ArrayProperties: PropertiesTableProps = { type: ['React.ReactNode', 'function'], status: 'optional', }, - '[Flex.Stack](/uilib/layout/flex/stack/)': { + '[Flex.Stack](/uilib/layout/flex/stack/properties)': { doc: 'All Flex.Stack properties.', type: 'Various', status: 'optional', diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayItemArea.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayItemArea.tsx index 8a1ddce7f15..35c9453fca1 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayItemArea.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/ArrayItemArea.tsx @@ -1,6 +1,6 @@ import React, { useCallback, useContext, useReducer, useRef } from 'react' import classnames from 'classnames' -import { Flex, HeightAnimation } from '../../../../components' +import { Card, HeightAnimation } from '../../../../components' import IterateItemContext, { IterateItemContextState, } from '../IterateItemContext' @@ -182,14 +182,15 @@ function ArrayItemArea(props: Props & FlexContainerProps) { duration={450} keepInDOM // Ensure fields get mounted so they will sync with the data context > - {children} - + ) diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-animated-container.snap.png b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-animated-container.snap.png index 0b927d81b34..3fb23e53f55 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-animated-container.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-animated-container.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-edit-container.snap.png b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-edit-container.snap.png index 51b80b43052..673fd378ebc 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-edit-container.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-edit-container.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-view-container.snap.png b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-view-container.snap.png index d854dd7ee4b..c6da7fa8185 100644 Binary files a/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-view-container.snap.png and b/packages/dnb-eufemia/src/extensions/forms/Iterate/Array/__tests__/__image_snapshots__/iteratearray-have-to-match-view-container.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/CancelButton.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/CancelButton.tsx index cc4aa139880..a5605c75533 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/CancelButton.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/CancelButton.tsx @@ -11,7 +11,7 @@ import { ContainerMode } from '../Array' type Props = ButtonProps -export default function EditToolbarTools(props: Props) { +export default function CancelButton(props: Props) { const { onClick, ...rest } = props const { restoreOriginalValue, diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainerDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainerDocs.ts index 167d73bb836..5e7981dc3f1 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainerDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/EditContainerDocs.ts @@ -31,7 +31,7 @@ export const EditContainerProperties: PropertiesTableProps = { type: 'boolean', status: 'optional', }, - '[FlexVertical](/uilib/layout/flex/container/)': { + '[FlexVertical](/uilib/layout/flex/container/properties)': { doc: 'All Flex.Vertical properties.', type: 'Various', status: 'optional', diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/CancelButton.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/CancelButton.test.tsx index 81fce673366..4136ec490b1 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/CancelButton.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/CancelButton.test.tsx @@ -1,9 +1,11 @@ import React from 'react' import { render, fireEvent } from '@testing-library/react' +import FieldBoundaryContext from '../../../DataContext/FieldBoundary/FieldBoundaryContext' import IterateItemContext from '../../IterateItemContext' import Toolbar from '../../Toolbar' import CancelButton from '../CancelButton' import nbNO from '../../../constants/locales/nb-NO' +import ToolbarContext from '../../Toolbar/ToolbarContext' const nb = nbNO['nb-NO'].IterateEditContainer @@ -67,6 +69,139 @@ describe('CancelButton', () => { expect(restoreOriginalValue).toHaveBeenCalledWith('original value') }) + it('should call "setShowError=false" when hasError is true and hasVisibleError is false', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(false) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(false) + }) + + it('should call "setShowError=false" when hasError and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(false) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(false) + }) + + it('should call "setShowError=true" when hasError and hasVisibleError is true and initialContainerMode is "auto"', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(true) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=false" when hasError is false and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(false) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(false) + }) + describe('to have button with correct text', () => { it('and isNew is true', () => { render( diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/DoneButton.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/DoneButton.test.tsx index 0c5ca02404a..c2d7ece6e0f 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/DoneButton.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/DoneButton.test.tsx @@ -4,6 +4,8 @@ import IterateItemContext from '../../IterateItemContext' import Toolbar from '../../Toolbar' import DoneButton from '../DoneButton' import nbNO from '../../../constants/locales/nb-NO' +import FieldBoundaryContext from '../../../DataContext/FieldBoundary/FieldBoundaryContext' +import ToolbarContext from '../../Toolbar/ToolbarContext' const nb = nbNO['nb-NO'].IterateEditContainer @@ -44,6 +46,104 @@ describe('DoneButton', () => { expect(switchContainerMode).toHaveBeenCalledWith('view') }) + it('should not call "setShowError" when hasError is true and hasVisibleError is false', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(0) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=true" when hasError and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(true) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(true) + }) + + it('should call "setShowError=false" when hasError is false and hasVisibleError is true', () => { + const setShowError = jest.fn() + const setShowBoundaryErrors = jest.fn() + + render( + + + + + + + + + + ) + + fireEvent.click(document.querySelector('button')) + expect(setShowError).toHaveBeenCalledTimes(1) + expect(setShowError).toHaveBeenCalledWith(false) + expect(setShowBoundaryErrors).toHaveBeenCalledTimes(1) + expect(setShowBoundaryErrors).toHaveBeenCalledWith(false) + }) + describe('to have button with correct text', () => { it('and isNew is true', () => { render( diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/EditContainer.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/EditContainer.test.tsx index 2c8674a450a..821fe943f01 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/EditContainer.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/EditContainer/__tests__/EditContainer.test.tsx @@ -38,7 +38,7 @@ describe('EditContainer', () => { expect(element).not.toHaveClass('dnb-height-animation--hidden') }) - it('calls "switchContainerMode" when remove button is clicked', () => { + it('calls "switchContainerMode" when edit button is clicked', () => { const switchContainerMode = jest.fn() render( @@ -53,7 +53,7 @@ describe('EditContainer', () => { expect(switchContainerMode).toHaveBeenCalledWith('view') }) - it('calls "switchContainerMode" when remove button is clicked and isNew is true', () => { + it('calls "switchContainerMode" when edit button is clicked and isNew is true', () => { const switchContainerMode = jest.fn() render( diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/EditButton.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/EditButton.tsx index be41361d035..68fbfe65242 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/EditButton.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/EditButton.tsx @@ -4,7 +4,7 @@ import useTranslation from '../../hooks/useTranslation' import IterateItemContext from '../IterateItemContext' import { edit } from '../../../../icons' -export default function ViewContainerEditButton() { +export default function EditButton() { const iterateItemContext = useContext(IterateItemContext) const { switchContainerMode } = iterateItemContext ?? {} const { editButton } = useTranslation().IterateViewContainer diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainerDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainerDocs.ts index 5c2a7fb2dd0..dc92473f35b 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainerDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/ViewContainerDocs.ts @@ -21,7 +21,7 @@ export const ViewContainerProperties: PropertiesTableProps = { type: 'string', status: 'optional', }, - '[FlexVertical](/uilib/layout/flex/container/)': { + '[FlexVertical](/uilib/layout/flex/container/properties)': { doc: 'All Flex.Vertical properties.', type: 'Various', status: 'optional', diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/EditButton.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/EditButton.test.tsx index e07b51753b0..f74983e6209 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/EditButton.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/EditButton.test.tsx @@ -21,7 +21,7 @@ describe('EditButton', () => { expect(button).toHaveTextContent(nb.editButton) }) - it('calls "switchContainerMode" when remove button is clicked', () => { + it('calls "switchContainerMode" when edit button is clicked', () => { const switchContainerMode = jest.fn() render( diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/ViewContainer.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/ViewContainer.test.tsx index 561903d8b94..a9c38dcee6c 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/ViewContainer.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/ViewContainer/__tests__/ViewContainer.test.tsx @@ -37,7 +37,7 @@ describe('ViewContainer', () => { expect(element).not.toHaveClass('dnb-height-animation--hidden') }) - it('calls "switchContainerMode" when remove button is clicked', () => { + it('calls "switchContainerMode" when edit button is clicked', () => { const switchContainerMode = jest.fn() render( diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelection.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelection.tsx index f971d5f2eb9..4d2a3fcb604 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelection.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelection.tsx @@ -3,43 +3,15 @@ import classnames from 'classnames' import { useValueProps } from '../../hooks' import { ValueProps } from '../../types' import ValueBlock from '../../ValueBlock' -import { LOCALE } from '../../../../shared/defaults' import { convertJsxToString } from '../../../../shared/component-helper' -import SharedContext, { InternalLocale } from '../../../../shared/Context' import Context from '../../DataContext/Context' -import { Li, Ol, Ul } from '../../../../elements' +import ListFormat, { + ListFormatProps, +} from '../../../../components/list-format' -export type Props = ValueProps> & { - /** - * Formatting options for the value. - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat - */ - format?: Intl.ListFormatOptions - /** - * Defines if the value should be displayed in list format or regular text format on one line. - * Default: `text` - */ - variant?: 'ol' | 'ul' | 'text' - /** - * Defines the type of list styling used for list variants. Used on conjunction with variant `ol` and `ul`. - * Variant `ol`: `a`, `A`, `i`, `I` and `1`. - * Variant `ul`: `circle`, `disc` and `square`. - * Default: `undefined` - */ - listType?: - | 'a' - | 'A' - | 'i' - | 'I' - | '1' - | 'circle' - | 'disc' - | 'square' - | undefined -} +export type Props = ValueProps> & ListFormatProps function ArraySelection(props: Props) { - const { locale } = useContext(SharedContext) const { fieldPropsRef } = useContext(Context) || {} const { path, @@ -52,7 +24,7 @@ function ArraySelection(props: Props) { } = useValueProps(props) const list = useMemo(() => { - const isListVariant = variant !== 'text' + let valueToUse = value if (path) { const data = fieldPropsRef?.current?.[ @@ -62,69 +34,33 @@ function ArraySelection(props: Props) { title: string | React.ReactNode }> - return ( - data?.map?.(({ title }, index) => - isListVariant ? ( -
  • {convertJsxToString(title)}
  • - ) : ( - convertJsxToString(title) - ) - ) || value - ) + valueToUse = + data?.map?.(({ title }) => convertJsxToString(title)) || value } - return isListVariant - ? value.map((value, index) => ( -
  • {convertJsxToString(value)}
  • - )) - : value - }, [fieldPropsRef, path, value, variant]) - - const listValue = useMemo(() => { - if (variant === 'text') { - return listFormat(list, { locale, format }) + if (typeof valueToUse === 'undefined') { + return undefined } - const ListElement = variant.startsWith('ol') ? Ol : Ul - - return {list} - }, [format, list, locale, variant, listType]) + return ( + + ) + }, [fieldPropsRef, path, value, variant, listType]) return ( - {listValue} + {list} ) } -export function listFormat( - value: Array, - { - locale = LOCALE, - format = { - style: 'long', - type: 'conjunction', - }, - separator = ', ', - }: { - locale?: InternalLocale - format?: Intl.ListFormatOptions - separator?: string - } -) { - if (!Array.isArray(value)) { - return value - } - try { - const formatter = new Intl.ListFormat(locale, format) - return formatter.format(value.map((v) => String(v))) - } catch (error) { - return value.join(separator) - } -} - ArraySelection._supportsSpacingProps = true export default ArraySelection diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelectionDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelectionDocs.ts index 35d594d4337..aa3693316d1 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelectionDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/ArraySelectionDocs.ts @@ -1,29 +1,7 @@ import { PropertiesTableProps } from '../../../../shared/types' +import { ListFormatProperties } from '../../../../components/list-format/ListFormatDocs' + export const ArraySelectionProperties: PropertiesTableProps = { - format: { - doc: 'Formatting options for the value. See the [Intl.ListFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat) documentation.', - type: 'Intl.ListFormatOptions', - status: 'optional', - }, - variant: { - doc: 'Defines if the value should be displayed in list format, or regular text format on one line. Defaults to `text`', - type: ['ol', 'ul', 'text'], - status: 'optional', - }, - listType: { - doc: 'Defines the type of list styling used for list variants. Used on conjunction with variant `ol` and `ul`. Variant `ol`: `a`, `A`, `i`, `I` and `1`. Variant `ul`: `circle`, `disc` and `square`. Defaults to `undefined`', - type: [ - 'a', - 'A', - 'i', - 'I', - '1', - 'circle', - 'disc', - 'square', - 'undefined', - ], - status: 'optional', - }, + ...ListFormatProperties, } diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/__tests__/ArraySelection.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/__tests__/ArraySelection.test.tsx index 4b2510b30ec..6e0404c3c1b 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/__tests__/ArraySelection.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Value/ArraySelection/__tests__/ArraySelection.test.tsx @@ -39,8 +39,9 @@ describe('Value.ArraySelection', () => { }) it('should render different variants', () => { + const values = [123, 456, 789] const { rerender } = render( - + ) const valueBlock = document.querySelector( @@ -54,7 +55,7 @@ describe('Value.ArraySelection', () => { expect(ol).toContainHTML( '
  • 123
  • 456
  • 789
  • ' ) - rerender() + rerender() const ul = valueBlock.querySelector('.dnb-ul') as HTMLUListElement @@ -65,9 +66,7 @@ describe('Value.ArraySelection', () => { '
  • 123
  • 456
  • 789
  • ' ) - rerender( - - ) + rerender() expect(ol).not.toBeInTheDocument() expect(ul).not.toBeInTheDocument() @@ -75,12 +74,9 @@ describe('Value.ArraySelection', () => { }) it('should render different `listTypes`', () => { + const values = [123, 456, 789] const { rerender } = render( - + ) const valueBlock = document.querySelector( @@ -93,29 +89,17 @@ describe('Value.ArraySelection', () => { expect(list('ol')).toHaveAttribute('type', 'a') rerender( - + ) expect(list('ol')).toHaveAttribute('type', 'A') rerender( - + ) expect(list('ol')).toHaveAttribute('type', 'i') rerender( - + ) expect(list('ol')).toHaveAttribute('type', 'I') @@ -123,17 +107,13 @@ describe('Value.ArraySelection', () => { ) expect(list('ul')).toHaveAttribute('type', 'circle') rerender( - + ) expect(list('ul')).toHaveAttribute('type', 'disc') @@ -141,7 +121,7 @@ describe('Value.ArraySelection', () => { ) expect(list('ul')).toHaveAttribute('type', 'square') diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Composition/CompositionDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Value/Composition/CompositionDocs.ts index 7e32eb14d3b..2ac5e88e840 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/Composition/CompositionDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Composition/CompositionDocs.ts @@ -1,10 +1,11 @@ import { PropertiesTableProps } from '../../../../shared/types' import { ValueProperties } from '../ValueDocs' -const { label } = ValueProperties +const { label, transformLabel } = ValueProperties export const CompositionProperties: PropertiesTableProps = { label, + transformLabel, maxWidth: { doc: 'Use `small`, `medium` or `large` for predefined standard max widths. Defaults to `auto`.', type: 'string', diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Composition/__tests__/Composition.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/Composition/__tests__/Composition.test.tsx index b4a715e9b98..36bd01d1020 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/Composition/__tests__/Composition.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Composition/__tests__/Composition.test.tsx @@ -217,4 +217,22 @@ describe('Value.Composition', () => { document.querySelector('.dnb-forms-value-block__label strong') ).toBeInTheDocument() }) + + describe('transformLabel', () => { + it('renders labels', async () => { + render( + label.toUpperCase()} + > + + + + ) + + const label = document.querySelector('.dnb-form-label') + + expect(label.textContent).toBe('LABEL') + }) + }) }) diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/SummaryList/SummaryListDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Value/SummaryList/SummaryListDocs.ts index 14d90f78fc6..7434545cd3a 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/SummaryList/SummaryListDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Value/SummaryList/SummaryListDocs.ts @@ -1,4 +1,7 @@ import { PropertiesTableProps } from '../../../../shared/types' +import { ValueProperties } from '../ValueDocs' + +const { transformLabel } = ValueProperties export const SummaryListProperties: PropertiesTableProps = { layout: { @@ -6,11 +9,6 @@ export const SummaryListProperties: PropertiesTableProps = { type: 'string', status: 'optional', }, - transformLabel: { - doc: 'Transforms the label before it gets displayed. Receives the label as the first parameter. The second parameter is a object containing the `convertJsxToString` function.', - type: 'function', - status: 'optional', - }, inheritVisibility: { doc: 'Use this property to propagate the `inheritVisibility` property to all nested values.', type: 'boolean', @@ -21,6 +19,7 @@ export const SummaryListProperties: PropertiesTableProps = { type: 'boolean', status: 'optional', }, + transformLabel, children: { doc: 'Contents.', type: 'React.Node', diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx new file mode 100644 index 00000000000..7e2f95674ac --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/Upload.tsx @@ -0,0 +1,128 @@ +import React, { useMemo } from 'react' +import classnames from 'classnames' +import { useValueProps } from '../../hooks' +import { ValueProps } from '../../types' +import ValueBlock from '../../ValueBlock' +import { Anchor } from '../../../../components' +import Icon from '../../../../components/Icon' +import ListFormat, { + ListFormatProps, +} from '../../../../components/list-format' +import type { + UploadFile, + UploadProps, +} from '../../../../components/upload/types' +import { fileExtensionImages } from '../../../../components/upload/UploadFileListCell' +import { + BYTES_IN_A_MEGA_BYTE, + getFileTypeFromExtension, +} from '../../../../components/upload/UploadVerify' +import { format } from '../../../../components/number-format/NumberUtils' + +export type Props = ValueProps> & + Omit & + Pick & { + displaySize?: boolean + } + +function Upload(props: Props) { + const { + path, + value, + format, + className, + variant = 'text', + listType, + download = false, + displaySize = false, + ...rest + } = useValueProps(props) + + const list = useMemo(() => { + const valueToUse = + value?.map((uploadFile, index) => { + const { file } = uploadFile || {} + if (!file) { + return + } + const imageUrl = URL.createObjectURL(file) + return ( + + {getIcon(file)} + + {file.name} + {displaySize && getSize(file.size)} + + + ) + }) || undefined + + if (valueToUse) { + return ( + + ) + } + }, [path, value, variant, listType]) + + return ( + + {list} + + ) +} + +function getSize(size: number) { + if (!size) { + return + } + // Converts from b (binary) to MB (decimal) + const sizeInMb = size / BYTES_IN_A_MEGA_BYTE + return ` (${format(sizeInMb, { + decimals: 0, + })} MB)` +} + +function getIcon(file: File) { + if (!file) { + return + } + const fileType = getFileTypeFromExtension(file) + + let iconFileType = fileType + + if (!iconFileType) { + const mimeParts = file.type.split('/') + iconFileType = + fileExtensionImages[mimeParts[0]] || + fileExtensionImages[mimeParts[1]] + } + + if ( + !Object.prototype.hasOwnProperty.call( + fileExtensionImages, + iconFileType + ) + ) { + iconFileType = 'file' + } + + return +} + +Upload._supportsSpacingProps = true +export default Upload diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/UploadDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/UploadDocs.ts new file mode 100644 index 00000000000..29ab7016fc9 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/UploadDocs.ts @@ -0,0 +1,17 @@ +import { PropertiesTableProps } from '../../../../shared/types' + +import { ListFormatProperties } from '../../../../components/list-format/ListFormatDocs' + +export const UploadProperties: PropertiesTableProps = { + download: { + doc: 'Causes the browser to treat all listed files as downloadable instead of opening them in a new browser tab or window. Defaults to `false`.', + type: 'boolean', + status: 'optional', + }, + displaySize: { + doc: 'Can be used to display the file size of the file. Defaults to `false`.', + type: 'boolean', + status: 'optional', + }, + ...ListFormatProperties, +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.screenshot.test.ts b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.screenshot.test.ts new file mode 100644 index 00000000000..410e3b7a300 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.screenshot.test.ts @@ -0,0 +1,38 @@ +import { + makeScreenshot, + setupPageScreenshot, +} from '../../../../../core/jest/jestSetupScreenshots' + +describe('Value.Upload', () => { + setupPageScreenshot({ + url: '/uilib/extensions/forms/Value/Upload/demos/', + }) + + it('have to match default upload value', async () => { + const screenshot = await makeScreenshot({ + selector: '[data-visual-test="upload-value-default"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) + + it('have to match upload displaying size', async () => { + const screenshot = await makeScreenshot({ + selector: '[data-visual-test="upload-value-size"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) + + it('have to list upload inline', async () => { + const screenshot = await makeScreenshot({ + selector: '[data-visual-test="upload-value-inline"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) + + it('have to list upload value', async () => { + const screenshot = await makeScreenshot({ + selector: '[data-visual-test="upload-value-lists"]', + }) + expect(screenshot).toMatchImageSnapshot() + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.test.tsx new file mode 100644 index 00000000000..da1f60417e4 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/Upload.test.tsx @@ -0,0 +1,403 @@ +import React from 'react' +import { screen, render } from '@testing-library/react' +import { Value, Form } from '../../..' +import { createMockFile } from '../../../../../components/upload/__tests__/testHelpers' + +global.URL.createObjectURL = jest.fn(() => 'url') + +const files = [ + { + file: createMockFile('foo.png', 1000000, 'image/png'), + exists: false, + id: '1', + }, + { + file: createMockFile('bar.png', 2000000, 'image/png'), + exists: false, + id: '2', + }, + { + file: createMockFile('baz.png', 3000000, 'image/png'), + exists: false, + id: '3', + }, +] + +describe('Value.Upload', () => { + it('renders file values', () => { + render() + + expect( + document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + ).toHaveTextContent('foo.png, bar.png og baz.png') + }) + + it('renders empty array of file values', () => { + render() + + expect( + document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + ).toHaveTextContent('') + }) + + it('renders array of falsy values', () => { + render() + + expect( + document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + ).toHaveTextContent('') + }) + + it('renders custom format', () => { + render( + + ) + + expect( + document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + ).toHaveTextContent('foo.png, bar.png eller baz.png') + }) + + it('should render different variants', () => { + const { rerender } = render( + + ) + + const valueBlock = document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + + const ol = valueBlock.querySelector('.dnb-ol') as HTMLOListElement + + expect(ol).toBeInTheDocument() + expect(ol.children.length).toBe(3) + + rerender() + + const ul = valueBlock.querySelector('.dnb-ul') as HTMLUListElement + + expect(ol).not.toBeInTheDocument() + expect(ul).toBeInTheDocument() + expect(ul.children.length).toBe(3) + + rerender() + + expect(ol).not.toBeInTheDocument() + expect(ul).not.toBeInTheDocument() + expect(valueBlock).toHaveTextContent('foo.png, bar.png og baz.png') + }) + + it('should render different `listTypes`', () => { + const { rerender } = render( + + ) + + const valueBlock = document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + + const list = (type: 'ol' | 'ul') => + valueBlock.querySelector(`.dnb-${type}`) + + expect(list('ol')).toHaveAttribute('type', 'a') + + rerender() + expect(list('ol')).toHaveAttribute('type', 'A') + + rerender() + expect(list('ol')).toHaveAttribute('type', 'i') + + rerender() + expect(list('ol')).toHaveAttribute('type', 'I') + + rerender() + expect(list('ul')).toHaveAttribute('type', 'circle') + + rerender() + expect(list('ul')).toHaveAttribute('type', 'disc') + + rerender() + expect(list('ul')).toHaveAttribute('type', 'square') + }) + + it('renders label when showEmpty is true', () => { + render() + expect(document.querySelector('.dnb-form-label')).toHaveTextContent( + 'My label' + ) + }) + + it('renders value and label', () => { + render() + expect( + document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + ).toHaveTextContent('foo.png, bar.png og baz.png') + + expect(document.querySelector('.dnb-form-label')).toHaveTextContent( + 'My selections' + ) + }) + + it('renders custom label', () => { + render() + expect(document.querySelector('.dnb-form-label')).toHaveTextContent( + 'Custom label' + ) + }) + + it('renders placeholder', () => { + render() + expect(screen.getByText('Please select a value')).toBeInTheDocument() + }) + + it('renders value from path', () => { + render( + + + + ) + + expect( + document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + ).toHaveTextContent('foo.png, bar.png og baz.png') + }) + + it('formats value in different locale', () => { + render( + + + + ) + + expect( + document.querySelector( + '.dnb-forms-value-upload .dnb-forms-value-block__content' + ) + ).toHaveTextContent('foo.png, bar.png and baz.png') + }) + + describe('Icons', () => { + it('renders the pdf icon', () => { + render( + + ) + + expect( + screen.queryByTestId('file pdf medium icon') + ).toBeInTheDocument() + }) + + it('renders the xls icon', () => { + render( + + ) + + expect( + screen.queryByTestId('file xls medium icon') + ).toBeInTheDocument() + }) + + it('renders the ppt icon', () => { + render( + + ) + + expect( + screen.queryByTestId('file ppt medium icon') + ).toBeInTheDocument() + }) + + it('renders the csv icon', () => { + render( + + ) + + expect( + screen.queryByTestId('file csv medium icon') + ).toBeInTheDocument() + }) + + it('renders the txt icon', () => { + render( + + ) + + expect( + screen.queryByTestId('file txt medium icon') + ).toBeInTheDocument() + }) + + it('renders the xml icon', () => { + render( + + ) + + expect( + screen.queryByTestId('file xml medium icon') + ).toBeInTheDocument() + }) + + it('renders the file icon as default', () => { + render( + + ) + + expect(screen.queryByTestId('file medium icon')).toBeInTheDocument() + }) + }) + + describe('File Anchor', () => { + it('renders the anchor', () => { + const fileName = 'file.png' + + render( + + ) + expect(screen.queryByText(fileName)).toBeInTheDocument() + }) + + it('renders the anchor href', () => { + const fileName = 'file.png' + const mockUrl = 'mock-url' + + global.URL.createObjectURL = jest.fn().mockReturnValueOnce(mockUrl) + + render( + + ) + const anchorElement = screen.queryByText( + fileName + ) as HTMLAnchorElement + expect(anchorElement.href).toMatch(mockUrl) + }) + + it('renders the download attribute', () => { + render( + + ) + + const element = document.querySelector('a') + + expect(element).toHaveAttribute('download', 'file.png') + }) + + it('renders the file size', () => { + const fileName = 'file.png' + + render( + + ) + + expect(screen.queryByText(`${fileName} (1 MB)`)).toBeInTheDocument() + }) + }) +}) diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-list-upload-inline.snap.png b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-list-upload-inline.snap.png new file mode 100644 index 00000000000..b2ddeebe3a8 Binary files /dev/null and b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-list-upload-inline.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-list-upload-value.snap.png b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-list-upload-value.snap.png new file mode 100644 index 00000000000..d5d514f7f1f Binary files /dev/null and b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-list-upload-value.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-default-upload-value.snap.png b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-default-upload-value.snap.png new file mode 100644 index 00000000000..11b559c4559 Binary files /dev/null and b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-default-upload-value.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-upload-displaying-size.snap.png b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-upload-displaying-size.snap.png new file mode 100644 index 00000000000..90181c49bd5 Binary files /dev/null and b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/__tests__/__image_snapshots__/valueupload-have-to-match-upload-displaying-size.snap.png differ diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/index.ts b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/index.ts new file mode 100644 index 00000000000..c2369c59991 --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/index.ts @@ -0,0 +1,2 @@ +export { default } from './Upload' +export * from './Upload' diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/Upload/stories/Upload.stories.tsx b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/stories/Upload.stories.tsx new file mode 100644 index 00000000000..21b18eb069c --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/Value/Upload/stories/Upload.stories.tsx @@ -0,0 +1,94 @@ +import { Form, Value } from '../../..' +import { Card } from '../../../../../components' +import { P } from '../../../../../elements' + +export default { + title: 'Eufemia/Extensions/Forms/Value/Upload', +} + +function createMockFile(name: string, size: number, type: string) { + const file = new File([], name, { type }) + Object.defineProperty(file, 'size', { + get() { + return size + }, + }) + return file +} + +export function Upload() { + return ( + + +

    layout="grid"

    + label.toUpperCase()} + > + + + + + +
    + +

    layout="horizontal"

    + label.toUpperCase()} + > + + + + + +
    + +

    layout="vertical"

    + label.toUpperCase()} + > + + + + + +
    + +

    empty values

    + label.toUpperCase()} + > + + + + + +
    +
    + ) +} diff --git a/packages/dnb-eufemia/src/extensions/forms/Value/index.ts b/packages/dnb-eufemia/src/extensions/forms/Value/index.ts index 05e14cc75f4..bc35941251e 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Value/index.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Value/index.ts @@ -16,3 +16,4 @@ export { default as OrganizationNumber } from './OrganizationNumber' export { default as SelectCountry } from './SelectCountry' export { default as ArraySelection } from './ArraySelection' export { default as Selection } from './Selection' +export { default as Upload } from './Upload' diff --git a/packages/dnb-eufemia/src/extensions/forms/ValueBlock/ValueBlock.tsx b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/ValueBlock.tsx index 9a16ca6bb74..b057b0f58aa 100644 --- a/packages/dnb-eufemia/src/extensions/forms/ValueBlock/ValueBlock.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/ValueBlock.tsx @@ -43,6 +43,7 @@ function ValueBlock(props: Props) { const { className, label: labelProp, + transformLabel = (label: Props['label']) => label, inline, maxWidth = props.composition ? props.maxWidth : 'large', placeholder, @@ -56,14 +57,18 @@ function ValueBlock(props: Props) { if (inline) { return null } + + let label = labelProp + if (iterateIndex !== undefined) { - return convertJsxToString(labelProp).replace( + label = convertJsxToString(labelProp).replace( '{itemNo}', String(iterateIndex + 1) ) } - return labelProp - }, [inline, iterateIndex, labelProp]) + + return transformLabel(label, transformLabelParameters) + }, [inline, iterateIndex, labelProp, transformLabel]) const ref = useRef(null) useNotInSummaryList(valueBlockContext?.composition ? null : ref, label) @@ -205,3 +210,7 @@ function useNotInSummaryList( ValueBlock._supportsSpacingProps = true export default ValueBlock + +const transformLabelParameters = { + convertJsxToString, +} as unknown as Parameters[1] diff --git a/packages/dnb-eufemia/src/extensions/forms/ValueBlock/__tests__/ValueBlock.test.tsx b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/__tests__/ValueBlock.test.tsx index 9fb5c92d8f0..ccb04c3bb22 100644 --- a/packages/dnb-eufemia/src/extensions/forms/ValueBlock/__tests__/ValueBlock.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/__tests__/ValueBlock.test.tsx @@ -2,7 +2,7 @@ import React from 'react' import { axeComponent } from '../../../../core/jest/jestSetup' import { render } from '@testing-library/react' import ValueBlock from '../ValueBlock' -import { Value } from '../..' +import { Form, Value } from '../..' describe('ValueBlock', () => { it('renders without crashing', () => { @@ -274,4 +274,98 @@ describe('ValueBlock', () => { log.mockRestore() }) + + describe('transformLabel', () => { + it('should transform label', () => { + const transformLabel = jest.fn((label) => label.toUpperCase()) + render( + + ) + expect(transformLabel).toHaveBeenCalledTimes(1) + expect(transformLabel).toHaveBeenLastCalledWith( + 'The label', + expect.anything() + ) + expect(document.querySelector('.dnb-form-label')).toHaveTextContent( + 'THE LABEL' + ) + }) + + it('should transform label in Value.String', () => { + const transformLabel = jest.fn((label) => label.toUpperCase()) + render( + + + + ) + expect(transformLabel).toHaveBeenCalledTimes(1) + expect(transformLabel).toHaveBeenLastCalledWith( + 'The label', + expect.anything() + ) + expect( + document.querySelector('.dnb-forms-value-string') + ).toHaveTextContent('THE LABEL') + }) + + it('should transform a JSX label and return "convertJsxToString"', () => { + const transformLabel = jest.fn((label, { convertJsxToString }) => + convertJsxToString(label).toUpperCase() + ) + render( + + The label} + transformLabel={transformLabel} + showEmpty + /> + + ) + expect(transformLabel).toHaveBeenCalledTimes(1) + expect(transformLabel).toHaveBeenLastCalledWith( + The label, + expect.anything() + ) + expect( + document.querySelector('.dnb-forms-value-string') + ).toHaveTextContent('THE LABEL') + }) + + it('should transform label using Value.Provider', () => { + const transformLabel = jest.fn((label) => label.toUpperCase()) + render( + + + + + + + + + ) + + const [first, second] = Array.from(document.querySelectorAll('dt')) + expect(first).toHaveTextContent('THE LABEL A') + expect(second).toHaveTextContent('THE LABEL B') + expect(transformLabel).toHaveBeenCalledTimes(2) + expect(transformLabel).toHaveBeenNthCalledWith( + 1, + 'The label A', + expect.anything() + ) + expect(transformLabel).toHaveBeenNthCalledWith( + 2, + 'The label B', + expect.anything() + ) + }) + }) }) diff --git a/packages/dnb-eufemia/src/extensions/forms/ValueBlock/stories/ValueBlock.stories.tsx b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/stories/ValueBlock.stories.tsx new file mode 100644 index 00000000000..24aaf2e10cf --- /dev/null +++ b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/stories/ValueBlock.stories.tsx @@ -0,0 +1,15 @@ +import { Value } from '../..' +import { P } from '../../../../elements' + +export default { + title: 'Eufemia/Extensions/Forms/ValueBlock', +} + +export function Inline() { + return ( +

    + Max value ( + ) +

    + ) +} diff --git a/packages/dnb-eufemia/src/extensions/forms/ValueBlock/style/dnb-value-block.scss b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/style/dnb-value-block.scss index 8275d3fe422..ca73de76beb 100644 --- a/packages/dnb-eufemia/src/extensions/forms/ValueBlock/style/dnb-value-block.scss +++ b/packages/dnb-eufemia/src/extensions/forms/ValueBlock/style/dnb-value-block.scss @@ -21,16 +21,6 @@ &--inline:not([class*='__composition']) { display: inline-block; - &::before, - &::after { - content: '\00A0'; // non-breaking space - } - .dnb-forms-value-block + & { - &::before { - content: none; - } - } - font-size: inherit; } diff --git a/packages/dnb-eufemia/src/extensions/forms/Wizard/Step/StepDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Wizard/Step/StepDocs.ts index 91108ecbf28..6973c68c76e 100644 --- a/packages/dnb-eufemia/src/extensions/forms/Wizard/Step/StepDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/Wizard/Step/StepDocs.ts @@ -26,7 +26,7 @@ export const StepProperties: PropertiesTableProps = { type: 'React.Node', status: 'required', }, - '[Flex.Container](/uilib/layout/flex/container)': { + '[Flex.Container](/uilib/layout/flex/container/properties)': { doc: 'Flex.Container properties.', type: 'Various', status: 'optional', diff --git a/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/ChildrenWithAge.tsx b/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/ChildrenWithAge.tsx index 134c964f690..4182a009ee2 100644 --- a/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/ChildrenWithAge.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/ChildrenWithAge.tsx @@ -141,6 +141,7 @@ function EditContainer({ tr.ChildrenWithAge.dayCareExpenses.required, }} minimum={1} + maximum={1000000} decimalLimit={0} allowNegative={false} /> @@ -174,6 +175,7 @@ function EditContainer({ tr.ChildrenWithAge.jointResponsibilityExpenses.required, }} minimum={1} + maximum={1000000} decimalLimit={0} allowNegative={false} /> diff --git a/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/ChildrenWithAge.test.tsx b/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/ChildrenWithAge.test.tsx index b360f7871d2..6b2f4e52755 100644 --- a/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/ChildrenWithAge.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/ChildrenWithAge.test.tsx @@ -184,6 +184,55 @@ describe('ChildrenWithAge', () => { expect(screen.queryByRole('alert')).not.toBeInTheDocument() }) + it('should not accept values over 1000000 as joint-responsibility expense', async () => { + render( + + ) + + await userEvent.click(document.querySelectorAll('button')[0]) + await userEvent.click(document.querySelectorAll('button')[4]) + await userEvent.type(document.querySelectorAll('input')[2], '10000001') + + const input = document.querySelectorAll('.dnb-input__input')[2] + + fireEvent.blur(input) + + expect(screen.getByRole('alert')).toHaveTextContent( + nbNO['nb-NO'].NumberField.errorMaximum.replace( + '{maximum}', + '1000000' + ) + ) + }) + + it('should not accept values over 1000000 as daycare expense', async () => { + render() + + await userEvent.click(document.querySelectorAll('button')[0]) + await userEvent.click(document.querySelectorAll('button')[5]) + await userEvent.type(document.querySelectorAll('input')[2], '10000001') + + const input = document.querySelectorAll('.dnb-input__input')[2] + + fireEvent.blur(input) + + expect(screen.getByRole('alert')).toHaveTextContent( + nbNO['nb-NO'].NumberField.errorMaximum.replace( + '{maximum}', + '1000000' + ) + ) + + expect(screen.getByRole('alert')).toHaveTextContent( + nbNO['nb-NO'].NumberField.errorMaximum.replace( + '{maximum}', + '1000000' + ) + ) + }) + it('should show summary with Nei when hasChildren changes to false', async () => { render( diff --git a/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/__snapshots__/ChildrenWithAge.test.tsx.snap b/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/__snapshots__/ChildrenWithAge.test.tsx.snap index 92c012ab23a..e8a459ad2a5 100644 --- a/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/__snapshots__/ChildrenWithAge.test.tsx.snap +++ b/packages/dnb-eufemia/src/extensions/forms/blocks/ChildrenWithAge/__tests__/__snapshots__/ChildrenWithAge.test.tsx.snap @@ -15,9 +15,9 @@ exports[`ChildrenWithAge should match snapshot 1`] = ` aria-placeholder="0" aria-required="true" class="dnb-input__input" - id="id-rbq" + id="id-rdu" inputmode="numeric" - name="id-rbq" + name="id-rdu" type="text" />, }, @@ -125,9 +125,9 @@ exports[`ChildrenWithAge should match snapshot 1`] = ` aria-placeholder="0" aria-required="true" class="dnb-input__input" - id="id-rbv" + id="id-re3" inputmode="numeric" - name="id-rbv" + name="id-re3" type="text" />, }, @@ -331,7 +331,7 @@ exports[`ChildrenWithAge should match snapshot 1`] = ` aria-valuenow="2" aria-valuetext="2" class="dnb-input__input" - id="id-rbg" + id="id-rdk" inputmode="numeric" name="countChildren" role="spinbutton" diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/DataValueDocs.ts b/packages/dnb-eufemia/src/extensions/forms/hooks/DataValueWritePropsDocs.ts similarity index 97% rename from packages/dnb-eufemia/src/extensions/forms/hooks/DataValueDocs.ts rename to packages/dnb-eufemia/src/extensions/forms/hooks/DataValueWritePropsDocs.ts index 53b70ff900b..17613b5a57c 100644 --- a/packages/dnb-eufemia/src/extensions/forms/hooks/DataValueDocs.ts +++ b/packages/dnb-eufemia/src/extensions/forms/hooks/DataValueWritePropsDocs.ts @@ -1,6 +1,6 @@ import { PropertiesTableProps } from '../../../shared/types' -export const dataValueProperties: PropertiesTableProps = { +export const DataValueWritePropsProperties: PropertiesTableProps = { value: { doc: 'Source data value for the field. Will take precedence over the path value given in the data context.', type: '{valueType}', @@ -98,7 +98,7 @@ export const dataValueProperties: PropertiesTableProps = { }, } -export const dataValueEvents: PropertiesTableProps = { +export const DataValueWritePropsEvents: PropertiesTableProps = { onChange: { doc: "Will be called on value changes made by the user, with the new value as argument. When an `async` function is used, the corresponding [FieldBlock](/uilib/extensions/forms/create-component/FieldBlock/) will show an indicator on the field label. You can return `{ success: 'saved' } as const` to show a success symbol, or an error or an object with these keys `{ info: 'Info message', warning: 'Warning message', error: Error('My error') } as const`.", type: '(value) => void', diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useValueProps.test.tsx b/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useValueProps.test.tsx index b93b31f2224..b4a69b54cfc 100644 --- a/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useValueProps.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/hooks/__tests__/useValueProps.test.tsx @@ -663,99 +663,4 @@ describe('useValueProps', () => { } }) }) - - describe('transformLabel', () => { - it('should transform label', () => { - const transformLabel = jest.fn((label) => label.toUpperCase()) - render( - - - - ) - expect(transformLabel).toHaveBeenCalledTimes(1) - expect(transformLabel).toHaveBeenLastCalledWith( - 'The label', - expect.anything() - ) - expect( - document.querySelector('.dnb-forms-value-string') - ).toHaveTextContent('THE LABEL') - }) - - it('should transform a JSX label and return "convertJsxToString"', () => { - const transformLabel = jest.fn((label, { convertJsxToString }) => - convertJsxToString(label).toUpperCase() - ) - render( - - The label} - transformLabel={transformLabel} - showEmpty - /> - - ) - expect(transformLabel).toHaveBeenCalledTimes(1) - expect(transformLabel).toHaveBeenLastCalledWith( - The label, - expect.anything() - ) - expect( - document.querySelector('.dnb-forms-value-string') - ).toHaveTextContent('THE LABEL') - }) - - it('should transform label using inheritLabel', () => { - render( - - - label.toUpperCase()} - showEmpty - /> - - ) - expect( - document.querySelector('.dnb-forms-field-string') - ).toHaveTextContent('The label') - expect( - document.querySelector('.dnb-forms-value-string') - ).toHaveTextContent('THE LABEL') - }) - - it('should transform label using Value.Provider', () => { - const transformLabel = jest.fn((label) => label.toUpperCase()) - render( - - - - - - - - - ) - - const [first, second] = Array.from(document.querySelectorAll('dt')) - expect(first).toHaveTextContent('THE LABEL A') - expect(second).toHaveTextContent('THE LABEL B') - expect(transformLabel).toHaveBeenCalledTimes(2) - expect(transformLabel).toHaveBeenNthCalledWith( - 1, - 'The label A', - expect.anything() - ) - expect(transformLabel).toHaveBeenNthCalledWith( - 2, - 'The label B', - expect.anything() - ) - }) - }) }) diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/useDataValue.ts b/packages/dnb-eufemia/src/extensions/forms/hooks/useDataValue.ts index 2371afe13b2..74a772bb7a7 100644 --- a/packages/dnb-eufemia/src/extensions/forms/hooks/useDataValue.ts +++ b/packages/dnb-eufemia/src/extensions/forms/hooks/useDataValue.ts @@ -2,6 +2,7 @@ import { useCallback, useContext, useRef } from 'react' import pointer from '../utils/json-pointer' import { Path } from '../types' import DataContext, { ContextState } from '../DataContext/Context' +import IterateItemContext from '../Iterate/IterateItemContext' import usePath from './usePath' export type Props = { @@ -16,7 +17,8 @@ export default function useDataValue({ value, }: Props = {}) { const dataContextRef = useRef() - dataContextRef.current = useContext(DataContext) + dataContextRef.current = useContext(DataContext) + const iterateItemContext = useContext(IterateItemContext) const { makePath, makeIteratePath } = usePath() @@ -76,12 +78,16 @@ export default function useDataValue({ const getSourceValue = useCallback( (source: Path | Value) => { if (typeof source === 'string' && isPath(source)) { + if (iterateItemContext) { + return getValueByIteratePath(source) + } + return getValueByPath(source) } return source }, - [getValueByPath] + [getValueByIteratePath, getValueByPath, iterateItemContext] ) if (pathProp) { diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts index bd7266b36f3..4aa47d776e1 100644 --- a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts +++ b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts @@ -32,7 +32,9 @@ import FieldProviderContext from '../Field/Provider/FieldProviderContext' import { combineDescribedBy, warn } from '../../../shared/component-helper' import useId from '../../../shared/helpers/useId' import useUpdateEffect from '../../../shared/helpers/useUpdateEffect' -import FieldBlockContext from '../FieldBlock/FieldBlockContext' +import FieldBlockContext, { + FieldBlockContextProps, +} from '../FieldBlock/FieldBlockContext' import IterateElementContext from '../Iterate/IterateItemContext' import SectionContext from '../Form/Section/SectionContext' import FieldBoundaryContext from '../DataContext/FieldBoundary/FieldBoundaryContext' @@ -208,12 +210,14 @@ export default function useFieldProps( const onChangeContext = dataContext?.props?.onChange const disabled = disabledProp ?? props.readOnly - const inFieldBlock = Boolean(fieldBlockContext) + const inFieldBlock = Boolean( + fieldBlockContext && fieldBlockContext.disableStatusSummary !== true + ) const { setFieldState: setFieldStateFieldBlock, showFieldError: showFieldErrorFieldBlock, mountedFieldsRef: mountedFieldsRefFieldBlock, - } = fieldBlockContext || {} + } = inFieldBlock ? fieldBlockContext : ({} as FieldBlockContextProps) const { handleChange: handleChangeIterateContext, index: iterateIndex, @@ -2154,7 +2158,11 @@ export default function useFieldProps( warning: !inFieldBlock ? warningRef.current : undefined, error: !inFieldBlock ? error : undefined, required, + label: props.label, + labelDescription: props.labelDescription, labelSuffix: props.labelSuffix, + layout: props.layout, + layoutOptions: props.layoutOptions, /** HTML Attributes */ disabled: @@ -2166,6 +2174,8 @@ export default function useFieldProps( /** Internal */ fieldState: resolveValidatingState(fieldStateRef.current), + labelHeight: + typeof props['size'] === 'string' ? props['size'] : undefined, // component/field size } const sharedData = useSharedState('field-block-props-' + id) diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/useValueProps.ts b/packages/dnb-eufemia/src/extensions/forms/hooks/useValueProps.ts index 65fd847eb38..873bc37cac0 100644 --- a/packages/dnb-eufemia/src/extensions/forms/hooks/useValueProps.ts +++ b/packages/dnb-eufemia/src/extensions/forms/hooks/useValueProps.ts @@ -6,7 +6,6 @@ import { useRef, } from 'react' import { Path, ValueProps } from '../types' -import { convertJsxToString } from '../../../shared/component-helper' import useExternalValue from './useExternalValue' import usePath from './usePath' import DataContext from '../DataContext/Context' @@ -14,10 +13,6 @@ import ValueProviderContext from '../Value/Provider/ValueProviderContext' export type Props = ValueProps -const transformLabelParameters = { - convertJsxToString, -} as unknown as Parameters['transformLabel']>[1] - export default function useValueProps< Value = unknown, Props extends ValueProps = ValueProps, @@ -34,7 +29,6 @@ export default function useValueProps< defaultValue, inheritVisibility, inheritLabel, - transformLabel = (label: Props['label']) => label, transformIn = (value: Value) => value, toInput = (value: Value) => value, fromExternal = (value: Value) => value, @@ -93,11 +87,9 @@ export default function useValueProps< ? transformIn(toInput(externalValue)) : undefined - const label = transformLabel( + const label = props.label ?? - (inheritLabel ? fieldPropsRef?.current?.[path]?.label : undefined), - transformLabelParameters - ) + (inheritLabel ? fieldPropsRef?.current?.[path]?.label : undefined) return { ...props, label, value } } diff --git a/packages/dnb-eufemia/src/extensions/forms/types.ts b/packages/dnb-eufemia/src/extensions/forms/types.ts index 98feaa1bc2e..c6841c4c4b2 100644 --- a/packages/dnb-eufemia/src/extensions/forms/types.ts +++ b/packages/dnb-eufemia/src/extensions/forms/types.ts @@ -5,6 +5,7 @@ import type { TransformData, VisibleDataOptions, } from './DataContext' +import type { SharedFieldBlockProps } from './FieldBlock' import type { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema' import type { JSONSchemaType } from 'ajv/dist/2020' import { JsonObject, FormError } from './utils' @@ -264,41 +265,6 @@ export type DataValueReadWriteComponentProps< DataValueReadProps & DataValueWriteProps -export type FieldBlockProps = { - /** - * The layout of the field block - */ - layout?: 'horizontal' | 'vertical' - /** - * Main label text for the field - */ - label?: React.ReactNode - /** - * Will append an additional text to the label, like "(optional)" or "(recommended)" - */ - labelSuffix?: React.ReactNode - /** - * A more discreet text displayed beside the label - */ - labelDescription?: React.ReactNode - /** - * Text showing in place of the value if no value is given - */ - placeholder?: React.ReactNode -} - -/** - * The width of a field block - */ -export type CustomWidth = `${number}rem` -export type FieldBlockWidth = - | false - | 'small' - | 'medium' - | 'large' - | 'stretch' - | CustomWidth - export interface UseFieldProps< Value = unknown, EmptyValue = undefined | unknown, @@ -316,6 +282,10 @@ export interface UseFieldProps< autoComplete?: | HTMLInputElement['autocomplete'] | HTMLTextAreaElement['autocomplete'] + /** + * Text showing in place of the value if no value is given + */ + placeholder?: React.ReactNode /** * NB: Undocumented for now. @@ -434,7 +404,7 @@ export type FieldProps< Value = unknown, EmptyValue = undefined | unknown, ErrorMessages extends DefaultErrorMessages = DefaultErrorMessages, -> = UseFieldProps & FieldBlockProps +> = UseFieldProps & SharedFieldBlockProps export type FieldPropsGeneric< Value = unknown, diff --git a/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/style/dnb-test-element.scss b/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/style/dnb-test-element.scss index 6a340c84705..b82fe612452 100644 --- a/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/style/dnb-test-element.scss +++ b/packages/dnb-eufemia/src/extensions/forms/utils/TestElement/style/dnb-test-element.scss @@ -1,4 +1,6 @@ .dnb-forms-test-element { + display: flex; + width: 100%; border: 1px dashed #808080; border-radius: 0.5rem; color: #909090; diff --git a/packages/dnb-eufemia/src/index.ts b/packages/dnb-eufemia/src/index.ts index 1ff99b13f3c..f017a7fa3c3 100644 --- a/packages/dnb-eufemia/src/index.ts +++ b/packages/dnb-eufemia/src/index.ts @@ -69,6 +69,7 @@ import IconPrimary from './components/icon-primary/IconPrimary' import InfoCard from './components/info-card/InfoCard' import Input from './components/input/Input' import InputMasked from './components/input-masked/InputMasked' +import ListFormat from './components/list-format/ListFormat' import Logo from './components/logo/Logo' import Modal from './components/modal/Modal' import NumberFormat from './components/number-format/NumberFormat' @@ -153,6 +154,7 @@ export { InfoCard, Input, InputMasked, + ListFormat, Logo, Modal, NumberFormat, diff --git a/packages/dnb-eufemia/src/shared/Context.tsx b/packages/dnb-eufemia/src/shared/Context.tsx index 5c552c80eca..3a86c930998 100644 --- a/packages/dnb-eufemia/src/shared/Context.tsx +++ b/packages/dnb-eufemia/src/shared/Context.tsx @@ -48,6 +48,7 @@ import type { ProgressIndicatorProps } from '../components/progress-indicator/ty import type { FormStatusProps } from '../components/FormStatus' import type { LogoProps } from '../components/Logo' import type { IconProps } from '../components/Icon' +import type { ListFormatProps } from '../components/list-format/ListFormat' import type { IconPrimaryProps } from '../components/IconPrimary' import { SwitchProps } from '../components/Switch' @@ -55,6 +56,7 @@ import type { FormElementProps } from './helpers/filterValidProps' import type { ThemeProps } from './Theme' import type { FormsTranslation } from '../extensions/forms/hooks/useTranslation' import type { DeepPartial } from './types' +import { DatePickerProps } from '../components/DatePicker' export type ContextComponents = { Button?: Partial @@ -92,6 +94,8 @@ export type ContextComponents = { Logo?: Partial Icon?: Partial IconPrimary?: Partial + DatePicker?: Partial + ListFormat?: Partial Switch?: Partial // -- TODO: Not converted yet -- diff --git a/packages/dnb-eufemia/src/shared/component-helper.js b/packages/dnb-eufemia/src/shared/component-helper.js index 8398e2c634e..0c7c0454c21 100644 --- a/packages/dnb-eufemia/src/shared/component-helper.js +++ b/packages/dnb-eufemia/src/shared/component-helper.js @@ -462,9 +462,10 @@ export function toCapitalized(str) { /** * [detectOutsideClick Detects a click outside a given DOM element] - * @param {[type]} ignoreElement [The element we want to protect from a click] - * @param {[type]} onSuccess [Will be called on outside click] - * @return {[type]} [void] + * @param {HTMLElement} ignoreElement [The element we want to protect from a click] + * @param {Function} onSuccess [Will be called on outside click] + * @param {Object} [options] [Options] + * @return {DetectOutsideClickClass} [A new instance of DetectOutsideClickClass] */ export const detectOutsideClick = (ignoreElements, onSuccess, options) => new DetectOutsideClickClass(ignoreElements, onSuccess, options) diff --git a/packages/dnb-eufemia/src/style/core/reset.scss b/packages/dnb-eufemia/src/style/core/reset.scss index bedcc090b4e..0abd2473d12 100644 --- a/packages/dnb-eufemia/src/style/core/reset.scss +++ b/packages/dnb-eufemia/src/style/core/reset.scss @@ -255,14 +255,6 @@ text-transform: none; /* 2 */ } - /** - * Correct the padding in Firefox. - */ - - fieldset { - padding: 0.35rem 0.75rem 0.625rem; - } - /** * Show the overflow in Edge and IE. * 1. Safari did inherit the break-word from html root diff --git a/packages/dnb-eufemia/src/style/core/utilities.scss b/packages/dnb-eufemia/src/style/core/utilities.scss index e9ffe1696cb..6f6a8204862 100644 --- a/packages/dnb-eufemia/src/style/core/utilities.scss +++ b/packages/dnb-eufemia/src/style/core/utilities.scss @@ -377,22 +377,18 @@ $breakpoint-offset: 0; } } -@mixin fieldsetReset($checkSpaceProps: false) { - @if $checkSpaceProps { - &:not([class*='space__top']) { - margin-top: 0; - } - &:not([class*='space__right']) { - margin-right: 0; - } - &:not([class*='space__bottom']) { - margin-bottom: 0; - } - &:not([class*='space__left']) { - margin-left: 0; - } - } @else { - margin: 0; +@mixin fieldsetReset() { + &:not([class*='space__top']) { + margin-top: 0; + } + &:not([class*='space__right']) { + margin-right: 0; + } + &:not([class*='space__bottom']) { + margin-bottom: 0; + } + &:not([class*='space__left']) { + margin-left: 0; } padding: 0; border: none; diff --git a/packages/dnb-eufemia/src/style/elements/__tests__/__snapshots__/Elements.test.js.snap b/packages/dnb-eufemia/src/style/elements/__tests__/__snapshots__/Elements.test.js.snap index c96e523debd..f2364b55c58 100644 --- a/packages/dnb-eufemia/src/style/elements/__tests__/__snapshots__/Elements.test.js.snap +++ b/packages/dnb-eufemia/src/style/elements/__tests__/__snapshots__/Elements.test.js.snap @@ -490,6 +490,7 @@ del .dnb-code { display: flex; flex-wrap: wrap; max-width: 60ch; + width: 100%; } .dnb-dl__layout--horizontal dt { margin-top: 0; diff --git a/packages/dnb-eufemia/src/style/themes/theme-sbanken/sbanken-theme-forms.scss b/packages/dnb-eufemia/src/style/themes/theme-sbanken/sbanken-theme-forms.scss index 0cb8b356df3..efa57a57117 100644 --- a/packages/dnb-eufemia/src/style/themes/theme-sbanken/sbanken-theme-forms.scss +++ b/packages/dnb-eufemia/src/style/themes/theme-sbanken/sbanken-theme-forms.scss @@ -16,4 +16,4 @@ $THEME_FALLBACK: 'ui'; @import '../../../extensions/forms/Field/Number/style/themes/dnb-number-theme-sbanken.scss'; @import '../../../extensions/forms/Wizard/style/themes/dnb-wizard-layout-theme-sbanken.scss'; -@import '../../../extensions/forms/FieldBlock/style/themes/dnb-field-block-theme-ui.scss'; +@import '../../../extensions/forms/FieldBlock/style/themes/dnb-field-block-theme-sbanken.scss';