diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms.mdx index 9b432d23e2b..67368a7fe23 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms.mdx @@ -8,7 +8,7 @@ breadcrumb: href: /uilib/extensions/forms/ --- -import * as Examples from './forms/Examples' +import QuickStart from './forms/quick-start' import InlineImg from 'dnb-design-system-portal/src/shared/tags/Img' import FormDiagram1 from 'Docs/uilib/extensions/forms/form-diagram-1.png' import FormDiagram2 from 'Docs/uilib/extensions/forms/form-diagram-2.png' @@ -21,69 +21,10 @@ import FormDiagram2 from 'Docs/uilib/extensions/forms/form-diagram-2.png' - [Philosophy](#philosophy) - [Features](#features) - [Examples](#examples) -- [Getting started](#getting-started) +- [First steps](#first-steps) - [Create your own components](#create-your-own-components) -## Quick start - -Field components can be used directly as they are, for example `Field.Email`: - -```jsx -import { Field } from '@dnb/eufemia/extensions/forms' -render() -``` - -By building an entire form with components from Eufemia and Eufemia Forms, you save time and code: - -```jsx -import { Card } from '@dnb/eufemia' -import { Form, Field } from '@dnb/eufemia/extensions/forms' -render( - - - - - - - - - - -) -``` - -Use the [useData](/uilib/extensions/forms/extended-features/Form/useData/) hook to access or modify your form data outside of the form context within your application: - -```jsx -import { Form } from '@dnb/eufemia/extensions/forms' -function Component() { - const { data, update } = Form.useData('unique') - - return ( - - ... - - ) -} -``` + ## Philosophy @@ -107,7 +48,7 @@ In summary: - Ready to use data driven form components. - All functionality in all components can be controlled and overridden via props. -- State management using the declarative [JSON Pointer](/uilib/extensions/forms/#what-is-a-json-pointer) directive (i.e `path="/firstName"`). +- State management using the declarative [JSON Pointer](/uilib/extensions/forms/getting-started/#what-is-a-json-pointer) directive (i.e `path="/firstName"`). - State can be handled outside of the Form.Handler (Provider Context) with the [useData](/uilib/extensions/forms/extended-features/Form/useData) hook. - Simple validation (like `minLength` on text fields) as well as advanced and complex [Ajv](https://ajv.js.org/) JSON schema validator (Ajv is like Joi or Yup – check out [some examples](/uilib/extensions/forms/extended-features/#schema-validation)) support on both single fields and the whole data set. - Building blocks for [creating custom field components](/uilib/extensions/forms/create-component). @@ -146,7 +87,7 @@ In this example, all state data, validation process and error handling are done - [General Demos](/uilib/extensions/forms/general-demos/) - [Case Demo 1 (fullscreen)](/uilib/extensions/forms/demo-cases/casedemo1/) -## Getting started +## First steps You import the components from with scopes, such as `Form` and `Field`: @@ -163,55 +104,11 @@ render( ) ``` -The needed styles are included in the Eufemia core package via `dnb-ui-components`. - -### Field components - -The data-driven [base field components](/uilib/extensions/forms/base-fields) are named and structured according to the type of data they can display and produce based on the user's input and action in the interface. - -On top of these, a number of [feature fields](/uilib/extensions/forms/feature-fields) have been built that have special functionality based on given types of data, such as bank account numbers, e-mails and social security numbers. - -### Value components - -Beside the interactive [Field](/uilib/extensions/forms/fields/) components, there are also the static [Value](/uilib/extensions/forms/extended-features/Value/) components. Use these to show summaries or read-only parts of your application with benefits such as linking to source data and standardized formatting based on the type of data to be displayed. - -### Layout - -When building your application forms, preferably use the following layout components. They seamlessly places all the fields and components of Eufemia Forms correctly into place. - -- [Flex](/uilib/layout/flex) layout component for easy and consistent application forms. -- [Card](/uilib/components/card) for the default card outline of forms. - -### Creating forms - -To build an entire form, there are surrounding components such as [Form.Handler](/uilib/extensions/forms/extended-features/Form/Handler) and [StepsLayout](/uilib/extensions/forms/extended-features/StepsLayout) that make data flow and layout easier and save you a lot of extra code, without compromising flexibility. - -### State management - -The state management is done via the [JSON Pointer](/uilib/extensions/forms/#what-is-a-json-pointer) directive (i.e `path="/firstName"`). This is a standardized way of pointing to a specific part of a JavaScript/JSON object. The JSON Pointer is used to both read and write data, and is also used to validate the data. - - - -### What is a JSON Pointer? - -A [JSON Pointer](https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-json-pointer-03) is a string of tokens separated by `/` characters, these tokens either specify keys in objects or indexes into arrays. - -```ts -const data = { - foo: { - bar: [ - { - baz: 'value', - }, - ], - }, -} -const pointer = '/foo/bar/0/baz' // points to 'value' -``` +More details in the [Getting started](/uilib/extensions/forms/getting-started/) section. -### Best Practices +### Best practices -- [Best Practices on Forms](/uilib/extensions/forms/best-practices-on-forms/). +- [Best practices on Forms](/uilib/extensions/forms/best-practices-on-forms/). ## Create your own components 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 bc34290091e..8c1cc5f2597 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 @@ -13,7 +13,6 @@ import { CreateBasicFieldComponent, CreateComposedFieldComponent, } from './Examples' -import UseDataValue from './create-component/useDataValue/info' # Create your own component @@ -24,12 +23,13 @@ By using the building blocks for field components, you save development time, an ```jsx import { FieldBlock, + ValueBlock, useDataValue, - Iterate, - DataContext, } from '@dnb/eufemia/extensions/forms' ``` + + ## FieldBlock and useDataValue The `FieldBlock` component and the `useDataValue` hook are the basis for all field components in Eufemia Forms. @@ -46,9 +46,9 @@ This example shows a custom component. The `useDataValue` hook receives the prop ### The example explained -Using these two form helpers in your field component triggers several automatic processes. These include timely validation checks, syncing value changes with the `DataContext`, coordinating error messages across multiple fields, and preventing premature error displays while the user is editing the field. +Using these two form helpers in your field component triggers several automatic processes. These include timely validation checks, syncing value changes with the [DataContext](/uilib/extensions/forms/extended-features/DataContext/), coordinating error messages across multiple fields, and preventing premature error displays while the user is editing the field. -Keep in mind, you can customize the behavior of `useDataValue` and other helper functions to make the component work exactly as you want. +Keep in mind, you can customize the behavior of [useDataValue](/) and other helper functions to make the component work exactly as you want. ### Your own validation @@ -79,13 +79,3 @@ These are the official sizes you can use when [creating your own form fields](/u ``` You can also use a [FieldBlock](/uilib/extensions/forms/create-component/FieldBlock/) and provide a `width` prop with a value of either `small`, `medium` or `large` and use it as a sized wrapper. - -## Components - - - ---- - -## Hooks - - diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock.mdx index 72d8ba2277f..8540de199f2 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/FieldBlock.mdx @@ -1,6 +1,6 @@ --- title: 'FieldBlock' -description: '`FieldBlock` is a reusable wrapper for building Field-components. It shows surrounding elements through properties from `FieldProps` like `label` and `error`, and ensure that spacing between different fields work as required when put into surrounding components like `Flex.Container` or `Card`. It can also be used to group multiple inner FieldBlock component, composing error messages together as one component.' +description: '`FieldBlock` is a reusable wrapper for building Field-components. It shows surrounding elements through properties from `FieldProps` like `label` and `error`.' componentType: 'basis-api' hideInMenu: true showTabs: true diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue.mdx new file mode 100644 index 00000000000..cecbbe379cc --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue.mdx @@ -0,0 +1,25 @@ +--- +title: 'useDataValue' +description: 'The `useDataValue` hook standardize handling of the value flow for a single consumer component representing one data point.' +componentType: 'basis-api' +hideInMenu: true +showTabs: true +tabs: + - title: Info + key: '/info' + - title: Demos + key: '/demos' +breadcrumb: + - text: Forms + href: /uilib/extensions/forms/ + - text: Create your component + href: /uilib/extensions/forms/create-component/ + - text: useDataValue + href: /uilib/extensions/forms/create-component/useDataValue/ +--- + +import Info from 'Docs/uilib/extensions/forms/create-component/useDataValue/info' +import Demos from 'Docs/uilib/extensions/forms/create-component/useDataValue/demos' + + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/Examples.tsx new file mode 100644 index 00000000000..4748f2ac66d --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/Examples.tsx @@ -0,0 +1,111 @@ +import React from 'react' +import ComponentBox from '../../../../../../shared/tags/ComponentBox' +import { + Field, + FieldBlock, + Form, + JSONSchema, + useDataValue, +} from '@dnb/eufemia/src/extensions/forms' +import { Flex, Slider } from '@dnb/eufemia/src' + +export const CustomComponentExample = () => { + return ( + + {() => { + const MySliderComponent = (props) => { + const fromInput = React.useCallback( + (event) => + typeof event === 'number' ? event : event?.value || 0, + [], + ) + + const errorMessages = React.useMemo( + () => ({ + required: 'This field is required', + ...props.errorMessages, + }), + [props.errorMessages], + ) + const schema = React.useMemo( + () => + props.schema ?? { + type: 'number', + minimum: props.minimum, + maximum: props.maximum, + }, + [props.schema, props.minimum, props.maximum], + ) + + const preparedProps = { + fromInput, + schema, + ...errorMessages, + label: 'Label', + ...props, + } + + const { + id, + label, + info, + warning, + error, + value, + width = 'medium', + minimum = 0, + maximum = 100, + step = 1, + handleChange, + handleFocus, + handleBlur, + } = useDataValue(preparedProps) + + const steps = { minimum, maximum, step } + + return ( + + + + + + + ) + } + + return ( + + + + ) + }} + + ) +} diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/demos.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/demos.mdx new file mode 100644 index 00000000000..903a39ec3bb --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/demos.mdx @@ -0,0 +1,23 @@ +--- +showTabs: true +--- + +import * as Examples from './Examples' + +## Demos + +On the consumer side, we can use this custom component like so: + +```jsx + + + +``` + + diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/info.mdx index 5e5e6c736e3..931a537bdad 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/create-component/useDataValue/info.mdx @@ -2,11 +2,11 @@ draft: true --- -### useDataValue +# Description The `useDataValue` hook standardize handling of the value flow for a single consumer component representing one data point. It holds error state, hides it while the field is in focus, connects to surrounding `DataContext` (if present) and other things that all field or value components needs to do. By implementing custom field or value components and passing the received props through `useDataValue`, all these features work the same way as other field or value components, and you only need to implement the specific unique features of that component. -How to use: +## How to use ```ts const { value } = useDataValue(componentProps) @@ -38,7 +38,7 @@ const { }) ``` -#### Internal Properties +### Internal Properties All properties are optional and can be used as needed. These properties can be provided as part of your component properties. @@ -62,7 +62,7 @@ All properties are optional and can be used as needed. These properties can be p - `error` object like `FormError` that includes the string to display or an object with the key `validationRule`. More info down below. - `errorMessages` object with your custom messages, where each key represents a `validationRule`. More info down below. -#### Return Parameters +### Return Parameters It returns all of the given component properties, in addition to these: @@ -77,7 +77,7 @@ It returns all of the given component properties, in addition to these: - `onBlur` event handler to assign to a form element. - `onChange` event handler to assign to a form element. -#### Custom validateRequired +### Custom validateRequired ```ts const validateRequired = ( @@ -102,7 +102,7 @@ const { error, hasError } = useDataValue({ }) ``` -##### Validation order +#### Validation order During validation, the different APIs do have a prioritization order and will stop processing further when they match: @@ -110,7 +110,7 @@ During validation, the different APIs do have a prioritization order and will st 1. `schema` prop (including `pattern`) 1. `validator` prop -#### Error handling +### Error handling Validation and error-handling is tight coupled together. When a validation fails, you may use the error-object to handle and show the failures/statuses. @@ -151,7 +151,7 @@ const { error, hasError } = useDataValue({ }) ``` -#### Event handlers +### Event handlers - `handleFocus()` to call the `onFocus` event. @@ -167,7 +167,7 @@ handleChange(value, (additionalArgs = null)) - `forceUpdate()` to re-render the React Hook along with the outer component. -#### Value transformers +### Value transformers The transformers are hooks to transform the value on different stages. diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/extended-features/Form/useData/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/extended-features/Form/useData/info.mdx index b011ab44ef2..8e79082d94b 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/extended-features/Form/useData/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/extended-features/Form/useData/info.mdx @@ -62,7 +62,7 @@ function Component() { If you need to update the data, you can use the `update` method. -It takes a path ([JSON Pointer](/uilib/extensions/forms/#what-is-a-json-pointer)) and a callback function. The callback function receives the existing value as the first argument, and the second argument is the path itself. The callback function must return the new value. +It takes a path ([JSON Pointer](/uilib/extensions/forms/getting-started/#what-is-a-json-pointer)) and a callback function. The callback function receives the existing value as the first argument, and the second argument is the path itself. The callback function must return the new value. ```jsx import { Form } from '@dnb/eufemia/extensions/forms' diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseInputComponents.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseInputComponents.tsx index b5c9aa02319..232d164d2e7 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseInputComponents.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseInputComponents.tsx @@ -44,6 +44,7 @@ export default function ListBaseInputComponents() { diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseSelectionComponents.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseSelectionComponents.tsx index 640e1ba4a47..4039f85a01c 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseSelectionComponents.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseSelectionComponents.tsx @@ -44,6 +44,7 @@ export default function ListBaseSelectionComponents() { diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseToggleComponents.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseToggleComponents.tsx index 05e9a4c09c5..d34387b0452 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseToggleComponents.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/fields/ListBaseToggleComponents.tsx @@ -44,6 +44,7 @@ export default function ListBaseToggleComponents() { diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/getting-started.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/getting-started.mdx new file mode 100644 index 00000000000..7534e3e7763 --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/getting-started.mdx @@ -0,0 +1,86 @@ +--- +title: 'Getting started' +description: 'Forms is reusable components for data input, data display and surrounding layout for simplified user interface creation in React, built on top of base Eufemia components.' +order: 0 +breadcrumb: + - text: Forms + href: /uilib/extensions/forms/ + - text: Getting started + href: /uilib/extensions/forms/getting-started/ +--- + +import * as Examples from './Examples' +import QuickStart from './quick-start' + +# Getting started + +**Table of Contents** + +- [Quick start](#quick-start) +- [Creating forms](#creating-forms) +- [State management](#state-management) +- [Field components](#field-components) +- [Value components](#value-components) +- [Layout](#layout) +- [Best practices](#best-practices) +- [Create your own components](#create-your-own-components) + + + +The needed styles are included in the Eufemia core package via `dnb-ui-components`. + +### Creating forms + +To build an entire form, there are surrounding components such as [Form.Handler](/uilib/extensions/forms/extended-features/Form/Handler) and [StepsLayout](/uilib/extensions/forms/extended-features/StepsLayout) that make data flow and layout easier and save you a lot of extra code, without compromising flexibility. + +### State management + +The state management is done via the [JSON Pointer](#what-is-a-json-pointer) directive (i.e `path="/firstName"`). This is a standardized way of pointing to a specific part of a JavaScript/JSON object. The JSON Pointer is used to both read and write data, and is also used to validate the data. + + + +You find more details in the [useData](/uilib/extensions/forms/extended-features/Form/useData/) docs. + +### What is a JSON Pointer? + +A [JSON Pointer](https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-json-pointer-03) is a string of tokens separated by `/` characters, these tokens either specify keys in objects or indexes into arrays. + +```ts +const data = { + foo: { + bar: [ + { + baz: 'value', + }, + ], + }, +} +const pointer = '/foo/bar/0/baz' // points to 'value' +``` + +### Field components + +The data-driven [base field components](/uilib/extensions/forms/base-fields) are named and structured according to the type of data they can display and produce based on the user's input and action in the interface. + +On top of these, a number of [feature fields](/uilib/extensions/forms/feature-fields) have been built that have special functionality based on given types of data, such as bank account numbers, e-mails and social security numbers. + +### Value components + +Beside the interactive [Field](/uilib/extensions/forms/fields/) components, there are also the static [Value](/uilib/extensions/forms/extended-features/Value/) components. Use these to show summaries or read-only parts of your application with benefits such as linking to source data and standardized formatting based on the type of data to be displayed. + +### Layout + +When building your application forms, preferably use the following layout components. They seamlessly places all the fields and components of Eufemia Forms correctly into place. + +- [Flex](/uilib/layout/flex) layout component for easy and consistent application forms. +- [Card](/uilib/components/card) for the default card outline of forms. + +### Best practices + +- [Best practices on Forms](/uilib/extensions/forms/best-practices-on-forms/). + +## Create your own components + +Eufemia Forms consists of helper components and tools so you can declaratively create interactive form components that flawlessly integrates between existing data and your custom form components. This ensures a common look and feel, even when ready-made components are combined with your local custom components. + +Read more about on how to [create your own component](/uilib/extensions/forms/create-component). diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/quick-start.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/quick-start.mdx new file mode 100644 index 00000000000..9ac7f910dee --- /dev/null +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/quick-start.mdx @@ -0,0 +1,60 @@ +## Quick start + +Field components can be used directly as they are, for example `Field.Email`: + +```jsx +import { Field } from '@dnb/eufemia/extensions/forms' +render() +``` + +By building an entire form with components from Eufemia and Eufemia Forms, you save time and code: + +```jsx +import { Card } from '@dnb/eufemia' +import { Form, Field } from '@dnb/eufemia/extensions/forms' +render( + + + + + + + + + + +) +``` + +Use the [useData](/uilib/extensions/forms/extended-features/Form/useData/) hook to access or modify your form data outside of the form context within your application: + +```jsx +import { Form } from '@dnb/eufemia/extensions/forms' +function Component() { + const { data, update } = Form.useData('unique') + + return ( + + ... + + ) +} +``` diff --git a/packages/dnb-design-system-portal/src/shared/parts/ListSummaryFromEdges.tsx b/packages/dnb-design-system-portal/src/shared/parts/ListSummaryFromEdges.tsx index 562ec3c45c9..54192183811 100644 --- a/packages/dnb-design-system-portal/src/shared/parts/ListSummaryFromEdges.tsx +++ b/packages/dnb-design-system-portal/src/shared/parts/ListSummaryFromEdges.tsx @@ -2,7 +2,10 @@ import React from 'react' import { Ul, Li } from '@dnb/eufemia/src' import AutoLinkHeader from '../tags/AutoLinkHeader' import Anchor from '../tags/Anchor' -import { resetLevels } from '@dnb/eufemia/src/components/Heading' +import { + HeadingSize, + resetLevels, +} from '@dnb/eufemia/src/components/Heading' import ReactMarkdown from 'react-markdown' import { basicComponents } from '../../shared/tags' import { SpacingProps } from '@dnb/eufemia/src/shared/types' @@ -28,14 +31,16 @@ export type ListEdges = Array type ListSummaryFromEdgesProps = { edges: ListEdges level?: HeadingLevel + size?: HeadingSize description?: string returnListItems?: boolean } & SpacingProps export default function ListSummaryFromEdges({ edges, - level = null, - description: _description = null, + level = undefined, + size = undefined, + description: description = null, returnListItems = false, ...props }: ListSummaryFromEdgesProps) { @@ -47,7 +52,7 @@ export default function ListSummaryFromEdges({ ( { node: { - frontmatter: { title, description }, + frontmatter: { title, description: fmDescription }, fields: { slug }, }, }, @@ -73,15 +78,16 @@ export default function ListSummaryFromEdges({ <> {title} - {(_description !== null ? _description : description) && ( + {(description !== null ? description : fmDescription) && ( - {_description !== null ? _description : description} + {description !== null ? description : fmDescription} )}