-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
1,130 additions
and
84 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
packages/dnb-design-system-portal/src/docs/uilib/components/list-format.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--- | ||
title: 'ListFormat' | ||
description: 'A ready to use DNB list formatter.' | ||
showTabs: true | ||
tabs: | ||
- title: Info | ||
key: /uilib/components/list-format/info | ||
- title: Demos | ||
key: /uilib/components/list-format/demos | ||
- title: Properties | ||
key: /uilib/components/list-format/properties | ||
theme: 'sbanken' | ||
status: 'new' | ||
--- | ||
|
||
import ListFormatInfo from 'Docs/uilib/components/list-format/info' | ||
import ListFormatDemos from 'Docs/uilib/components/list-format/demos' | ||
|
||
<ListFormatInfo /> | ||
<ListFormatDemos /> |
96 changes: 96 additions & 0 deletions
96
packages/dnb-design-system-portal/src/docs/uilib/components/list-format/Examples.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/** | ||
* UI lib Component Example | ||
* | ||
*/ | ||
|
||
import React from 'react' | ||
import ComponentBox from '../../../../shared/tags/ComponentBox' | ||
import { Provider } from '@dnb/eufemia/src/shared' | ||
import { ListFormat, P } from '@dnb/eufemia/src' | ||
|
||
export const WithValue = () => { | ||
return ( | ||
<ComponentBox data-visual-test="list-format-default"> | ||
<ListFormat value={['Foo', 'Bar', 'Baz']} /> | ||
</ComponentBox> | ||
) | ||
} | ||
|
||
export const WithCustomFormat = () => { | ||
return ( | ||
<ComponentBox data-visual-test="list-format-custom-format"> | ||
<Provider locale="en-GB" data={{ myPath: [123, 456, 789] }}> | ||
<ListFormat | ||
value={[123, 456, 789]} | ||
format={{ type: 'disjunction' }} | ||
/> | ||
</Provider> | ||
</ComponentBox> | ||
) | ||
} | ||
|
||
export const Inline = () => { | ||
return ( | ||
<ComponentBox data-visual-test="list-format-inline"> | ||
<P> | ||
This is before the component{' '} | ||
<ListFormat value={['Foo', 'Bar', 'Baz']} /> This is after the | ||
component | ||
</P> | ||
</ComponentBox> | ||
) | ||
} | ||
|
||
export const ListVariants = () => { | ||
return ( | ||
<ComponentBox data-visual-test="list-format-variants"> | ||
<P>Ordered List:</P> | ||
<ListFormat value={['Foo', 'Bar', 'Baz']} variant="ol" /> | ||
<P>Unordered List:</P> | ||
<ListFormat value={['Foo', 'Bar', 'Baz']} variant="ul" /> | ||
</ComponentBox> | ||
) | ||
} | ||
|
||
export const ListTypes = () => { | ||
return ( | ||
<ComponentBox data-visual-test="list-format-types"> | ||
<P>Ordered List a:</P> | ||
<ListFormat | ||
value={['Foo', 'Bar', 'Baz']} | ||
variant="ol" | ||
listType="a" | ||
/> | ||
<P>Ordered List A:</P> | ||
<ListFormat | ||
value={['Foo', 'Bar', 'Baz']} | ||
variant="ol" | ||
listType="A" | ||
/> | ||
<P>Ordered List i:</P> | ||
<ListFormat | ||
value={['Foo', 'Bar', 'Baz']} | ||
variant="ol" | ||
listType="i" | ||
/> | ||
<P>Ordered List I:</P> | ||
<ListFormat | ||
value={['Foo', 'Bar', 'Baz']} | ||
variant="ol" | ||
listType="I" | ||
/> | ||
<P>Unordered List square:</P> | ||
<ListFormat | ||
value={['Foo', 'Bar', 'Baz']} | ||
variant="ul" | ||
listType="square" | ||
/> | ||
<P>Unordered List circle:</P> | ||
<ListFormat | ||
value={['Foo', 'Bar', 'Baz']} | ||
variant="ul" | ||
listType="circle" | ||
/> | ||
</ComponentBox> | ||
) | ||
} |
27 changes: 27 additions & 0 deletions
27
packages/dnb-design-system-portal/src/docs/uilib/components/list-format/demos.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
showTabs: true | ||
--- | ||
|
||
import * as Examples from './Examples' | ||
|
||
## Demos | ||
|
||
### Value | ||
|
||
<Examples.WithValue /> | ||
|
||
### Custom format | ||
|
||
<Examples.WithCustomFormat /> | ||
|
||
### Inline | ||
|
||
<Examples.Inline /> | ||
|
||
### List variants | ||
|
||
<Examples.ListVariants /> | ||
|
||
### List types | ||
|
||
<Examples.ListTypes /> |
22 changes: 22 additions & 0 deletions
22
packages/dnb-design-system-portal/src/docs/uilib/components/list-format/info.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
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) |
11 changes: 11 additions & 0 deletions
11
...s/dnb-design-system-portal/src/docs/uilib/components/list-format/properties.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
||
<PropertiesTable props={ListFormatProperties} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
160 changes: 160 additions & 0 deletions
160
packages/dnb-eufemia/src/components/list-format/ListFormat.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
import React, { useContext, useMemo } from 'react' | ||
import { LOCALE } from '../../shared/defaults' | ||
import { | ||
convertJsxToString, | ||
extendPropsWithContext, | ||
} from '../../shared/component-helper' | ||
import SharedContext, { InternalLocale } from '../../shared/Context' | ||
import { Li, Ol, Ul } from '../../elements' | ||
|
||
export type ListFormatProps = { | ||
/** | ||
* 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 together 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 | ||
|
||
/** | ||
* The value to format as list. | ||
* Default: null | ||
*/ | ||
value?: Array<number | string | React.ReactNode> | ||
|
||
/** | ||
* The children to format as list. | ||
* Default: null | ||
*/ | ||
children?: React.ReactNode | ||
} | ||
|
||
export const defaultProps = {} | ||
|
||
function ListFormat(localProps: ListFormatProps) { | ||
const { locale, ListFormat } = useContext(SharedContext) | ||
|
||
// Extract additional props from global context | ||
const allProps = extendPropsWithContext( | ||
localProps, | ||
defaultProps, | ||
ListFormat | ||
) | ||
const { value, format, variant = 'text', listType, children } = allProps | ||
|
||
const list = useMemo(() => { | ||
const isListVariant = variant !== 'text' | ||
if (children) { | ||
return isListVariant | ||
? React.Children.map(children, (child: React.ReactNode, index) => { | ||
return <Li key={index}>{child}</Li> | ||
}) | ||
: children | ||
} | ||
return isListVariant | ||
? value.map((value, index) => ( | ||
<Li key={index}> | ||
{React.isValidElement(value) | ||
? value | ||
: convertJsxToString(value)} | ||
</Li> | ||
)) | ||
: value | ||
}, [value, children, variant]) | ||
|
||
const result = useMemo(() => { | ||
if (variant === 'text') { | ||
return listFormat(list, { locale, format }) | ||
} | ||
|
||
const ListElement = variant.startsWith('ol') ? Ol : Ul | ||
|
||
return <ListElement type={listType}>{list}</ListElement> | ||
}, [format, list, locale, variant, listType]) | ||
|
||
return result | ||
} | ||
|
||
// Support for "ListFormat.format(list)" for non-React usage | ||
ListFormat.format = listFormat | ||
|
||
export function listFormat( | ||
list: Array<React.ReactNode> | React.ReactNode, | ||
{ | ||
locale = LOCALE, | ||
format = { | ||
style: 'long', | ||
type: 'conjunction', | ||
}, | ||
}: { | ||
locale?: InternalLocale | ||
format?: Intl.ListFormatOptions | ||
} = {} | ||
) { | ||
if (!Array.isArray(list)) { | ||
return list | ||
} | ||
|
||
const buffer = new Map() | ||
const hasJSX = list.some((v) => typeof v === 'object') | ||
const shadow = list.map((v, i) => { | ||
if (hasJSX) { | ||
const id = `id-${i}` | ||
buffer.set(id, v) | ||
return `{${id}}` | ||
} | ||
|
||
return String(v) | ||
}) | ||
|
||
try { | ||
const formatter = new Intl.ListFormat(locale, format) | ||
const formattedList = formatter.format(shadow) | ||
|
||
if (hasJSX) { | ||
return formattedList.split(/\{(id-[0-9]+)\}/).map((v, i) => { | ||
if (v.startsWith('id-')) { | ||
const element = buffer.get(v) | ||
|
||
return element.key | ||
? element | ||
: // Support lists without a key | ||
React.createElement(React.Fragment, { key: i }, element) | ||
} | ||
|
||
return v | ||
}) | ||
} | ||
|
||
return formattedList | ||
} catch (error) { | ||
if (hasJSX) { | ||
return list | ||
} | ||
|
||
return list.join(', ') | ||
} | ||
} | ||
|
||
ListFormat._supportsSpacingProps = true | ||
|
||
export default ListFormat |
Oops, something went wrong.