diff --git a/packages/clay-button/src/Button.tsx b/packages/clay-button/src/Button.tsx index 639e55159a..717b760ae2 100644 --- a/packages/clay-button/src/Button.tsx +++ b/packages/clay-button/src/Button.tsx @@ -106,16 +106,16 @@ const ClayButton = React.forwardRef( ) => { const childArray = React.Children.toArray(children); - warning( - !( - childArray.length === 1 && - // @ts-ignore - childArray[0].type?.displayName === 'ClayIcon' && - typeof otherProps['aria-label'] !== 'string' && - typeof otherProps['aria-labelledby'] !== 'string' - ), - 'Button Accessibility: Component has only the Icon declared. Define an `aria-label` or `aria-labelledby` attribute that labels the interactive button that screen readers can read. The `title` attribute is optional but consult your design team.' - ); + warning( + !( + childArray.length === 1 && + // @ts-ignore + childArray[0].type?.displayName === 'ClayIcon' && + typeof otherProps['aria-label'] !== 'string' && + typeof otherProps['aria-labelledby'] !== 'string' + ), + 'Button Accessibility: Component has only the Icon declared. Define an `aria-label` or `aria-labelledby` attribute that labels the interactive button that screen readers can read. The `title` attribute is optional but consult your design team.' + ); if (displayType === 'beta') { displayType = 'info'; @@ -140,7 +140,6 @@ const ClayButton = React.forwardRef( displayType && !outline && !borderless, [`btn-outline-${displayType}`]: displayType && (outline || borderless), - 'rounded-pill': rounded, [`btn-${size}`]: size && size !== 'regular', })} ref={ref} @@ -151,8 +150,35 @@ const ClayButton = React.forwardRef( ); } -); - -ClayButton.displayName = 'ClayButton'; -export default Object.assign(ClayButton, {Group}); + return ( + - {active && ( - -
- - -
- -
-
-
- )} - - ); -}; - -render()`; - -const FocusTrapExample = () => { - const scope = {Button, FocusTrap, useEffect, useRef, useState}; - - return ; -}; - -export {FocusTrapExample}; diff --git a/packages/clay-core/docs/focus-trap.mdx b/packages/clay-core/docs/focus-trap.mdx index ff30c35bb2..283e93ba3d 100644 --- a/packages/clay-core/docs/focus-trap.mdx +++ b/packages/clay-core/docs/focus-trap.mdx @@ -3,31 +3,60 @@ title: 'Focus Trap' description: 'Focus Trap keeps the focus within its focusable children elements.' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {FocusTrap} from '@clayui/core';" storybookPath: 'design-system-components-focus-trap' --- -import {FocusTrapExample} from '$packages/clay-core/docs/focus-trap'; - - - ## Introduction Focus Trap is a component that wraps elements in the DOM and prevents focus from escaping from its child components when the user navigates with Tab or Shift + Tab. It definitely is used when trying to build accessible components, blocking all interactions outside of it while Focus Trap is active. -
+
It's the responsibility of the user to add an escape method for the focus trap, either with a button or the escape key.
## Example - +```jsx preview +import {Provider, Button, FocusTrap} from '@clayui/core'; +import React, {useEffect, useRef, useState} from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + const [active, setActive] = useState(false); + const activateButtonRef = useRef(null); + + useEffect(() => { + if (active) { + return () => activateButtonRef.current?.focus(); + } + }, [active]); + + return ( + +
+ + {active && ( + +
+ + +
+ +
+
+
+ )} +
+
+ ); +} +``` diff --git a/packages/clay-core/docs/heading.js b/packages/clay-core/docs/heading.js deleted file mode 100644 index 3ec88d9dcd..0000000000 --- a/packages/clay-core/docs/heading.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * SPDX-FileCopyrightText: © 2022 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Editor from '$clayui.com/src/components/Editor'; -import {Heading} from '@clayui/core'; -import React from 'react'; - -const exampleImports = `import {Heading} from '@clayui/core'; -import React from 'react';`; - -const exampleLevelCode = `const Component = () => { - - return ( - <> - - h1. Heading Level 1 - - - h2. Heading Level 2 - - - h3. Heading Level 3 - - - h4. Heading Level 4 - - - h5. Heading Level 5 - - - h6. Heading Level 6 - - - ); -}; - -render()`; - -export const HeadingLevel = () => { - const scope = {Heading}; - - return ( - - ); -}; - -const exampleWeightCode = `const Component = () => { - - return ( - <> - - Heading with ligther weight - - - Heading with light weight - - - Heading with normal weight - - - Heading with semi-bold weight - - - Heading with bold weight - - - Heading with bolder weight - - - ); - }; - - render()`; - -export const HeadingWeight = () => { - const scope = {Heading}; - - return ( - - ); -}; diff --git a/packages/clay-core/docs/heading.mdx b/packages/clay-core/docs/heading.mdx index fa823f383d..c04a92da2b 100644 --- a/packages/clay-core/docs/heading.mdx +++ b/packages/clay-core/docs/heading.mdx @@ -3,21 +3,10 @@ title: 'Heading' description: 'Heading creates a title or subject of an article or another piece of written work.' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {Heading} from '@clayui/core';" storybookPath: 'design-system-components-typography--heading-typography' --- -import {HeadingLevel, HeadingWeight} from '$packages/clay-core/docs/heading'; - - - ## Introduction Heading is a component that creates a title or a subject of an article or a pice of work. This a proposal created using the `h1` tag which you can modify the `weight` and the `level` of the component. @@ -26,10 +15,74 @@ Heading is a component that creates a title or a subject of an article or a pice By default, the semantic of the heading level is level 1 in which the component will render as an `h1` element. However, if you need to change the semantic of the level, you just provide it using the `level` property from 1 to 6. - +```jsx preview +import {Provider, Heading} from '@clayui/core'; +import React from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( + +
+ + h1. Heading Level 1 + + + h2. Heading Level 2 + + + h3. Heading Level 3 + + + h4. Heading Level 4 + + + h5. Heading Level 5 + + + h6. Heading Level 6 + +
+
+ ); +} +``` ## Font Weights In the same way, Heading component provides some styles depending on the `weight`. You can check them [here](/docs/css/utilities/markup-text.html#css-text-weights). - +```jsx preview +import {Provider, Heading} from '@clayui/core'; +import React from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( + +
+ + Heading with ligther weight + + + Heading with light weight + + + Heading with normal weight + + + Heading with semi-bold weight + + + Heading with bold weight + + + Heading with bolder weight + +
+
+ ); +} +``` diff --git a/packages/clay-core/docs/overlay-mask.js b/packages/clay-core/docs/overlay-mask.js deleted file mode 100644 index 8af1cb4486..0000000000 --- a/packages/clay-core/docs/overlay-mask.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * SPDX-FileCopyrightText: © 2022 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Editor from '$clayui.com/src/components/Editor'; -import {Button, OverlayMask} from '@clayui/core'; -import React, {useState} from 'react'; - -const exampleImports = `import {Button, OverlayMask} from '@clayui/core'; -import React, {useState} from 'react';`; - -const exampleCode = `const OverlayTrigger = () => { - const [visible, setVisible] = useState(false); - - return ( - - - setVisible(false)} visible={visible}> - - - - ); -}; - -render()`; - -const OverlayMaskExample = () => { - const scope = {Button, OverlayMask, useState}; - - return ; -}; - -export {OverlayMaskExample}; diff --git a/packages/clay-core/docs/overlay-mask.mdx b/packages/clay-core/docs/overlay-mask.mdx index 645a537b47..612e0842f6 100644 --- a/packages/clay-core/docs/overlay-mask.mdx +++ b/packages/clay-core/docs/overlay-mask.mdx @@ -3,26 +3,44 @@ title: 'OverlayMask' description: 'OverlayMask create a highlight area on some DOM element with overlay.' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {OverlayMask} from '@clayui/core';" storybookPath: 'design-system-components-overlaymask' --- -import {OverlayMaskExample} from '$packages/clay-core/docs/overlay-mask'; - - - ## Example - +```jsx preview +import {Provider, Button, OverlayMask} from '@clayui/core'; +import React, {useState} from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + const [visible, setVisible] = useState(false); + + return ( + +
+ + + setVisible(false)} + visible={visible} + > + + + +
+
+ ); +} +``` ## Introduction @@ -62,14 +80,14 @@ const logo = document.body.querySelector('.logo'); const {height, width, x, y} = logo.getBoundingClientRect(); + defaultBounds={{ + height, + width, + x, + y, + }} + visible +/>; // or @@ -80,11 +98,7 @@ const [bounds, setBounds] = useState({ y: 0, }); -useEffect(() => {...}, []); +useEffect(() => {}, []); - +; ``` diff --git a/packages/clay-core/docs/picker.js b/packages/clay-core/docs/picker.js deleted file mode 100644 index 3997d385de..0000000000 --- a/packages/clay-core/docs/picker.js +++ /dev/null @@ -1,313 +0,0 @@ -/** - * SPDX-FileCopyrightText: © 2022 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Editor from '$clayui.com/src/components/Editor'; -import {Option, Picker, Text} from '@clayui/core'; -import DropDown from '@clayui/drop-down'; -import Form from '@clayui/form'; -import Icon from '@clayui/icon'; -import Label from '@clayui/label'; -import Layout from '@clayui/layout'; -import {useId} from '@clayui/shared'; -import React from 'react'; - -const PickerWidthExample = () => { - const imports = `import {Option, Picker} from '@clayui/core'; -import Form from '@clayui/form'; -import React from 'react';`; - - const code = `const CustomWidth = () => { - return ( -
- - - - {(item) => } - - -
- ); -}; - -render()`; - - return ( - - ); -}; - -const exampleImports = `import {Option, Picker} from '@clayui/core'; -import Form from '@clayui/form'; -import React from 'react';`; - -const exampleCode = `const SelectAnFruit = () => { - return ( -
- - - - {(item) => } - - -
- ); -}; - -render()`; - -const PickerExample = () => { - const scope = {Form, Option, Picker}; - - return ; -}; - -const exampleTriggerImports = `import {Option, Picker} from '@clayui/core'; -import Form from '@clayui/form'; -import Icon from '@clayui/icon'; -import React from 'react';`; - -const exampleTriggerCode = `const Trigger = React.forwardRef(({children, ...otherProps}, ref) => ( -
- - {children} -
-)); - -const CustomTrigger = () => { - const pickerId = useId(); - const labelId = useId(); - - return ( -
- - - - {(item) => } - - -
- ); -}; - -render()`; - -const PickerTriggerExample = () => { - const scope = {Form, Icon, Option, Picker, React, useId}; - - return ( - - ); -}; - -const exampleOptionsImports = `import {Option, Picker} from '@clayui/core'; -import Form from '@clayui/form'; -import React from 'react';`; - -const exampleOptionsCode = `const CustomOptions = () => { - const pickerId = useId(); - const labelId = useId(); - - return ( -
- - - - {(item) => ( - - )} - - -
- ); -}; - -render()`; - -const PickerOptionsxample = () => { - const scope = { - Form, - Icon, - Label, - Layout, - Option, - Picker, - React, - Text, - useId, - }; - - return ( - - ); -}; - -const exampleGroupImports = `import {Option, Picker} from '@clayui/core'; -import Form from '@clayui/form'; -import Icon from '@clayui/icon'; -import React from 'react';`; - -const exampleGroupCode = `const Trigger = React.forwardRef(({children, ...otherProps}, ref) => ( -
- - {children} -
-)); - -const CustomTrigger = () => { - const pickerId = useId(); - const labelId = useId(); - - return ( -
- - - - {(group) => ( - - {(item) => ( - - )} - - )} - - -
- ); -}; - -render()`; - -const PickerGroupExample = () => { - const scope = {DropDown, Form, Option, Picker, React, useId}; - - return ( - - ); -}; -export { - PickerWidthExample, - PickerExample, - PickerGroupExample, - PickerTriggerExample, - PickerOptionsxample, -}; diff --git a/packages/clay-core/docs/picker.mdx b/packages/clay-core/docs/picker.mdx index 00f80bd099..1e15678e19 100644 --- a/packages/clay-core/docs/picker.mdx +++ b/packages/clay-core/docs/picker.mdx @@ -3,39 +3,54 @@ title: 'Picker' description: 'A select is very similar to a dropdown visually but it let users select options from the panel and then represent the selection in the button.' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {Option, Picker} from '@clayui/core';" storybookPath: 'design-system-components-picker' --- -import { - PickerWidthExample, - PickerExample, - PickerGroupExample, - PickerTriggerExample, - PickerOptionsxample, -} from '$packages/clay-core/docs/picker'; - - +```jsx preview +import {Provider, Option, Picker} from '@clayui/core'; +import Form from '@clayui/form'; +import React from 'react'; -## Example +import '@clayui/css/lib/css/atlas.css'; - +export default function App() { + return ( + +
+
+ + + + {(item) => } + + +
+
+
+ ); +} +``` ## Introduction @@ -94,19 +109,18 @@ For the `` component you can control the `selectedKey` and `active` st If you just need to set the initial state of the `selectedKey`, use the `defaultSelectedKey` property which is appropriate for that use case. -
- Info - The selectedKey property is represented by - the key property configured in the - Option - component, so the component can identify which value is selected and - which should be shown in the trigger.
+
+ Info + The selectedKey property is represented + by the key property configured in the{' '} + Option component, so the component can + identify which value is selected and which should be shown in the trigger.

- When the content rendering is dynamic and the data has + When the content rendering is dynamic and the data has id - property defined, the component uses + property defined, the component uses id - instead of key. + instead of key.
```jsx @@ -145,28 +159,232 @@ The composition allows you to customize the component or add new features. See s ### Custom Trigger - +```jsx preview +import {Provider, Option, Picker, Icon} from '@clayui/core'; +import {useId} from '@clayui/shared'; +import Form from '@clayui/form'; +import React from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +const Trigger = React.forwardRef(({children, ...otherProps}, ref) => ( +
+ + {children} +
+)); + +export default function App() { + const pickerId = useId(); + const labelId = useId(); + + return ( + +
+
+ + + + {(item) => } + + +
+
+
+ ); +} +``` ### Custom Options - +```jsx preview +import {Provider, Option, Picker, Text} from '@clayui/core'; +import {useId} from '@clayui/shared'; +import Layout from '@clayui/layout'; +import Label from '@clayui/label'; +import Form from '@clayui/form'; +import React from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + const pickerId = useId(); + const labelId = useId(); + + return ( + +
+
+ + + + {(item) => ( + + )} + + +
+
+
+ ); +} +``` ### Group - +```jsx preview +import {Provider, Option, Picker} from '@clayui/core'; +import {useId} from '@clayui/shared'; +import DropDown from '@clayui/drop-down'; +import Form from '@clayui/form'; +import React from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + const pickerId = useId(); + const labelId = useId(); + + return ( + +
+
+ + + + {(group) => ( + + {(item) => ( + + )} + + )} + + +
+
+
+ ); +} +``` ## Flexible width - +```jsx preview +import {Provider, Option, Picker} from '@clayui/core'; +import Form from '@clayui/form'; +import React from 'react'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( + +
+
+ + + + {(item) => } + + +
+
+
+ ); +} +``` ## Hybrid component Native select for mobile devices offers a better experience compared to Picker in some cases. The Picker offers the possibility to render using the native selector of the browser of the device when it is detected that it is on a mobile device, by default this property is disabled but it can be enabled by setting the `native` property to `true`. -
- Warning +
+ Warning If the content of the Option component is not simple text, for it to work correctly - set the property textValue to ensure that + set the property textValue to ensure that the component knows what the option label is.
diff --git a/packages/clay-core/docs/reduced-motion.mdx b/packages/clay-core/docs/reduced-motion.mdx index a632f109a9..6abae1e6fd 100644 --- a/packages/clay-core/docs/reduced-motion.mdx +++ b/packages/clay-core/docs/reduced-motion.mdx @@ -2,18 +2,9 @@ title: 'Reduced Motion' description: 'Provider component which aggregates the main Clay, Icon, and Modal.' packageNpm: '@clayui/core' +packageUse: "import {Provider} from '@clayui/core';" --- - - ## Introduction Setting the motion reduction of animations can be done in two different ways in Clay, transitions that are done purely in CSS can use the `c-prefers-reduced-motion` class and transitions that are made with JS are defined using Clay's `Provider` component. diff --git a/packages/clay-core/docs/table.js b/packages/clay-core/docs/table.js deleted file mode 100644 index aa8bbc8521..0000000000 --- a/packages/clay-core/docs/table.js +++ /dev/null @@ -1,149 +0,0 @@ -/** - * SPDX-FileCopyrightText: © 2019 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Editor from '$clayui.com/src/components/Editor'; -import {Body, Cell, Head, Row, Table, Text} from '@clayui/core'; -import React, {useCallback, useState} from 'react'; - -const tableImportsCode = `import React, {useCallback, useState} from 'react'; -import {Body, Cell, Head, Row, Table} from '@clayui/core';`; - -const tableCode = `const TableExample = () => { - const [sort, setSort] = useState(null); - const [items, setItems] = useState([ - {files: 22, id: 1, name: 'Games', type: 'File folder'}, - {files: 7, id: 2, name: 'Program Files', type: 'File folder'}, - ]); - - const onSortChange = useCallback((sort) => { - if (sort) { - setItems((items) => - items.sort((a, b) => { - let cmp = new Intl.Collator('en', {numeric: true}).compare( - a[sort.column], - b[sort.column] - ); - - if (sort.direction === 'descending') { - cmp *= -1; - } - - return cmp; - }) - ); - } - - setSort(sort); - }, []); - - return ( - - - {(column) => {column.name}} - - - - {(row) => ( - - {row['name']} - {row['files']} - {row['type']} - - )} - -
- ); -} - -render()`; - -const TableExample = () => { - const scope = {Body, Cell, Head, Row, Table, Text, useCallback, useState}; - - return ; -}; - -const tableTreeImportsCode = `import React, {useCallback, useState} from 'react'; -import {Body, Cell, Head, Row, Table} from '@clayui/core';`; - -const tableTreeCode = `const TableExample = () => { - const columns = [ - { - id: 'name', - name: 'Name', - }, - { - id: 'type', - name: 'Type', - }, - ]; - - return ( - - - {(column) => ( - - {column.name} - - )} - - - - {(row) => ( - - {(column) => ( - - {row[column.id]} - - )} - - )} - -
- ); -} - -render()`; - -const TableTreeExample = () => { - const scope = {Body, Cell, Head, Row, Table, Text, useCallback, useState}; - - return ( - - ); -}; - -export {TableExample, TableTreeExample}; diff --git a/packages/clay-core/docs/table.mdx b/packages/clay-core/docs/table.mdx index 18fc5354c9..06f966118d 100644 --- a/packages/clay-core/docs/table.mdx +++ b/packages/clay-core/docs/table.mdx @@ -4,32 +4,92 @@ description: 'A table is a specific pattern for comparing datasets in a very dir lexiconDefinition: 'https://liferay.design/lexicon/core-components/table/' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {Body, Cell, Head, Row, Table} from '@clayui/core';" storybookPath: 'design-system-components-table--dynamic' --- - +```jsx preview +import React, {useCallback, useState} from 'react'; +import {Body, Cell, Text, Head, Row, Table, Provider} from '@clayui/core'; -import {TableExample, TableTreeExample} from '$packages/clay-core/docs/table'; +import '@clayui/css/lib/css/atlas.css'; -## Example +export default function App() { + const [sort, setSort] = useState(null); + const [items, setItems] = useState([ + {files: 22, id: 1, name: 'Games', type: 'File folder'}, + {files: 7, id: 2, name: 'Program Files', type: 'File folder'}, + ]); + + const onSortChange = useCallback((sort) => { + if (sort) { + setItems((items) => + items.sort((a, b) => { + let cmp = new Intl.Collator('en', {numeric: true}).compare( + a[sort.column], + b[sort.column] + ); + + if (sort.direction === 'descending') { + cmp *= -1; + } + + return cmp; + }) + ); + } - + setSort(sort); + }, []); + + return ( + +
+ + + {(column) => ( + + {column.name} + + )} + + + + {(row) => ( + + + + {row['name']} + + + {row['files']} + {row['type']} + + )} + +
+
+
+ ); +} +``` ## Introduction @@ -37,10 +97,10 @@ Table allows the rendering of static and dynamic content for data-oriented and d The component covers the [W3C accessibility](https://www.w3.org/WAI/ARIA) patterns for the [simplest table implementation](https://www.w3.org/WAI/tutorials/tables/) and also the [treegrid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treegrid/examples/treegrid-1/) for when [nested row](#nested-row) is used without requiring the developer to have to configure something extremely complex. -
- Warning +
+ Warning To use the new Table implementation it is necessary to consume the component - using the package @clayui/core. + using the package @clayui/core.
## Content @@ -110,8 +170,8 @@ Unlike static content, dynamic content is when the options can change during the ## Icons -
- Warning +
+ Warning When implementing ClayTable from a React application, the icons may not render. The Application Provider @@ -119,10 +179,6 @@ Unlike static content, dynamic content is when the options can change during the
```jsx -import {Provider} from '@clayui/core'; - -const spritemap = 'icons.svg'; -
-
; + ``` ## Sorting @@ -163,56 +219,58 @@ Column sorting is implemented OOTB so the developer doesn't need to worry about It is also possible to implement your own logic on the client side when your data is predictable, check out the pseudocode. -
- Info - Column sorting is only enabled for columns that contain the +
+ Info + Column sorting is only enabled for columns that contain the sortable API defined.
```jsx -const [sort, setSort] = useState(null); -const [items, setItems] = useState([ - {files: 22, id: 1, name: 'Games', type: 'File folder'}, - {files: 7, id: 2, name: 'Program Files', type: 'File folder'}, -]); - -const filteredItems = useMemo(() => { - if (!sort) { - return; - } - - return items.sort((a, b) => { - let cmp = new Intl.Collator('en', {numeric: true}).compare( - a[sort.column], - b[sort.column] - ); - - if (sort.direction === 'descending') { - cmp *= -1; - } - - return cmp; - }); -}, [sort, items]) - - - - - Name - - - Files - - - Type - - - - - ... - -
+export function App() { + const [sort, setSort] = (useState < Sorting) | (null > null); + const [items, setItems] = useState([ + {files: 22, id: 1, name: 'Games', type: 'File folder'}, + {files: 7, id: 2, name: 'Program Files', type: 'File folder'}, + ]); + + const filteredItems = useMemo(() => { + if (!sort) { + return; + } + + return items.sort((a, b) => { + let cmp = new Intl.Collator('en', {numeric: true}).compare( + a[sort.column], + b[sort.column] + ); + + if (sort.direction === 'descending') { + cmp *= -1; + } + + return cmp; + }); + }, [sort, items]); + + return ( + + + + Name + + + Files + + + Type + + + + ... +
+ ); +} ``` ### Asynchronous @@ -220,37 +278,41 @@ const filteredItems = useMemo(() => { Most tables with sorting can have a lot of data and are paged so the sorting must happen on the server side instead of implementing the logic on the client side. You can achieve this level of implementation by composing using the [`useResource` hook](/docs/components/data-provider.html). ```jsx -const { - resource: items, - sort, - sortChange, -} = useResource({ - fetch: (link, init, sort) => { - const url = new URL(link); - - if (sort) { - url.searchParams.append('column', String(sort.column)); - url.searchParams.append('direction', sort.direction); - } - - return fetch(url, init); - }, - link: 'https://example.com/api/items', -}); - - - - - Name - - - Files - - Type - - - ... -
; +function App() { + const { + resource: items, + sort, + sortChange, + } = useResource({ + fetch: (link, init, sort) => { + const url = new URL(link); + + if (sort) { + url.searchParams.append('column', String(sort.column)); + url.searchParams.append('direction', sort.direction); + } + + return fetch(url, init); + }, + link: 'https://example.com/api/items', + }); + + return ( + + + + Name + + + Files + + Type + + + ... +
+ ); +} ``` ## Nested row @@ -259,17 +321,82 @@ Implementing nested row allows you to render a table as a tree view. It is not n When using the nested row pattern, Clay automatically changes the accessibility behavior to use the [treegrid](https://www.w3.org/WAI/ARIA/apg/patterns/treegrid/examples/treegrid-1/) recommendation instead of the default behavior. -
- Limitation - The unique id of a row does not work properly when configured via +
+ Limitation + The unique id of a row does not work properly when configured via key - in the Row component property to deal - with the nodes expandability, it is necessary that the + in the Row component property + to deal with the nodes expandability, it is necessary that the id key is defined in your row data to use as unique id.
- +```jsx preview +import React from 'react'; +import {Body, Cell, Head, Row, Table, Provider} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + const columns = [ + { + id: 'name', + name: 'Name', + }, + { + id: 'type', + name: 'Type', + }, + ]; + + return ( + +
+ + + {(column) => ( + + {column.name} + + )} + + + + {(row) => ( + + {(column) => ( + + {row[column.id]} + + )} + + )} + +
+
+
+ ); +} +``` ### Expandable @@ -300,8 +427,8 @@ When the tree is very large with a lot of data on a single node, loading the dat - When returning `void`, `null` or `undefined` the Table will do nothing. - When returning the `items` will add to the tree. -
- Warning +
+ Warning If you have an error in the asynchronous call of the onLoadMore method, only the suppression is done and an error is thrown on the console. diff --git a/packages/clay-core/docs/text.js b/packages/clay-core/docs/text.js deleted file mode 100644 index ede55a2651..0000000000 --- a/packages/clay-core/docs/text.js +++ /dev/null @@ -1,289 +0,0 @@ -/** - * SPDX-FileCopyrightText: © 2022 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -/** - * SPDX-FileCopyrightText: © 2022 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Editor from '$clayui.com/src/components/Editor'; -import {Text, TextHighlight} from '@clayui/core'; -import React from 'react'; - -const exampleImports = `import {Text} from '@clayui/core'; -import React from 'react';`; - -const exampleSizeCode = `const Component = () => { - - -return ( - <> -
- - Text Size Level 11 - -
-
- - Text Size Level 10 - -
-
- - Text Size Level 9 - -
-
- - Text Size Level 8 - -
-
- - Text Size Level 7 - -
-
- - Text Size Level 6 - -
-
- - Text Size Level 5 - -
-
- - Text Size Level 4 - -
-
- - Text Size Level 3 - -
-
- - Text Size Level 2 - -
-
- - Text Size Level 1 - -
- - ); -}; - -render()`; - -export const TextSize = () => { - const scope = {Text}; - - return ( - - ); -}; - -const exampleItalicCode = `const Component = () => { - - return ( - <> - - Single origin, extra id beans, eu to go, skinny americano ut - aftertas te sugar. At americano, viennese variety iced grounds, - grinder froth and pumpkin spice aromatic. Cultivar aged lungo, - grounds café au lait, skinny, blue mountain, in variety sugar - shop roast. Wings, blue mountain affogato organic cappuccino - java plunger pot. Single shot variety pumpkin spice seasonal - skinny barista carajillo robust cream. - - - ); - }; - - render()`; - -export const TextItalicFont = () => { - const scope = {Text}; - - return ( - - ); -}; - -const exampleTruncateCode = `const Component = () => { - - return ( - <> - - Single origin, extra id beans, eu to go, skinny americano ut - aftertas te sugar. At americano, viennese variety iced grounds, - grinder froth and pumpkin spice aromatic. Cultivar aged lungo, - grounds café au lait, skinny, blue mountain, in variety sugar - shop roast. Wings, blue mountain affogato organic cappuccino - java plunger pot. Single shot variety pumpkin spice seasonal - skinny barista carajillo robust cream. - - - ); - }; - - render()`; - -export const TextTruncateFont = () => { - const scope = {Text}; - - return ( - - ); -}; - -const exampleColorCode = `const Component = () => { - - return ( - <> - - primary - - - secondary - - - muted - - - success - - - warning - - - danger - - - info - - - ); - }; - - render()`; - -export const TextColorFont = () => { - const scope = {Text}; - - return ( - - ); -}; - -const exampleMonospaceCode = `const Component = () => { - - return ( - <> - - Single origin, extra id beans, eu to go, skinny americano ut - aftertas te sugar. At americano, viennese variety iced grounds, - grinder froth and pumpkin spice aromatic. Cultivar aged lungo, - grounds café au lait, skinny, blue mountain, in variety sugar - shop roast. Wings, blue mountain affogato organic cappuccino - java plunger pot. Single shot variety pumpkin spice seasonal - skinny barista carajillo robust cream. - - - ); - }; - - render()`; - -export const TextMonospaceFont = () => { - const scope = {Text}; - - return ( - - ); -}; - -const exampleWeightCode = `const Component = () => { - - return ( - <> - - Text with ligther weight - - - Text with light weight - - - Text with normal weight - - - Text with semi-bold weight - - - Text with bold weight - - - Text with bolder weight - - - ); - }; - - render()`; - -export const TextWeight = () => { - const scope = {Text}; - - return ( - - ); -}; - -const exampleTextHighlightImports = `import {TextHighlight} from '@clayui/core'; -import React from 'react';`; - -const exampleTextHighlightCode = `const Component = () => { - return ( - Rick Sanchez - ); - }; - - render()`; - -export const ExampleTextHighlight = () => { - const scope = {TextHighlight}; - - return ( - - ); -}; diff --git a/packages/clay-core/docs/text.mdx b/packages/clay-core/docs/text.mdx index f8f4d02b2e..aa814116fb 100644 --- a/packages/clay-core/docs/text.mdx +++ b/packages/clay-core/docs/text.mdx @@ -3,36 +3,10 @@ title: 'Text' description: 'Text represent a single text line without semantic meaning.' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {Text} from '@clayui/core';" storybookPath: 'design-system-components-typography--text-typography' --- -import { - ExampleTextHighlight, - TextColorFont, - TextItalicFont, - TextMonospaceFont, - TextSize, - TextTruncateFont, - TextWeight, -} from '$packages/clay-core/docs/text'; - - - ## Introduction Text is a component that represents a single text line without semantic meaning like a [Button](/docs/components/button.html). Text can also provide its styles using its props like [`italic`](#italic), [`truncate`](#truncate), [`monospace`](#monospace), [`color`](#color), [`weight`](#font-weights) and [`size`](#size). @@ -41,19 +15,62 @@ Text is a component that represents a single text line without semantic meaning The same way as [Heading](/docs/components/heading.html), Text provides its own font size level from 1 to 11 just indicating it in the property `size`. The default font size is 4. - +```jsx preview +import {Text} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( +
+
+ Text Size Level 11 +
+
+ Text Size Level 10 +
+
+ Text Size Level 9 +
+
+ Text Size Level 8 +
+
+ Text Size Level 7 +
+
+ Text Size Level 6 +
+
+ Text Size Level 5 +
+
+ Text Size Level 4 +
+
+ Text Size Level 3 +
+
+ Text Size Level 2 +
+
+ Text Size Level 1 +
+
+ ); +} +``` ## As API The HTML tag of this component can be chosen to ensure that the semantics of the text are representative. Text provides a property that allows to display the component depending on the user election. It can be displayed as `p` or `span` tag providing a block element or a inline one. ```jsx - - Text using paragraph - - - Text using span - +Text using paragraph +``` + +```jsx +Text using span ``` ## Font Styles @@ -62,34 +79,167 @@ The HTML tag of this component can be chosen to ensure that the semantics of the Likewise, Text provides a new property that allows you change the font weight of text in `italic` form. - +```jsx preview +import {Text} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( +
+ + Single origin, extra id beans, eu to go, skinny americano ut + aftertas te sugar. At americano, viennese variety iced grounds, + grinder froth and pumpkin spice aromatic. Cultivar aged lungo, + grounds café au lait, skinny, blue mountain, in variety sugar + shop roast. Wings, blue mountain affogato organic cappuccino + java plunger pot. Single shot variety pumpkin spice seasonal + skinny barista carajillo robust cream. + +
+ ); +} +``` ### Truncate If you want to shortening Text content because it doesn't fit the layout correctly, you can use `truncate` property. - +```jsx preview +import {Text} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( +
+ + Single origin, extra id beans, eu to go, skinny americano ut + aftertas te sugar. At americano, viennese variety iced grounds, + grinder froth and pumpkin spice aromatic. Cultivar aged lungo, + grounds café au lait, skinny, blue mountain, in variety sugar + shop roast. Wings, blue mountain affogato organic cappuccino + java plunger pot. Single shot variety pumpkin spice seasonal + skinny barista carajillo robust cream. + +
+ ); +} +``` ### Monospace Text provides a property which sets a font whose letters and characters each occupy the same amount of horizontal space, which is `monospace`. - +```jsx preview +import {Text} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( +
+ + Single origin, extra id beans, eu to go, skinny americano ut + aftertas te sugar. At americano, viennese variety iced grounds, + grinder froth and pumpkin spice aromatic. Cultivar aged lungo, + grounds café au lait, skinny, blue mountain, in variety sugar + shop roast. Wings, blue mountain affogato organic cappuccino + java plunger pot. Single shot variety pumpkin spice seasonal + skinny barista carajillo robust cream. + +
+ ); +} +``` ## Color Text has the ability to apply different `color` fonts giving emphasis to the text, you can check [here](/docs/css/content/typography.html#css-contextual-texts). Notice that is not recommended on light backgrounds due to contrast issues around light text. - +```jsx preview +import {Text} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( +
+ + primary + + + secondary + + + muted + + + success + + + warning + + + danger + + + info + +
+ ); +} +``` ## Font Weights As well as [Heading](/docs/components/heading.html), Text provides its own font weight styles from `bolder` to `lighter` just indicating it in the property `weight`. The default font weight is `normal`. - +```jsx preview +import {Text} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( +
+ + Text with ligther weight + + + Text with light weight + + + Text with normal weight + + + Text with semi-bold weight + + + Text with bold weight + + + Text with bolder weight + +
+ ); +} +``` ## Text Highlight The `` component adds a highlight to the text characters that match the value that can be entered by the user, for example can be used in an Autocomplete component. - +```jsx preview +import {Text} from '@clayui/core'; + +import '@clayui/css/lib/css/atlas.css'; + +export default function App() { + return ( +
+ Rick Sanchez +
+ ); +} +``` diff --git a/packages/clay-core/docs/treeview.mdx b/packages/clay-core/docs/tree-view.mdx similarity index 85% rename from packages/clay-core/docs/treeview.mdx rename to packages/clay-core/docs/tree-view.mdx index 12495604e6..f0fa48b5fd 100644 --- a/packages/clay-core/docs/treeview.mdx +++ b/packages/clay-core/docs/tree-view.mdx @@ -3,50 +3,139 @@ title: 'TreeView' description: 'A tree view is a component based on nodes that are shown in a hierarchical structure.' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {TreeView} from '@clayui/core';" lexiconDefinition: 'https://liferay.design/lexicon/core-components/tree-view/' storybookPath: 'design-system-components-treeview' --- -import {Example, MultipleSelection} from '$packages/clay-core/docs/treeview'; - - +```jsx preview +import {Provider, TreeView} from '@clayui/core'; +import Icon from '@clayui/icon'; -## Example +import '@clayui/css/lib/css/atlas.css'; + +const spritemap = '/public/icons.svg'; + +export default function FileExplorer() { + const items = [ + { + children: [ + { + children: [ + { + children: [{name: 'Research 1'}], + name: 'Research', + }, + { + children: [{name: 'News 1'}], + name: 'News', + }, + ], + name: 'Blogs', + }, + { + children: [ + { + children: [ + { + name: 'Instructions.pdf', + status: 'success', + type: 'pdf', + }, + ], + name: 'PDF', + }, + { + children: [ + { + name: 'Treeview review.docx', + status: 'success', + type: 'document', + }, + { + name: 'Heuristics Evaluation.docx', + status: 'success', + type: 'document', + }, + ], + name: 'Word', + }, + ], + name: 'Documents and Media', + }, + ], + name: 'Liferay Drive', + type: 'cloud', + }, + { + children: [{name: 'Blogs'}, {name: 'Documents and Media'}], + name: 'Repositories', + type: 'repository', + }, + { + children: [{name: 'PDF'}, {name: 'Word'}], + name: 'Documents and Media', + status: 'warning', + }, + ]; + + const TYPES_TO_SYMBOLS = { + document: 'document-text', + pdf: 'document-pdf', + success: 'check-circle-full', + warning: 'warning-full', + }; - + const TYPES_TO_COLORS = { + document: 'text-primary', + pdf: 'text-danger', + success: 'text-success', + warning: 'text-warning', + }; + + return ( + + + {(item) => ( + + + + {item.name} + {item.status && ( + + )} + + + {({name, status, type}) => ( + + {type && ( + + )} + {name} + {status && ( + + )} + + )} + + + )} + + + ); +} +``` ## Introduction @@ -174,8 +263,8 @@ The TreeView doesn't know when an item is asynchronous, so the developer must sp When adding a new asynchronous item to the tree, the `onItemsChange` method is respectively called to update the tree with a new value if the `items` prop is controlled. -
- Warning +
+ Warning If you have an error in the asynchronous call of the onLoadMore method, only the suppression is done and an error is thrown on the console. @@ -187,7 +276,7 @@ When adding a new asynchronous item to the tree, the `onItemsChange` method is r return await fetch(`example.com/tree/item?parent_id=${item.id}`); }} > - {...} + ... ``` @@ -198,7 +287,9 @@ The `onLoadMore` API can also be used to load paginated data for a specific item ```jsx { - const result = await fetch(cursor ?? `example.com/tree/item?parent_id=${item.id}`); + const result = await fetch( + cursor ?? `example.com/tree/item?parent_id=${item.id}` + ); return { cursor: result.next, @@ -206,21 +297,19 @@ The `onLoadMore` API can also be used to load paginated data for a specific item }; }} > - {...} + ... ``` The `cursor` helps to store the data that will be used to identify which will be the next request, this can be an `offset`, `cursor`, `id` the URL or any other data that represents the item cursor, when there is no more data just sets the cursor to `null`. The TreeView also exposes a public API that can invoke `loadMore` and find out if there is a cursor for a specific item. ```jsx - + {(item, selection, expand, load) => ( {item.name} - {(item) => ( - {item.name} - )} + {(item) => {item.name}} {expand.has(item.id) && load.has(item.id) !== null && ( @@ -323,7 +412,7 @@ Actions are added using the `actions` property on each item. The component abstr ``` -#### Disabled(#item-disabled) +#### Disabled An item can be disabled by setting the `disabled` prop in the `` and `` components. By default, the `Expander` and `Checkbox` are also disabled, and any other clickable elements other than these need to be set to disabled in the composition. @@ -352,16 +441,14 @@ The TreeView exposes the `expandedKeys` property and the `onExpandedChange` call ```jsx function Example() { - const [expandedKeys, setExpandedKeys] = useState( - new Set(['1', '2', '3']) - ); + const [expandedKeys, setExpandedKeys] = useState(new Set(['1', '2', '3'])); return ( - {...} + ... ); } @@ -378,11 +465,11 @@ Customizing the expander is possible using the `expanderIcons` property. Changin open: , }} > - {...} + ... ``` -### Disabled(#expander-disabled) +### Disabled The `Expander` is automatically disabled when the item is disabled but you can optionally control its state. @@ -470,8 +557,8 @@ return ( Rendering the TreeView with pre-selected items will cause their parent items to be expanded so that the selected item is visible on the first render. In recursive multiple selection, the parents items will marked as intermediate. -
- Info +
+ Info Expanding selected items in the first render implies performance degradation if the TreeView has too many items; but there are some possibilities to work around depending on the use case, read the @@ -484,8 +571,6 @@ Rendering the TreeView with pre-selected items will cause their parent items to The single selection state works independently of adding the `` and this state is set by default. - - ### Multiple Selection The multi-selection in TreeView is a achieved by composing with the `` component that must be added explicitly in the item rendering. @@ -495,15 +580,15 @@ The multi-selection in TreeView is a achieved by composing with the ` Drive +``` +```jsx Drive - - {...} - + ... ``` @@ -523,7 +608,7 @@ function Example() { selectedKeys={selectedKeys} selectionMode="multiple" > - {...} + ... ); } @@ -535,13 +620,11 @@ By default, when selecting an item with nested items, its children are recursive There are some limitations: for static content the recursive selection only works if the item is expanded, (i.e visible). For dynamic content, it works independently. -
- Warning +
+ Warning Recursive selection will not select items from an asynchronous Item.
- - ### Manual Selection Manual selection is the possibility to trigger the selection without using the `` or visually changing the state of the selection types, such as the single selection state. @@ -592,12 +675,8 @@ function Example() { const [items, setItems] = useState([]); return ( - - {...} + + ... ); } @@ -634,7 +713,7 @@ In some cases it is necessary to check if the item can be dropped in another ite return false; }} > - {...} + ... ``` @@ -642,8 +721,8 @@ In some cases it is necessary to check if the item can be dropped in another ite The TreeView implements shortcuts and manages the focus. Some shortcuts and focus trigger some actions like renaming, removing or asynchronous loading if any. -
- Warning +
+ Warning If an Item is asynchronous the onLoadMore method will be called as described in the Asynchronous Item section. @@ -662,7 +741,7 @@ The `onRenameItem` property receives the `item` object corresponding to the curr return await openRenameModal(item); }} > - {...} + ... ``` @@ -687,8 +766,8 @@ This can lead to a performance problem on the first render if you have too many - `render-first` will render first and then hydrate. It doesn't block the initial rendering but it is possible to see the items being expanded. - `hydrate-first` will hydrate first and then render. This blocks rendering first until it traverses the tree, when rendered the items are already expanded. -
- Info +
+ Info The tree traversal implementation internally has some performance optimizations. Depending on the number of selected items, the TreeView stops traversing the tree when it finds all the selected items. In most scenarios, the TreeView will diff --git a/packages/clay-core/docs/treeview.js b/packages/clay-core/docs/treeview.js deleted file mode 100644 index 1331e09946..0000000000 --- a/packages/clay-core/docs/treeview.js +++ /dev/null @@ -1,196 +0,0 @@ -/** - * SPDX-FileCopyrightText: © 2021 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Editor from '$clayui.com/src/components/Editor'; -import {Provider, TreeView} from '@clayui/core'; -import {ClayCheckbox as Checkbox} from '@clayui/form'; -import Icon from '@clayui/icon'; -import React from 'react'; - -const exampleImports = `import {Provider, TreeView} from '@clayui/core'; -import Icon from '@clayui/icon';`; - -const exampleCode = `const FileExplorer = ({selectionMode}) => { - const items = [ - { - children: [ - { - children: [ - { - children: [{name: 'Research 1'}], - name: 'Research', - }, - { - children: [{name: 'News 1'}], - name: 'News', - }, - ], - name: 'Blogs', - }, - { - children: [ - { - children: [ - { - name: 'Instructions.pdf', - status: 'success', - type: 'pdf', - }, - ], - name: 'PDF', - }, - { - children: [ - { - name: 'Treeview review.docx', - status: 'success', - type: 'document', - }, - { - name: 'Heuristics Evaluation.docx', - status: 'success', - type: 'document', - }, - ], - name: 'Word', - }, - ], - name: 'Documents and Media', - }, - ], - name: 'Liferay Drive', - type: 'cloud', - }, - { - children: [{name: 'Blogs'}, {name: 'Documents and Media'}], - name: 'Repositories', - type: 'repository', - }, - { - children: [{name: 'PDF'}, {name: 'Word'}], - name: 'Documents and Media', - status: 'warning', - }, - ]; - - const TYPES_TO_SYMBOLS = { - document: 'document-text', - pdf: 'document-pdf', - success: 'check-circle-full', - warning: 'warning-full', - }; - - const TYPES_TO_COLORS = { - document: 'text-primary', - pdf: 'text-danger', - success: 'text-success', - warning: 'text-warning', - }; - - return ( - - - {(item) => ( - - - - {item.name} - {item.status && ( - - )} - - - {({name, status, type}) => ( - - {type && ( - - )} - {name} - {status && ( - - )} - - )} - - - )} - - - ); -}; - -render()`; - -const Example = () => { - const scope = {Icon, Provider, TreeView}; - - return ; -}; - -const multipleSelectionImports = `import {Provider, TreeView} from '@clayui/core'; -import {ClayCheckbox as Checkbox} from '@clayui/form';`; - -const multipleSelectionCode = `const MultipleSelection = () => ( - - - - - - Root - - - - - Item - - - - Item 2 - - - - Item 3 - - - - - -); - -render()`; - -const MultipleSelection = () => { - const scope = {Checkbox, Provider, TreeView}; - - return ( - - ); -}; - -export {Example, MultipleSelection}; diff --git a/packages/clay-core/docs/vertical-bar.js b/packages/clay-core/docs/vertical-bar.js deleted file mode 100644 index 321332463c..0000000000 --- a/packages/clay-core/docs/vertical-bar.js +++ /dev/null @@ -1,147 +0,0 @@ -/** - * SPDX-FileCopyrightText: © 2022 Liferay, Inc. - * SPDX-License-Identifier: BSD-3-Clause - */ - -import Editor from '$clayui.com/src/components/Editor'; -import {Button, Provider, TreeView, VerticalBar} from '@clayui/core'; -import Icon from '@clayui/icon'; -import React from 'react'; - -const exampleImports = `import {Provider, TreeView} from '@clayui/core'; -import Icon from '@clayui/icon';`; - -const exampleCode = `const VerticalBarExample = () => { - const items = [ - { - icon: 'tag', - title: 'Tag', - }, - { - divider: true, - icon: 'message', - title: 'Message', - }, - { - icon: 'effects', - title: 'Effects', - }, - ]; - - return ( -
- - - - {(item) => ( - -
-
{item.title}
-
-
- )} -
- - - {(item) => ( - - - - )} - -
-
-
- ); -}; - -render()`; - -const VerticalBarExample = () => { - const scope = {Button, Icon, Provider, TreeView, VerticalBar}; - - return ; -}; - -const resizeImports = `import {Provider, TreeView} from '@clayui/core'; -import Icon from '@clayui/icon'; -import React, {useState} from 'react';`; - -const resizeCode = `const VerticalBarResize = () => { - const items = [ - { - icon: 'tag', - title: 'Tag', - }, - { - divider: true, - icon: 'message', - title: 'Message', - }, - { - icon: 'effects', - title: 'Effects', - }, - ]; - - const [width, setWidth] = useState(320); - - return ( -
- And aged, cinnamon, redeye dripper, organic and mocha cinnamon qui macchiato. Whipped, cream single origin, coffee eu a brewed macchiato. Instant, whipped barista so ut siphon viennese medium aftertaste steamed. - - Cappuccino plunger pot macchiato coffee froth caramelization froth, so id rich cream pumpkin spice. Milk rich, a that cultivar shop saucer a caffeine. French press acerbic qui that cortado plunger pot beans bar cappuccino. - - { - setWidth(width); - - document.getElementById('verticalBarResizeContainer1').style.paddingLeft = width + 52 + 'px'; - }} - panelWidth={width} - panelWidthMax={700} - panelWidthMin={150} - position="left" - resize - > - - {(item) => ( - - - - )} - - - - {(item) => ( - -
-
{item.title}
-
-
- )} -
-
-
-
- ); -}; - -render()`; - -const VerticalBarResize = () => { - const scope = {Button, Icon, Provider, TreeView, VerticalBar}; - - return ; -}; - -export {VerticalBarExample, VerticalBarResize}; diff --git a/packages/clay-core/docs/vertical-bar.mdx b/packages/clay-core/docs/vertical-bar.mdx index d09f02ce3d..10579b0375 100644 --- a/packages/clay-core/docs/vertical-bar.mdx +++ b/packages/clay-core/docs/vertical-bar.mdx @@ -3,32 +3,74 @@ title: 'VerticalBar' description: 'A vertical bar is a flexible container that organizes items vertically.' packageNpm: '@clayui/core' packageStatus: 'Beta' +packageUse: "import {VerticalBar} from '@clayui/core';" storybookPath: 'design-system-components-verticalbar' --- -import { - VerticalBarExample, - VerticalBarResize, -} from '$packages/clay-core/docs/vertical-bar'; +## Example - +const spritemap = '/public/icons.svg'; -## Example +export default function App() { + const items = [ + { + icon: 'tag', + title: 'Tag', + }, + { + divider: true, + icon: 'message', + title: 'Message', + }, + { + icon: 'effects', + title: 'Effects', + }, + ]; - + return ( +
+ + + + {(item) => ( + +
+
+ {item.title} +
+
+
+ )} +
+ + + {(item) => ( + + + + )} + +
+
+
+ ); +} +``` ## Introduction @@ -36,7 +78,7 @@ VerticalBar allows rendering a vertical navigation bar positioned fixedly on the Just like the TreeView component, the VerticalBar is considered a middle-level component instead of a low-level or high-level, it guarantees more flexibility and composition and delivers features that would only be available at high-level with the same synthetic form of an API low-level. -## Content(#vertical-bar-content) +## Content As VerticalBar is middle-level, it allows you to build static or dynamic content if you need to consume data from some service. @@ -180,13 +222,13 @@ Positioning the VerticalBar on the right or left side is possible by setting the ``` -## Resize(#vertical-bar-resize) +## Resize The property `resize` in `` enables the user to increase or decrease the panel width using the mouse or keyboard. The maximum width can be set using the property `panelWidthMax`. It defaults to 500px. The minimum width is set using the property `panelWidthMin` and defaults to 280px. The starting width is set using `panelWidth` with a default value of 320px. The property `onPanelWidthChange` accepts a callback function that executes when the `panelWidth` is updated. The callback function has the value of the panel width as the parameter. It can be used to make updates to other parts of your application, such as pushing body content over as the user resizes the Vertical Bar Panel. -
+
When using the property `onPanelWidthChange`, you must also declare `panelWidth`. Setting a fixed value for `panelWidth` will result in `onPanelWidthChange` always returning that value, you must use @@ -194,9 +236,7 @@ The property `onPanelWidthChange` accepts a callback function that executes when Please see the code example below.
-
- -
+
## Load lazy panel diff --git a/packages/clay-core/src/index.ts b/packages/clay-core/src/index.ts index e2aaf36752..b4e7359bb0 100644 --- a/packages/clay-core/src/index.ts +++ b/packages/clay-core/src/index.ts @@ -3,16 +3,6 @@ * SPDX-License-Identifier: BSD-3-Clause */ -export { - default as Button, - ClayButtonWithIcon as ButtonWithIcon, -} from '@clayui/button'; -export {default as Icon} from '@clayui/icon'; -export { - default as Modal, - Context as ModalContext, - useModal, -} from '@clayui/modal'; export {Provider, useProvider} from '@clayui/provider'; export {Heading, Text, TextHighlight} from './typography'; diff --git a/packages/clay-core/src/tree-view/TreeView.tsx b/packages/clay-core/src/tree-view/TreeView.tsx index 817cc0d564..19b11f5e97 100644 --- a/packages/clay-core/src/tree-view/TreeView.tsx +++ b/packages/clay-core/src/tree-view/TreeView.tsx @@ -124,14 +124,6 @@ const Application = ({children}: {children: React.ReactNode}) => (
{children}
); -export function TreeView>( - props: ITreeViewProps -): JSX.Element & { - Item: typeof TreeViewItem; - Group: typeof TreeViewGroup; - ItemStack: typeof TreeViewItemStack; -}; - export function TreeView>({ children, className, diff --git a/www/app/_components/Heading.tsx b/www/app/_components/Heading.tsx index b24fa169ea..a0aa2805b2 100644 --- a/www/app/_components/Heading.tsx +++ b/www/app/_components/Heading.tsx @@ -10,7 +10,7 @@ type Props = { description?: string; title: string; npmPackage?: string; - use?: string; + use?: React.ReactNode; }; export default function Heading({description, title, npmPackage, use}: Props) { diff --git a/www/app/_components/Sandpack.server.tsx b/www/app/_components/Sandpack.server.tsx new file mode 100644 index 0000000000..74f589c1dd --- /dev/null +++ b/www/app/_components/Sandpack.server.tsx @@ -0,0 +1,64 @@ +import {promises as fs} from 'fs'; +import { + SandpackProvider, + SandpackLayout, + SandpackCodeEditor, + SandpackPreview, + theme, +} from './Sandpack'; +import classNames from 'classnames'; +import styles from './sandpack.module.css'; + +type Props = { + language: string; + children: any; +}; + +export async function Sandpack({language, children}: Props) { + const file = await fs.readFile( + process.cwd() + '/node_modules/@clayui/css/lib/images/icons/icons.svg', + 'utf-8' + ); + + return ( + +
+ +
+ + + +
+ ); +} diff --git a/www/app/_components/Sidebar.tsx b/www/app/_components/Sidebar.tsx index 6ca354b539..ea4fc56293 100644 --- a/www/app/_components/Sidebar.tsx +++ b/www/app/_components/Sidebar.tsx @@ -1,4 +1,6 @@ import Link from 'next/link'; +import type {SourceTreeItem} from 'mdxts'; + import ClayLink from '../_components/Link'; import styles from './sidebar.module.css'; @@ -8,10 +10,11 @@ type Item = { }; type Props = { - items: Array; + items?: Array; + tree?: Array; }; -export function Sidebar({items}: Props) { +export function Sidebar({items, tree}: Props) { return ( ); } + +type TreeProps = { + children: Array; + depth: number; +}; + +function Tree({children, depth}: TreeProps) { + return children.map((item) => ( +
    +

    {item.label}

    + {!!item.children.length && ( + + )} +
+ )); +} + +function Item({children, depth}: TreeProps) { + return ( +
    + {children.map((item) => ( +
  • + + {item.label} + + {!!item.children.length && ( + + )} +
  • + ))} +
+ ); +} diff --git a/www/app/_components/sandpack.module.css b/www/app/_components/sandpack.module.css new file mode 100644 index 0000000000..77b91605ce --- /dev/null +++ b/www/app/_components/sandpack.module.css @@ -0,0 +1,9 @@ +.code_preview { + border: 1px solid #F3F3F3; + border-radius: 4px; + height: 300px; +} + +.code_preview > div { + height: 300px; +} \ No newline at end of file diff --git a/www/app/_components/sidebar.module.css b/www/app/_components/sidebar.module.css index d891b10fea..ef93300716 100644 --- a/www/app/_components/sidebar.module.css +++ b/www/app/_components/sidebar.module.css @@ -6,6 +6,7 @@ padding: 19px 32px; border-right: 1px solid #F5F5F8; height: 100vh; + overflow-y: auto; } .logo { diff --git a/www/app/_examples/autocomplete.tsx b/www/app/_examples/autocomplete.tsx deleted file mode 100644 index ab91a1a03b..0000000000 --- a/www/app/_examples/autocomplete.tsx +++ /dev/null @@ -1,52 +0,0 @@ -'use client'; - -import Autocomplete from '@clayui/autocomplete'; -import Form from '@clayui/form'; - -export const Example = () => ( - - - - {(item) => {item}} - - -); - -export const MenuTrigger = () => ( - - - - {(item) => {item}} - - -); diff --git a/www/app/docs/(layout)/[...slug]/page.module.css b/www/app/docs/(layout)/[...slug]/page.module.css new file mode 100644 index 0000000000..542530a610 --- /dev/null +++ b/www/app/docs/(layout)/[...slug]/page.module.css @@ -0,0 +1,47 @@ +.toc { + position: sticky; + top: 40px; + height: 100vh; +} + +.toc_list { + list-style-type: none; + margin-left: 2px; + height: 100%; + overflow-y: auto; + padding-bottom: 40px; +} + +.toc_list li { + margin-top: 5px; + margin-bottom: 5px; +} + +.content { + --color-separator: #F5F5F8; + --color-foreground-secondary: #B3482E; + + position: relative; + display: grid; + grid-template-columns: 1fr 200px; + gap: 120px; + padding-bottom: 100px; +} + +.author_container { + border-top: 1px solid #F5F5F8; + padding-top: 50px; + margin-top: 50px; +} + +.author_list { + display: flex; + gap: 5px; +} + +.author { + width: 30px; + height: 30px; + border-radius: 100%; + background-color: #C4C4C4; +} \ No newline at end of file diff --git a/www/app/docs/(layout)/[...slug]/page.tsx b/www/app/docs/(layout)/[...slug]/page.tsx new file mode 100644 index 0000000000..c6fb227a55 --- /dev/null +++ b/www/app/docs/(layout)/[...slug]/page.tsx @@ -0,0 +1,457 @@ +import type {Metadata} from 'next'; +import {notFound} from 'next/navigation'; +import Heading from '@/app/_components/Heading'; +import {Fragment} from 'react'; +import {data} from '@/data'; +import {CodeInline, MDXContent, MDXComponents} from 'mdxts/components'; + +const mdxComponents = { + p: (props) =>

, + code: (props) => , +} as MDXComponents; + +import styles from './page.module.css'; + +type Props = { + params: { + slug: Array; + }; +}; + +export async function generateMetadata({params}: Props): Promise { + const document = await data.get(params.slug); + + const title = `${document?.frontMatter?.title} - Clay by Liferay`; + + return { + title: title, + openGraph: { + title: title, + description: document?.frontMatter?.description, + }, + }; +} + +export default async function Page({params}: Props) { + const document = await data.get(params.slug); + const component = await data.get(['packages', ...params.slug.slice(1)]); + + if (!document) { + notFound(); + } + + console.log(data.paths()) + + const Content = document.Content!; + + return ( +

+
+ + } + /> + + + {component && component.exportedTypes.length > 0 && ( + + )} + +
+ + Edit this page on GitHub + +

Contributors

+
+ {document.authors.map((item) => ( +
+ ))} +
+ + {document.updatedAt && ( +

+ Last edited{' '} + {new Intl.DateTimeFormat('en-US', { + dateStyle: 'long', + timeStyle: 'medium', + }).format(new Date(document.updatedAt!))} +

+ )} +
+
+ +
+
+ ); +} + +function Props({ + props, + isComponent, +}: { + props: any[] | null; + isComponent: boolean; +}) { + return props?.map((propType, index) => { + if (propType === null) { + return null; + } + + if ( + isComponent && + propType.unionProperties && + propType.unionProperties.length > 0 + ) { + return ( +
+

+ {propType.text} +

+ {propType.description && ( + + )} +
+ + Union + + {propType.unionProperties.map( + (props: any, index: number) => ( + + {index > 0 ? ( +
+
+
+ + or + +
+
+
+ ) : null} + + + ) + )} +
+ +
+ ); + } + + if (propType.name === null) { + return propType.properties ? ( +
+ +
+ ) : ( +
+ {isComponent ? 'Props' : 'Types'}{' '} + +
+ ); + } + + return ( +
+
+

+ {propType.name}{' '} + {propType.required && ( + + * + + )} +

+
+ + {propType.defaultValue ? ( + + ={' '} + + + ) : null} +
+
+ {propType.description && ( + + )} + + {propType.properties && propType.properties.length > 0 ? ( +
+ +
+ ) : null} +
+ ); + }); +} diff --git a/www/app/docs/(layout)/components/autocomplete/page.mdx b/www/app/docs/(layout)/components/autocomplete/page.mdx deleted file mode 100644 index 7c50641461..0000000000 --- a/www/app/docs/(layout)/components/autocomplete/page.mdx +++ /dev/null @@ -1,298 +0,0 @@ -import Heading from '@/app/_components/Heading'; -import {Example, MenuTrigger} from '@/app/_examples/autocomplete'; - -export const metadata = { - title: 'Autocomplete', - description: - 'An autocomplete text field is an input that offers the user text suggestions while they type.', -}; - - - -## Example - - - -## Introduction - -Autocomplete provides as a mid-level API as it was done for TreeView and follows the same standards that exist in Clay components. A new implementation of Autocomplete provides new OOTB functionality and lessens the verbose composition of the old implementation but still provides backward compatibility but will be deprecated in the next major release, so if you are using this component for the first time, consider using the new implementation. - -## Content - -Autocomplete follows the Collection pattern, the same as TreeView and VerticalBar, it accepts static and dynamic contents. Similar to TreeView, the content accepts the `Item` component but the Item that belongs to Autocomplete, ``. - -### Static - -```jsx - - Apples - Bananas - Cantaloupe - Mangos - Oranges - Strawberries - -``` - -### Dynamic - -Dynamic content works when the data comes from a service, there are two possible scenarios: - -- All data exists on the client and the filter is done on the client -- The filter is done on the server - -```jsx - - {(item) => {item}} - -``` - -The most common scenario for a large list of data is the filter is done on the server and it is necessary to make a request to the server as soon as the input value changes and update the list respectively. You need to make Autocomplete a controlled component that allows you to state control. - -```jsx -function Example() { - const [value, setValue] = useState(''); - - const [networkStatus, setNetworkStatus] = useState(4); - const {resource} = useResource({ - fetchPolicy: 'cache-first', - link: 'https://api.clay.example/devs/', - onNetworkStatusChange: setNetworkStatus, - variables: {name: value}, - }); - - return ( - {}} - placeholder="Enter the name of a fruit" - value={value} - > - {(item) => ( - - {item.name} - - )} - - ); -} -``` - -### Internationalization - -To internationalize data in Autocomplete, you must pass the data to each child of the `Item`. Autocomplete also handles "Not found" and "Loading" messages for the respective scenarios, it is necessary to define the internationalized messages by defining the `messages` prop. - -## Value - -The value of Autocomplete by default is an empty value, but it can start with a value using the `defaultValue` prop. Also, a value can be controlled by providing the `value` and `onChange` properties to switch to the controlled state. - -```jsx -function Example() { - const [value, setValue] = useState('Apples'); - - return ( - <> - - {(item) => ( - {item} - )} - - - - {(item) => ( - {item} - )} - - - ); -} -``` - -## Asynchronous loading - -Autocomplete supports loading data asynchronously, and displays the loading indicator reflecting the current loading state, by setting the `loadingState` prop. - -```jsx -function Example() { - const [value, setValue] = useState(''); - - const [networkStatus, setNetworkStatus] = useState(4); - const {resource} = useResource({ - fetchPolicy: 'cache-first', - link: 'https://api.clay.example/devs/', - onNetworkStatusChange: setNetworkStatus, - variables: {name: value}, - }); - - return ( - {}} - placeholder="Enter a name" - value={value} - > - {(item) => ( - - {item.name} - - )} - - ); -} -``` - -Autocomplete also supports infinite scrolling to load more data on demand as the user scrolls. This is works with the `useResource` hook. - -```jsx -function Example() { - const [value, setValue] = useState(''); - - const [networkStatus, setNetworkStatus] = useState(4); - const {loadMore, resource} = useResource({ - fetch: async (link, options) => { - const result = await fetch(link, options); - const json = await result.json(); - - return { - cursor: json.next, - items: json.results, - }; - }, - fetchPolicy: 'cache-first', - link: 'https://api.clay.example/devs/', - onNetworkStatusChange: setNetworkStatus, - variables: {name: value}, - }); - - return ( - {}} - onLoadMore={loadMore} - placeholder="Enter a name" - value={value} - > - {(item) => ( - - {item.name} - - )} - - ); -} -``` - -## Custom Filtering - -By default, Autocomplete uses the `contains` string filtering strategy to decide which items should be visible in the menu. This filtering strategy can be replaced by your own filtering rule by passing the data through the `items` prop. - -```jsx -function Example() { - const options = [ - 'Apples', - 'Bananas', - 'Cantaloupe', - 'Mangos', - 'Oranges', - 'Strawberries', - ]; - - const [value, setValue] = useState(''); - - const filteredItems = useMemo( - () => - options.filter( - (item) => value.match(new RegExp(value, 'i')) !== null - ), - [value] - ); - - return ( - {}} - placeholder="Enter the name of a fruit" - value={value} - > - {(item) => {item}} - - ); -} -``` - -## Trigger options - -By default, Autocomplete show the menu when the user types in the input field. Alternatively this mode can be modified by setting the `menuTrigger` property to `focus`, which shows the menu when Autocomplete is focused. - - diff --git a/www/app/docs/(layout)/components/page.mdx b/www/app/docs/(layout)/components/page.mdx deleted file mode 100644 index 05eadb893a..0000000000 --- a/www/app/docs/(layout)/components/page.mdx +++ /dev/null @@ -1,7 +0,0 @@ -import Heading from '@/app/_components/Heading'; - -export const metadata = { - title: 'Components', -}; - - diff --git a/www/app/docs/(layout)/layout.tsx b/www/app/docs/(layout)/layout.tsx index 3b5f1ede05..b3bbb52dbd 100644 --- a/www/app/docs/(layout)/layout.tsx +++ b/www/app/docs/(layout)/layout.tsx @@ -1,3 +1,5 @@ +import {sidebar} from '@/data'; + import {Sidebar} from '../../_components/Sidebar'; import {Navbar} from '../../_components/Navbar'; import styles from './layout.module.css'; @@ -5,34 +7,7 @@ import styles from './layout.module.css'; export default function DocsLayout({children}: {children: React.ReactNode}) { return ( <> - +
{children}
diff --git a/www/app/docs/(layout)/provider/page.mdx b/www/app/docs/(layout)/provider/page.mdx deleted file mode 100644 index 6e37d200d1..0000000000 --- a/www/app/docs/(layout)/provider/page.mdx +++ /dev/null @@ -1,46 +0,0 @@ -import Heading from '@/app/_components/Heading'; - -export const metadata = { - title: 'Provider', - description: - 'Provider component which aggregates the main Clay, Icon, and Modal.', -}; - - - -## Example - -```jsx -import {Provider} from '@clayui/core'; - - - - -; -``` - -## Application provider - -A Provider is a component that be at the root of your application. Provider is used by other Clay components to define `theme` scopes, render icons with `spritemap`, or help handle Modal creation in your application. - -### Theme - -Themes in Clay is different from patterns that are common in other libraries, Clay's CSS framework is built using Sass and we allow to create themes based on CSS scope, a class is added in Clay components that use `React.Portal` to render elements in the body for example. - -```jsx -Content -``` - -### Icon spritemap - -Icons need the path where to find the icon collection to be rendered. Clay components that use the `Icon` component pass props from `spritemap` to the icon, to avoid passing `spritemap` to all your components at different levels, add the spritemap path in `Provider` to that `Icon` can use and avoid passing the property on all components. - -```jsx - - - - -``` diff --git a/www/app/globals.scss b/www/app/globals.scss index 6faaa75872..6d9f15fa0a 100644 --- a/www/app/globals.scss +++ b/www/app/globals.scss @@ -25,8 +25,6 @@ html, body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - max-width: 100vw; - overflow-x: hidden; } body { diff --git a/www/app/page.tsx b/www/app/page.tsx index b3517a7783..70a6c11428 100644 --- a/www/app/page.tsx +++ b/www/app/page.tsx @@ -70,9 +70,9 @@ export default function Home() {

- Clay is an extensive Component Library, where you'll - find useful components—with extensive code examples—for - your web application. + Clay is an extensive Component Library, where + you'll find useful components—with extensive code + examples—for your web application.

**_Important Note: Be Mindful of the Asterisk:_** +> When using the `@clayui/*` command for installation, it's crucial to remember that the asterisk (\*) is a placeholder. It's not a valid package name on its own. To install a specific Clay package, you must replace the asterisk with the name of the package you require. +> +> For instance, if you want to install the "Clay Button" package, the correct command would be: +> +> ```shell +> npm install @clayui/button or yarn add @clayui/button +> ``` + +### Install via Clay CSS CDN + +We provide Clay CSS via CDN, which is an option when you do not want to install the clay package via NPM or Yarn. + +```html + +``` + +If you want a specific version of CSS, specify the desired version. + +Example: + +```diff +- https://cdn.jsdelivr.net/npm/@clayui/css/lib/css/atlas.css ++ https://cdn.jsdelivr.net/npm/@clayui/css@3.0.0/lib/css/atlas.css +``` + +### Quick start + +
+ Warning + Before you get started with this quick start, read about Clay's fundamentals + of composition to move on. The information below is assuming you have read about + Clay's compositional philosophy and learned about the terms. +
+ +
+ Warning + This quick start requires that you have a minimum knowledge of + React Hooks, not much of your API's will be used but just + useState to control the component. +
+ +
+ Warning + To ensure that Clay functions correctly, please remember to import the CSS package + from @clayui/css into your React entrypoint component, as demonstrated in the + example below. +
+ +For this quick start we will use [codesandbox](https://codesandbox.io/) which does not need to install an environment on your machine. + +Use the **codesandbox** below as your text editor and environment so we can follow through with the examples. + +