@workday/canvas-kit-mcp 14.3.16 → 14.3.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/action-bar.html +1 -1
- package/dist/apps/breadcrumbs.html +1 -1
- package/dist/apps/form-field.html +1 -1
- package/dist/apps/menu.html +1 -1
- package/dist/apps/modal.html +1 -1
- package/dist/apps/multiselect.html +1 -1
- package/dist/apps/select.html +1 -1
- package/dist/apps/tabs.html +1 -1
- package/dist/cli.js +67 -67
- package/dist/cli.js.map +2 -2
- package/dist/index.js +67 -67
- package/dist/index.js.map +2 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import { z } from "zod";
|
|
|
12
12
|
// package.json
|
|
13
13
|
var package_default = {
|
|
14
14
|
name: "@workday/canvas-kit-mcp",
|
|
15
|
-
version: "14.3.
|
|
15
|
+
version: "14.3.17",
|
|
16
16
|
description: "MCP package for Canvas Kit",
|
|
17
17
|
author: "Workday, Inc. (https://www.workday.com)",
|
|
18
18
|
license: "Apache-2.0",
|
|
@@ -109,6 +109,72 @@ var config_default = {
|
|
|
109
109
|
// lib/stories-config.json
|
|
110
110
|
var stories_config_default = {
|
|
111
111
|
stories: {
|
|
112
|
+
"status-indicator": {
|
|
113
|
+
title: "Preview/Status Indicator",
|
|
114
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-status-indicator--docs",
|
|
115
|
+
mdxPath: "modules/preview-react/status-indicator/stories/StatusIndicator.mdx",
|
|
116
|
+
mdxProse: "# Canvas Kit Status Indicator\n\nStatus Indicators help the user quickly identify the status of a task, action, or page element.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\n`StatusIndicator` includes a container `StatusIndicator` component and the following subcomponents\nwhich can be composed in a variety of ways: `StatusIndicator.Label` and `StatusIndicator.Icon`.\n\nA basic `StatusIndicator` with a `StatusIndicator.Label` will render text with a gray background and\nlow emphasis.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\n\nexport const Basic = () => {\n return (\n <StatusIndicator>\n <StatusIndicator.Label>Unpublished</StatusIndicator.Label>\n </StatusIndicator>\n );\n};\n```\n\n### Emphasis\n\nSet the `emphasis` prop of `StatusIndicator` to adjust the contrast between the text and background\ncolor. Emphasis is typically used to convey more visual urgency.\n\n`emphasis` accepts `high` or `low`.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst parentContainerStyles = createStyles({\n gap: system.space.x4,\n});\n\nexport const Emphasis = () => {\n return (\n <Flex cs={parentContainerStyles}>\n <StatusIndicator emphasis=\"high\">\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n <StatusIndicator.Label>High Emphasis</StatusIndicator.Label>\n </StatusIndicator>\n <StatusIndicator emphasis=\"low\">\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n <StatusIndicator.Label>Low Emphasis</StatusIndicator.Label>\n </StatusIndicator>\n </Flex>\n );\n};\n```\n\n### Icon\n\nUse `StatusIndicator.Icon` to add an icon to the `StatusIndicator` as a visual decorator. The\nposition of the icon may be adjusted depending on where you place it in the markup.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst parentContainerStyles = createStyles({\n gap: system.space.x4,\n});\n\nexport const Icon = () => {\n return (\n <Flex cs={parentContainerStyles}>\n <StatusIndicator>\n <StatusIndicator.Icon aria-label=\"unpublished\" icon={uploadCloudIcon} />\n <StatusIndicator.Label>Unpublished</StatusIndicator.Label>\n </StatusIndicator>\n <StatusIndicator variant=\"positive\">\n <StatusIndicator.Label>published</StatusIndicator.Label>\n <StatusIndicator.Icon aria-label=\"published\" icon={uploadCloudIcon} />\n </StatusIndicator>\n </Flex>\n );\n};\n```\n\n### Overflow\n\nWe **strongly** discourage using text in a `StatusIndicator` which will cause it to exceed its\nmaximum width of `200px`. In situations where this cannot be avoided and text must be overflowed, we\nsuggest wrapping `StatusIndicator` in an `OverflowTooltip` and applying `tabIndex={0}` to it so the\noverflowed text is accessible via keyboard and mouse. You may also override the default `maxWidth`\nof `StatusIndicator` via [style props](/get-started/for-developers/documentation/style-props/).\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {OverflowTooltip} from '@workday/canvas-kit-react/tooltip';\nimport {calc, createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst statusIndicatorStyles = createStyles({\n maxWidth: calc.add(system.space.x20, system.space.x4),\n});\n\nexport const Overflow = () => {\n return (\n <OverflowTooltip>\n <StatusIndicator tabIndex={0} cs={statusIndicatorStyles}>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n <StatusIndicator.Label>\n Your workbook is currently in process of saving\n </StatusIndicator.Label>\n </StatusIndicator>\n </OverflowTooltip>\n );\n};\n```\n\n### Variants\n\nSet the `variant` prop of `StatusIndicator` to adjust its background color. `variant` accepts the\nfollowing values:\n\n- `gray`\n- `orange`\n- `blue`\n- `green`\n- `red`\n- `transparent`\n\nThe background color dictated by the `variant` will be dark or light based on the `emphasis`.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst styleOverrides = {\n parentContainerStyles: createStyles({\n gap: system.space.x4,\n flexDirection: 'column',\n }),\n innerContainerStyles: createStyles({\n gap: system.space.x4,\n }),\n};\n\nexport const Variants = () => {\n return (\n <Flex cs={styleOverrides.parentContainerStyles}>\n <Flex cs={styleOverrides.innerContainerStyles}>\n <StatusIndicator>\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"caution\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"info\">\n <StatusIndicator.Label>Lorem ipsum dolor </StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"positive\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"critical\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"transparent\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n </Flex>\n <Flex cs={styleOverrides.innerContainerStyles}>\n <StatusIndicator emphasis=\"high\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"caution\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"info\">\n <StatusIndicator.Label>Lorem ipsum dolor </StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"positive\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"critical\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"transparent\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Custom Styles\n\nStatus Indicator and its subcomponents support custom styling via the `cs` prop. For more\ninformation, check our\n[\"How To Customize Styles\"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs).\n\n## Component API\n\n"
|
|
117
|
+
},
|
|
118
|
+
"segmented-control": {
|
|
119
|
+
title: "Preview/Segmented Control",
|
|
120
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-segmented-control--docs",
|
|
121
|
+
mdxPath: "modules/preview-react/segmented-control/stories/SegmentedControl.mdx",
|
|
122
|
+
mdxProse: '# Canvas Kit Segmented Control\n\nSegmented Control is a\n[compound component](/get-started/for-developers/documentation/compound-components/) that represents\na linear group of multiple buttons allowing the selection of a specific value.\n\n[> Workday Design Reference](https://design.workday.com/components/buttons/segmented-control)\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\n`SegmentedControl` includes a container `SegmentedControl` component and the following\nsubcomponents: `SegmentedControl.List` and `SegmentedControl.Item`.\n\nThe example below contains a `SegmentedControl` with four icon-only buttons. Each button is rendered\nusing a `SegmentedControl.Item` and is paired with a tooltip describing the button\'s function. Only\none button can be active at a time.\n```tsx\nimport React from \'react\';\n\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {BodyText} from \'@workday/canvas-kit-react/text\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Basic = () => {\n const [viewType, setViewType] = React.useState(\'table\');\n\n return (\n <>\n <SegmentedControl initialValue={viewType} onSelect={data => setViewType(data.id)}>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon} tooltipProps={{title: \'Table\'}} />\n <SegmentedControl.Item\n data-id="list-view"\n icon={listViewIcon}\n tooltipProps={{title: \'List\'}}\n />\n <SegmentedControl.Item\n data-id="list-detail"\n icon={listDetailIcon}\n tooltipProps={{title: \'Detail\'}}\n />\n <SegmentedControl.Item\n data-id="diagrams"\n icon={pieChartIcon}\n tooltipProps={{title: \'Diagram\'}}\n />\n </SegmentedControl.List>\n </SegmentedControl>\n <BodyText size="small" marginTop="s">\n Selected: {viewType}\n </BodyText>\n </>\n );\n};\n```\n\nWe **strongly** discourage including more than four buttons in a single `SegmentedControl`.\n\n### Accessibility\n\nOur `SegmentedControl` component renders semantic HTML `<button>` elements to the browser DOM,\nwrapped inside of a `<div>` with an explicit ARIA `role="group"`. This is equivalent to an HTML\n`<fieldset>` element, and useful for screen readers to describe the relationship between the\nbuttons.\n\n- Each button is a 2-state toggle button with `aria-pressed={true | false}` to indicate the current\n state to screen readers.\n- Providing your own `aria-label`string to `SegmentedControl.List` is recommended for describing the\n purpose of the component.\n\n#### Screen Reader Experience\n\nWhen users interact with a `SegmentedControl` using screen readers:\n\n- The group context is announced (e.g., "View options, group" when using\n `aria-label="View options"`)\n- Each button announces its text/label, "toggle button" role, and pressed/unpressed state (e.g.,\n "List view, toggle button, pressed" or "Grid view, toggle button, not pressed")\n- For icon-only buttons with tooltips, the tooltip text is announced along with the button role and\n state\n- When a button is activated, screen readers should announce the new state\n\nRefer to [Button](?path=/docs/components-buttons--docs#accessibility) for more information about\naccessibility of these components.\n\n### Variations\n\n`SegmentedControl` supports three variations based on whether or not its `SegmentedControl.Item`\ncomponents have an `icon` prop and/or text content: icon-only, text-only, and text-and-icon.\n\nAll `SegmentedControl.Item` components within a given `SegmentedControl` must be of the same\nvariation.\n\n#### Icon-Only\n\nTo render an icon-only `SegmentedControl`, apply the `icon` prop to `SegmentedControl.Item` and do\nnot provide it with text content. Refer to the [basic example](#basic-example) above for an instance\nof an icon-only `SegmentedControl`.\n\nThe icon-only variation is the only variation which supports a vertical orientation in addition to\nthe default horizontal orientation. Set the `orientation` prop of `SegmentedControl` to `vertical`\nto configure the component to render vertically.\n```tsx\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Vertical = () => (\n <SegmentedControl orientation="vertical">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon} tooltipProps={{title: \'Table\'}} />\n <SegmentedControl.Item\n data-id="list-view"\n icon={listViewIcon}\n tooltipProps={{title: \'List\'}}\n />\n <SegmentedControl.Item\n data-id="list-detail"\n icon={listDetailIcon}\n tooltipProps={{title: \'Detail\'}}\n />\n <SegmentedControl.Item\n data-id="diagram"\n icon={pieChartIcon}\n tooltipProps={{title: \'Diagram\'}}\n />\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n#### Text-Only\n\nTo render a text-only `SegmentedControl`, omit the `icon` prop from `SegmentedControl.Item` and\nprovide it with text content.\n```tsx\nimport React from \'react\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\n\nexport const TextOnly = () => (\n <SegmentedControl>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table">Table</SegmentedControl.Item>\n <SegmentedControl.Item data-id="list">List</SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagram">Diagram</SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n#### Text-and-Icon\n\nTo render a text-and-icon `SegmentedControl`, apply the `icon` prop to `SegmentedControl.Item` and\nprovide it with text content.\n```tsx\nimport React from \'react\';\nimport {gridIcon, listViewIcon, pieChartIcon} from \'@workday/canvas-system-icons-web\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\n\nexport const TextAndIcon = () => (\n <SegmentedControl>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagram" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n### Sizes\n\n`SegmentedControl` accepts a `size` prop which supports the following values:\n\n- `small`\n- `medium` (Default)\n- `large`\n```tsx\nimport React from \'react\';\nimport {Box} from \'@workday/canvas-kit-react/layout\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {BodyText} from \'@workday/canvas-kit-react/text\';\n\nexport const Sizes = () => (\n <>\n <Box>\n <BodyText size="medium" fontWeight="bold" marginTop={0}>\n Small\n </BodyText>\n <SegmentedControl size="small">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n Detail\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </Box>\n <Box>\n <BodyText size="medium" fontWeight="bold">\n Medium\n </BodyText>\n <SegmentedControl size="medium">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n Detail\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </Box>\n <Box>\n <BodyText size="medium" fontWeight="bold">\n Large\n </BodyText>\n <SegmentedControl size="large">\n <SegmentedControl.List aria-label="Content view type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n Detail\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </Box>\n </>\n);\n```\n\n### Disabled\n\nSet the `disabled` prop of `SegmentedControl` to disable the entire component including its buttons.\n```tsx\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Disabled = () => (\n <SegmentedControl disabled>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon} tooltipProps={{title: \'Table\'}} />\n <SegmentedControl.Item\n data-id="list-view"\n icon={listViewIcon}\n tooltipProps={{title: \'List\'}}\n />\n <SegmentedControl.Item\n data-id="list-detail"\n icon={listDetailIcon}\n tooltipProps={{title: \'Detail\'}}\n />\n <SegmentedControl.Item\n data-id="diagrams"\n icon={pieChartIcon}\n tooltipProps={{title: \'Diagram\'}}\n />\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n### Right-to-Left (RTL)\n\n`SegmentedControl` supports right-to-left languages when specified in the `CanvasProvider` `theme`.\n```tsx\nimport {CanvasProvider} from \'@workday/canvas-kit-react/common\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\n\nexport const RTL = () => (\n <CanvasProvider dir="rtl">\n <SegmentedControl initialValue="list-detail">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n \u05E9\u05D5\u05DC\u05D7\u05DF\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n \u05E8\u05E9\u05D9\u05DE\u05D4\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n \u05E4\u05E8\u05D8\u05D9\u05DD\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n \u05EA\u05E8\u05E9\u05D9\u05DD\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </CanvasProvider>\n);\n```\n\n### Dynamic Items\n\n`SegmentedControl` supports a\n[dynamic API](/get-started/for-developers/guides/collection-api/#dynamic-items) where instead\nof statically providing the JSX for each `SegmentedControl.Item`, you pass an array of `items` in\nthe `model` state and provide a render function to display the items.\n```tsx\nimport React from \'react\';\nimport {\n SegmentedControl,\n useSegmentedControlModel,\n} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Dynamic = () => {\n const [viewType, setViewType] = React.useState(\'table\');\n\n const model = useSegmentedControlModel({\n items: [\n {id: \'table\', icon: gridIcon, label: \'Table\'},\n {id: \'list\', icon: listViewIcon, label: \'List\'},\n {id: \'detail\', icon: listDetailIcon, label: \'Detail\'},\n {id: \'diagram\', icon: pieChartIcon, label: \'Diagram\'},\n ],\n size: \'small\',\n initialValue: viewType,\n onSelect: data => {\n console.log(`${data.id} is selected`);\n setViewType(data.id);\n },\n });\n\n return (\n <SegmentedControl model={model}>\n <SegmentedControl.List aria-label="View type">\n {item => (\n <SegmentedControl.Item data-id={item.id} icon={item.icon}>\n {item.label}\n </SegmentedControl.Item>\n )}\n </SegmentedControl.List>\n </SegmentedControl>\n );\n};\n```\n\n## Component API\n\n## Specifications\n\n'
|
|
123
|
+
},
|
|
124
|
+
radio: {
|
|
125
|
+
title: "Preview/Inputs/Radio",
|
|
126
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-inputs-radio--docs",
|
|
127
|
+
mdxPath: "modules/preview-react/radio/stories/Radio.mdx",
|
|
128
|
+
mdxProse: '# Canvas Kit Radio\n\nRadio Buttons allow a user to select one value from a predefined list of 7 or fewer options.\n\n[> Workday Design Reference](https://design.workday.com/components/inputs/radio-buttons)\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\nOur radio component includes a `RadioGroup` container and `RadioGroup.RadioButton`, which renders an\nindividual radio button. Nest related `RadioGroup.RadioButton` buttons within a `RadioGroup` and\nprovide a `name` prop to the `RadioGroup` to group the radio buttons together. Each\n`RadioGroup.Radio` must have a unique `value`. This value is used in conjunction with the `value`\nprop set on the `RadioGroup` to determine which radio button is selected. To tie it all together,\nprovide an `onChange` handler to the `RadioGroup` to track the selected value as it changes.\n\n`RadioGroup` should be used in tandem with [Form Field](/components/inputs/form-field/) where the\n`useFieldset` prop is set to `true` to meet accessibility standards. This ensures the `label` text\nfrom `FormField` is attached to the `RadioGroup` and read out as a group for voiceover.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\nimport {Flex} from \'@workday/canvas-kit-react/layout\';\nimport {createStyles, px2rem} from \'@workday/canvas-kit-styling\';\n\nconst formfieldInputStyles = createStyles({\n width: px2rem(200),\n});\n\nexport const Basic = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Flex flexDirection="column">\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n cs={formfieldInputStyles}\n as={RadioGroup}\n name="pizza-crust"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="custom">\n Butter - the best thing to put on bread\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n Value selected: {value}\n </Flex>\n );\n};\n```\n\nOur example uses [React state](<(https://react.dev/learn/state-a-components-memory)>) to track the\nvalue of the `RadioGroup`.\n\n`RadioGroup` and `RadioGroup.Radio` support keyboard navigation through the proper use of WAI-ARIA\n[properties](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/radiogroup_role#associated_wai-aria_roles_states_and_properties).\n\n### Inverse\n\nSet the `variant` prop of `RadioGroup.RadioButton` to `inverse` to ensure proper contrast on dark\nbackgrounds.\n```tsx\nimport React from \'react\';\nimport {Box} from \'@workday/canvas-kit-react/layout\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst styleOverrides = {\n containerStyles: createStyles({\n backgroundColor: system.color.bg.primary.default,\n padding: system.space.x4,\n }),\n formFieldStyles: createStyles({\n legend: {\n color: system.color.text.inverse,\n },\n }),\n};\n\nexport const Inverse = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Box cs={styleOverrides.containerStyles}>\n <RadioGroup name="crust-inverse" onChange={handleChange} value={value}>\n <RadioGroup.RadioButton variant="inverse" value="deep-dish">\n Deep dish\n </RadioGroup.RadioButton>\n <RadioGroup.RadioButton variant="inverse" value="thin">\n Thin\n </RadioGroup.RadioButton>\n <RadioGroup.RadioButton variant="inverse" value="gluten-free">\n Gluten free\n </RadioGroup.RadioButton>\n <RadioGroup.RadioButton variant="inverse" value="cauliflower">\n Cauliflower\n </RadioGroup.RadioButton>\n </RadioGroup>\n </Box>\n );\n};\n```\n\n### Radio Group with No Value\n\nOmit the `value` prop from `RadioGroup` to render the group with no selected\n`RadioGroup.RadioButton`.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const NoValue = () => {\n const [value, setValue] = React.useState<string | number>(0);\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup>\n <FormFieldGroup.Label as="legend">Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-no-value"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup>\n );\n};\n```\n\n### Ref Forwarding\n\n`RadioGroup.RadioButton` supports [ref forwarding](https://reactjs.org/docs/forwarding-refs.html).\nIt will forward `ref` to its underlying `<input type="radio">` element.\n```tsx\nimport React from \'react\';\nimport {PrimaryButton} from \'@workday/canvas-kit-react/button\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const RefForwarding = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n const glutenFreeRef = React.useRef(null);\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n const handleClick = () => {\n glutenFreeRef.current.click();\n };\n\n return (\n <>\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.List as={RadioGroup} name="crust-ref" onChange={handleChange} value={value}>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free" ref={glutenFreeRef}>\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup>\n <PrimaryButton onClick={handleClick}>Select Gluten Free</PrimaryButton>\n </>\n );\n};\n```\n\n### Label Position\n\nSet the `orientation` prop of the Form Field to designate the position of the label relative to the\ninput component. By default, the orientation will be set to `vertical`.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const LabelPosition = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup orientation="horizontalStart">\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-label"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n### Required\n\nSet the `required` prop of the wrapping `FormField` to `true` to indicate that the field is\nrequired. Labels for required fields are suffixed by a red asterisk.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Required = () => {\n const [value, setValue] = React.useState<string | number>(\'\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup isRequired={true}>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-required"\n onChange={handleChange}\n value={value}\n aria-describedby="choose-crust"\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n <FormFieldGroup.Hint>You must choose a crust</FormFieldGroup.Hint>\n </FormFieldGroup>\n );\n};\n```\n\n### Disabled\n\nSet the `disabled` prop of `RadioGroup.RadioButton` to prevent users from interacting with it. Be\ncareful not to disable a pre-selected radio button as this will block keyboard access to the entire\n`RadioGroup`.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Disabled = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-disabled"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} disabled value="gluten-free">\n Gluten free (sold out)\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n### Custom Radio Button\n\nUse `RadioGroup.Label` instead of `RadioGroup.RadioButton` if you need direct access to the label\nand the radio input. This will allow you to apply custom styling to the text and radio input.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\nimport {Flex} from \'@workday/canvas-kit-react/layout\';\nimport {createStyles, px2rem} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst styleOverrides = {\n formfieldInputStyles: createStyles({\n width: px2rem(200),\n }),\n radioGroupLabelTextStyles: createStyles({\n color: system.color.fg.default,\n }),\n};\n\nexport const Custom = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Flex flexDirection="column">\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="pizza-crust-custom"\n onChange={handleChange}\n cs={styleOverrides.formfieldInputStyles}\n value={value}\n >\n <RadioGroup.Label>\n <FormFieldGroup.Input as={RadioGroup.Label.Input} value="deep-dish" />\n <RadioGroup.Label.Text cs={styleOverrides.radioGroupLabelTextStyles}>\n Deep dish\n </RadioGroup.Label.Text>\n </RadioGroup.Label>\n <RadioGroup.Label>\n <FormFieldGroup.Input as={RadioGroup.Label.Input} value="gluten-free" />\n <RadioGroup.Label.Text cs={styleOverrides.radioGroupLabelTextStyles}>\n Gluten free\n </RadioGroup.Label.Text>\n </RadioGroup.Label>\n <RadioGroup.Label>\n <FormFieldGroup.Input as={RadioGroup.Label.Input} value="cauliflower" />\n <RadioGroup.Label.Text cs={styleOverrides.radioGroupLabelTextStyles}>\n Cauliflower\n </RadioGroup.Label.Text>\n </RadioGroup.Label>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n Value selected: {value}\n </Flex>\n );\n};\n```\n\n### Standalone Radio Button\n\nUse `StyledRadioButton` when you want a styled radio button on its own without using `RadioGroup`.\nYou will need to handle behavior and accessibility.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {StyledRadioButton} from \'@workday/canvas-kit-preview-react/radio\';\nimport {Flex} from \'@workday/canvas-kit-react/layout\';\n\nexport const StandaloneRadio = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Flex flexDirection="column">\n <FormFieldGroup as="fieldset">\n <FormFieldGroup.Label as="legend">Choose Your Pizza Crust</FormFieldGroup.Label>\n <Flex gap="m">\n <Flex as="label" gap="xs">\n <FormFieldGroup.Input\n as={StyledRadioButton}\n onChange={handleChange}\n value="deep-dish"\n name="pizza-crust-standalone"\n checked={value === \'deep-dish\'}\n />\n Deep dish\n </Flex>\n <Flex as="label" gap="xs">\n <FormFieldGroup.Input\n as={StyledRadioButton}\n onChange={handleChange}\n value="gluten-free"\n checked={value === \'gluten-free\'}\n name="pizza-crust-standalone"\n />\n Gluten free\n </Flex>\n </Flex>\n </FormFieldGroup>\n Value selected: {value}\n </Flex>\n );\n};\n```\n\nUse `RadioGroup.Label` when you want more control styling the text and radio input but still want\nsome behavior handled for you.\n\n### Error States\n\nSet the `error` prop of the wrapping `FormField` to `"caution"` or\n`"error"` to set the `RadioGroup` to the alert or error state, respectively. You\nwill also need to set the `hintId` and `hintText` props on the `FormField` to meet accessibility\nstandards. You must set an `aria-describedby` attribute on the `RadioGroup` element that matches the\nvalue of `hintId` set on the `FormField` element. These attributes ensure that the alert message is\nassociated to the `RadioGroup` and read out by voiceover.\n\n#### Caution\n\nUse the alert state when a selection is valid but there is additional information.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Caution = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <FormFieldGroup error="caution" id="hint-alert">\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-alert"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n <FormFieldGroup.Hint>Deep dish is an extra $2.99.</FormFieldGroup.Hint>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n#### Error\n\nUse the error state when the selection is no longer valid.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Error = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <FormFieldGroup error="error">\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-error"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n <FormFieldGroup.Hint>Deep dish is currently sold out.</FormFieldGroup.Hint>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n### React Hook Form\n\nUsing a form library like [React Hook Form](https://www.react-hook-form.com/) is a common use case.\nReference this [CodeSandbox](https://codesandbox.io/s/radio-preview-with-react-hook-form-stn5vr) on\nhow to use `RadioGroup` with React Hook Form.\n\n### Custom Styles\n\nRadio and its subcomponents support custom styling via the `cs` prop. For more information, check\nour\n["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs).\n\n## Component API\n\n'
|
|
129
|
+
},
|
|
130
|
+
pill: {
|
|
131
|
+
title: "Preview/Pill",
|
|
132
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-pill--docs",
|
|
133
|
+
mdxPath: "modules/preview-react/pill/stories/Pill.mdx",
|
|
134
|
+
mdxProse: "# Canvas Kit Pill\n\n`Pill`s are static or interactive indicators that allow users to input, filter, or label\ninformation.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n`Pill`s are used to visually label objects on a page for quick recognition. They\u2019re offered as both\nstatic (read-only) and interactive elements. They allow users to filter a list or table, or label\ninformation to help with scanning and organization.\n\n### Basic Pills\n\nBy default a Pill is considered interactive. All leading elements (icons or avatars) are intended to\nbe descriptive, helping support the label. Do not rely on the leading element to indicate the\ninteraction behavior.\n\n#### Icon\n\nYou can render an icon inside the `Pill` with `Pill.Icon`. It will render a `plusIcon` by default,\nbut it can be customized by providing an icon to the `icon` prop. Because it uses `SystemIcon` under\nthe hood, you also have access to all `SystemIconProps`.\n\n#### Accessibility\n\nYou must provide an `aria-label` to the `Pill.Icon` for proper accessibility.\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\n\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const Basic = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill onClick={() => setText('The first pill is clicked!')}>\n <Pill.Icon aria-label=\"Add user\" />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n <Pill disabled>\n <Pill.Icon aria-label=\"Add user\" />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n#### Avatar\n\nYou can render an avatar image inside the `Pill` with `Pill.Avatar`. It should appear before the\n`Pill` text. Because it uses `Avatar` under the hood, you also have access to all `AvatarProps`.\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\n// @ts-ignore: Cannot find module error\nimport testAvatar from './test-avatar.png';\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithAvatar = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill onClick={() => setText('The first pill is clicked!')}>\n <Pill.Avatar name=\"Regina Skeltor\" url={testAvatar} />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n <Pill disabled>\n <Pill.Avatar name=\"Regina Skeltor\" />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n#### Count\n\nThe count appears after the label. It is usually associated with the label. If you have a category,\nthe count will directly correlate to that category.\n```tsx\nimport React from 'react';\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithCount = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill onClick={() => setText('The first pill is clicked!')}>\n Shoes\n <Pill.Count>30</Pill.Count>\n </Pill>\n <Pill disabled>\n Shoes\n <Pill.Count>30</Pill.Count>\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n### Read Only\n\nThe `readOnly` variant is a non-interactive element that is used to display information.\n\nYou can define a read only `Pill` by providing a `variant='readOnly'` prop.\n```tsx\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithReadOnly = () => (\n <div className={flexStyles} id=\"read-only-list\">\n <Pill variant=\"readOnly\">Read-only</Pill>\n <Pill variant=\"readOnly\" maxWidth={150}>\n Read-only but with super long text in case you want to read a paragraph in a Pill which we\n don't recommend\n </Pill>\n </div>\n);\n```\n\n### Removable Pills\n\nRemovable `Pill`s display an `X` icon after the label. They have a smaller, more specific focus\nstate and click target to be more intentional about their actions and to avoid unintended removal.\n\nYou can define a removable `Pill` by providing a `variant='removable'` prop.\n\n```tsx\n<Pill variant=\"removable\">\n Pink Shirts\n <Pill.IconButton onClick={() => console.warn('clicked')} />\n</Pill>\n```\n\nIn this case, we use a `Pill.IconButton` because the `X` becomes the focusable and clickable\nelement.\n\nThe default icon for `Pill.IconButton` is `xSmallIcon` but this can also be overwritten by passing\nan `icon` prop to `Pill.IconButton`\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\n// @ts-ignore: Cannot find module error\nimport testAvatar from './test-avatar.png';\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {system} from '@workday/canvas-tokens-web';\nimport {createStyles} from '@workday/canvas-kit-styling';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithRemovable = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill variant=\"removable\">\n <Pill.Label>Pink Shirts</Pill.Label>\n <Pill.IconButton\n aria-label=\"Remove\"\n onClick={() => setText('The first pill is clicked!')}\n />\n </Pill>\n <Pill variant=\"removable\">\n <Pill.Avatar name=\"Avatar\" url={testAvatar} />\n <Pill.Label>Carolyn Grimaldi</Pill.Label>\n <Pill.IconButton\n aria-label=\"Remove\"\n onClick={() => setText('The second pill is clicked!')}\n />\n </Pill>\n <Pill variant=\"removable\" disabled>\n <Pill.Label>This is a category that should not exist because it is too long</Pill.Label>\n <Pill.IconButton aria-label=\"Remove\" />\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n### List of Pills\n\n`Pill`s can often represent multiple pieces of information such as a filtered list of categories or\nskills.\n\nIn order to achieve this, use our `Flex` component to wrap each `Pill` and space them out\naccordingly.\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst data = [\n 'Shoes',\n 'Pants',\n 'Dress Shoes',\n 'Color',\n 'Accessories',\n 'Luxury',\n 'Casual',\n 'Hats',\n 'Beanies',\n 'Glasses',\n 'Jewelry',\n];\n\nconst flexWrapStyles = createStyles({\n display: 'flex',\n flexWrap: 'wrap',\n gap: system.space.x2,\n});\n\nexport const WithList = () => {\n const [items, setItems] = React.useState(data);\n\n return (\n <div className={flexWrapStyles}>\n {items.map((cat, index) => {\n return (\n <Pill key={index} variant=\"removable\">\n <Pill.Label>{cat}</Pill.Label>\n <Pill.IconButton\n aria-label=\"Remove\"\n onClick={() => setItems(items.filter(i => i !== cat))}\n />\n </Pill>\n );\n })}\n </div>\n );\n};\n```\n\n### Custom Styles\n\n`Pill` supports custom styling via the `cs` prop. For more information, check our\n[\"How To Customize Styles\"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs)\nor view the example below.\n```tsx\nimport {Pill, pillCountStencil, pillStencil} from '@workday/canvas-kit-preview-react/pill';\n\nimport {createStencil} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\nimport {systemIconStencil} from '@workday/canvas-kit-react/icon';\n\nconst customPillStencil = createStencil({\n base: {\n [pillStencil.vars.background]: system.color.static.green.default,\n [pillStencil.vars.border]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.default,\n [pillCountStencil.vars.borderColor]: system.color.static.green.default,\n\n '&:hover, &.hover': {\n [pillStencil.vars.background]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.stronger,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.borderColor]: system.color.static.green.stronger,\n },\n '&:active, &.active': {\n [pillStencil.vars.background]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.stronger,\n },\n '&:focus, &.focus, &:focus-visible': {\n [pillStencil.vars.background]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.stronger,\n },\n '&:disabled, &.disabled': {\n [pillStencil.vars.background]: system.color.static.green.default,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n },\n },\n});\n\nexport const CustomStyles = () => {\n return (\n <div>\n <Pill cs={customPillStencil()}>\n <Pill.Icon aria-label=\"Add user\" />\n <Pill.Label>Custom Pill Color</Pill.Label>\n <Pill.Count>10</Pill.Count>\n </Pill>\n </div>\n );\n};\n```\n\n## Component API\n\n"
|
|
135
|
+
},
|
|
136
|
+
multiselect: {
|
|
137
|
+
title: "Preview/MultiSelect",
|
|
138
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-multiselect--docs",
|
|
139
|
+
mdxPath: "modules/preview-react/multi-select/stories/MultiSelect.mdx",
|
|
140
|
+
mdxProse: "# Canvas Kit MultiSelect\n\nMultiSelect inputs allow users to choose multiple options from a list of items.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\n`MultiSelect` supports a\n[dynamic API](/get-started/for-developers/guides/collection-api/#dynamic-items) where you\npass an array of items via the `items` prop and provide a render function to display the items. The\nitems may be provided as an\n[array of strings](/get-started/for-developers/guides/collection-api/#array-of-strings) or an\n[array of objects](/get-started/for-developers/guides/collection-api/#array-of-objects).\n\n`MultiSelect` should be used in tandem with [Form Field](/components/inputs/form-field/) where the\n`MultiSelect` wraps the `FormField` element and the `FormField` element wraps the children of\n`MultiSelect` to meet accessibility standards. This ensures the `label` text from `FormField` is\nattached to the `MultiSelect.Input` and read out as a group for voiceover.\n\n```tsx\n<MultiSelect items={options}>\n <FormField label=\"Your Label\">\n <MultiSelect.Input onChange={e => handleChange(e)} id=\"contact-multi-select\" />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => <MultiSelect.Item>{item.id}</MultiSelect.Item>}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n</MultiSelect>\n```\n\n### Disabled Example\n\nDisabling `MultiSelect` involves passing the `disabled` prop to the `MultiSelect.Input` component.\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = ['Cheese', 'Olives', 'Onions', 'Pepperoni', 'Peppers'];\n\nexport const Disabled = () => {\n return (\n <>\n <MultiSelect items={items} initialSelectedIds={['Olives', 'Onions', 'Pepperoni']}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n disabled\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item}>\n <MultiSelect.Item.Text>{item}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </>\n );\n};\n```\n\n### Error States\n\nThe `MultiSelect.Input` and `MultiSelect.SearchInput` support the `ErrorType` from the Common\npackage. The error styling is identical to the `TextInput` error styling. The `error` prop is\ntypically passed from the `FormField` component.\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {MultiSelect, useMultiSelectModel} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = ['Cheese', 'Olives', 'Onions', 'Pepperoni', 'Peppers'];\n\nexport const Error = () => {\n const model = useMultiSelectModel({\n items,\n initialSelectedIds: [],\n });\n return (\n <>\n <MultiSelect model={model}>\n <FormField\n orientation=\"horizontalStart\"\n error={\n model.state.selectedIds.length < 1\n ? 'error'\n : model.state.selectedIds.length > 3\n ? 'caution'\n : undefined\n }\n >\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Field>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item}>\n <MultiSelect.Item.Text>{item}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n\n <FormField.Hint>\n {model.state.selectedIds.length < 1\n ? 'Select at least one topping.'\n : model.state.selectedIds.length > 3\n ? 'More than 3 toppings cost extra.'\n : undefined}\n </FormField.Hint>\n </FormField.Field>\n </FormField>\n </MultiSelect>\n </>\n );\n};\n```\n\n### Complex\n\nWhen registering items in an array of objects, it's common to have the text that is displayed to the\nuser be different than an id. In this example, `serverId` and `label` properties need to be remapped\nto `id` and `text` hence the usage of `getId` and `getTextValue`. If your object has the properties\n`text` and `id`, there would be no need for this.\n```tsx\nimport React from 'react';\n\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {FormField} from '@workday/canvas-kit-react/form-field';\n\nimport {system} from '@workday/canvas-tokens-web';\n\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst mainContentStyles = createStyles({\n padding: system.space.x4,\n});\n\nconst items = [\n {id: '1', text: 'Cheese'},\n {id: '2', text: 'Olives'},\n {id: '3', text: 'Onions'},\n {id: '4', text: 'Pepperoni'},\n {id: '5', text: 'Peppers'},\n];\n\nexport const Complex = () => {\n const [value, setValue] = React.useState('');\n const [label, setLabel] = React.useState('');\n return (\n <CanvasProvider>\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n >\n <main className={mainContentStyles}>\n <MultiSelect items={items} getId={i => i.id} getTextValue={i => i.text}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={e => {\n const value = e.currentTarget.value;\n setValue(value);\n setLabel(\n value\n .split(', ')\n .map(item => items.find(i => i.id === item)?.text || 'Not Found')\n .join(', ')\n );\n }}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </main>\n </form>\n <div>Selected IDs: {value}</div>\n <div>Selected Labels: {label}</div>\n </>\n </CanvasProvider>\n );\n};\n```\n\n### With Icons\n\nUse `MultiSelect.Item.Icon` to render an icon for a `MultiSelect.Item`. The `icon` prop for\n`MultiSelect.Item.Icon` accepts [system icons](/assets/system-icons/) from\n`@workday/canvas-system-icons-web`.\n\n> **Note: `data-id` on `MultiSelect.Item` must match the `id` property in your array of objects.\n> This ensures proper keyboard handling and type-ahead.**\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {\n mediaPauseIcon,\n mediaPlayIcon,\n mediaTopicsIcon,\n skipIcon,\n previousIcon,\n} from '@workday/canvas-system-icons-web';\n\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = [\n {id: '1', text: 'Pause', icon: mediaPauseIcon},\n {id: '2', text: 'Play', icon: mediaPlayIcon},\n {id: '3', text: 'Skip', icon: skipIcon},\n {id: '4', text: 'Previous', icon: previousIcon},\n];\n\nexport const Icons = () => {\n return (\n <MultiSelect items={items}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Controls</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Icon icon={item.icon} />\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n <MultiSelect.Item.Icon icon={mediaTopicsIcon} />\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n );\n};\n```\n\n### Controlled\n\nThe MultiSelect can be a controlled input component by passing the `value` and `onChange` to either\nthe `<MultiSelect>` component or the `<MultiSelect.Input>` component. Internally, the\n`MultiSelect.Input` watches for changes on the `value` React prop as well as the `value` DOM\nproperty and will update the model accordingly.\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {PrimaryButton, SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {Flex} from '@workday/canvas-kit-react/layout';\n\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = [\n {id: '1', text: 'Cheese'},\n {id: '2', text: 'Olives'},\n {id: '3', text: 'Onions'},\n {id: '4', text: 'Pepperoni'},\n {id: '5', text: 'Peppers'},\n];\n\nexport const Controlled = () => {\n const formRef = React.useRef<HTMLFormElement>(null);\n const [value, setValue] = React.useState('1');\n const [label, setLabel] = React.useState('Cheese');\n\n function handleOnChange(event: React.ChangeEvent<HTMLInputElement>) {\n const value = event.currentTarget.value;\n setValue(value);\n setLabel(\n value\n .split(', ')\n .map(item => items.find(i => i.id === item)?.text || 'Not Found')\n .join(', ')\n );\n }\n\n return (\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n ref={formRef}\n >\n <Flex gap=\"s\" flexDirection=\"column\">\n <MultiSelect items={items}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={handleOnChange}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n <Flex gap=\"s\">\n <SecondaryButton\n onClick={e => {\n setValue('1, 2, 3');\n }}\n >\n Set to \"Cheese, Olives, Onions\" via React `value`\n </SecondaryButton>\n <SecondaryButton\n onClick={e => {\n const input = formRef.current.querySelector('[name=toppings]') as HTMLInputElement;\n input.value = '1, 2';\n }}\n >\n Set to \"Cheese, Olives\" via DOM `value`\n </SecondaryButton>\n </Flex>\n <div>\n <PrimaryButton type=\"submit\">Submit</PrimaryButton>\n </div>\n <div>Selected ID: {value}</div>\n <div>Selected Label: {label}</div>\n </Flex>\n </form>\n </>\n );\n};\n```\n\n### Searching\n\nA MultiSelect input can be used as a filter for results. Most likely this also means there are many\nitems that may not be all be loaded from the server at once. The `useComboboxLoader` can be used to\ndynamically load items as the user navigates the available options.\n\n> **Note:** The behavior of search is experimental. The example should continue to work without\n> modification, but how the searchable input is presented to the user may change with user testing.\n> Don't rely too much on the exact behavior of the search input. For example, the search input may\n> be cleared when the user blurs the field.\n```tsx\nimport React from 'react';\n\nimport {system} from '@workday/canvas-tokens-web';\n\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {LoadReturn} from '@workday/canvas-kit-react/collection';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {useComboboxLoader} from '@workday/canvas-kit-react/combobox';\nimport {FormField} from '@workday/canvas-kit-react/form-field';\n\nimport {MultiSelect, useMultiSelectModel} from '@workday/canvas-kit-preview-react/multi-select';\nimport {StyledMenuItem} from '@workday/canvas-kit-react/menu';\n\nconst mainContentStyles = createStyles({\n padding: system.space.x4,\n});\n\nconst colors = ['Red', 'Blue', 'Purple', 'Green', 'Pink'];\nconst fruits = ['Apple', 'Orange', 'Banana', 'Grape', 'Lemon', 'Lime'];\nconst options = Array(1000)\n .fill('')\n .map((_, index) => {\n return {\n id: `${index + 1}`,\n text: `${colors[index % colors.length]} ${fruits[index % fruits.length]} ${index + 1}`,\n };\n });\n\nexport const Searching = () => {\n const [value, setValue] = React.useState('');\n\n const {model, loader} = useComboboxLoader(\n {\n // You can start with any number that makes sense.\n total: 0,\n\n // Pick whatever number makes sense for your API\n pageSize: 20,\n\n // A load function that will be called by the loader. You must return a promise that returns\n // an object like `{items: [], total: 0}`. The `items` will be merged into the loader's cache\n async load({pageNumber, pageSize, filter}) {\n return new Promise<LoadReturn<(typeof options)[0]>>(resolve => {\n // simulate a server response by resolving after a period of time\n setTimeout(() => {\n // simulate paging and filtering based on pre-computed items\n const start = (pageNumber - 1) * pageSize;\n const end = start + pageSize;\n const filteredItems = options.filter(item => {\n if (filter === '' || typeof filter !== 'string') {\n return true;\n }\n return item.text.toLowerCase().includes(filter.toLowerCase());\n });\n\n const total = filteredItems.length;\n const items = filteredItems.slice(start, end);\n\n resolve({\n items,\n total,\n });\n }, 300);\n });\n },\n onShow() {\n // The `shouldLoad` cancels while the combobox menu is hidden, so let's load when it is\n // visible\n loader.load();\n },\n },\n useMultiSelectModel\n );\n\n return (\n <CanvasProvider>\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n >\n <main className={mainContentStyles}>\n <MultiSelect model={model}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Fruits</FormField.Label>\n <FormField.Input\n as={MultiSelect.SearchInput}\n placeholder=\"Search\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={e => {\n setValue(e.currentTarget.value);\n }}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n {model.state.items.length === 0 && (\n <StyledMenuItem as=\"span\">No Results Found</StyledMenuItem>\n )}\n {model.state.items.length > 0 && (\n <MultiSelect.List maxHeight={200}>\n {item =>\n item ? (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n ) : undefined\n }\n </MultiSelect.List>\n )}\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </main>\n </form>\n <div>Selected: {value}</div>\n </>\n </CanvasProvider>\n );\n};\n```\n\n### Initial Selected Items\n\nYou can set `initialSelectedIds` to the value that you want initially selected.\n```tsx\nimport React, {useEffect} from 'react';\n\nimport {system} from '@workday/canvas-tokens-web';\n\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {LoadReturn} from '@workday/canvas-kit-react/collection';\nimport {CanvasProvider, useMountLayout} from '@workday/canvas-kit-react/common';\nimport {useComboboxLoader} from '@workday/canvas-kit-react/combobox';\nimport {FormField} from '@workday/canvas-kit-react/form-field';\n\nimport {MultiSelect, useMultiSelectModel} from '@workday/canvas-kit-preview-react/multi-select';\nimport {StyledMenuItem} from '@workday/canvas-kit-react/menu';\n\nconst mainContentStyles = createStyles({\n padding: system.space.x4,\n});\n\nconst colors = ['Red', 'Blue', 'Purple', 'Green', 'Pink'];\nconst fruits = ['Apple', 'Orange', 'Banana', 'Grape', 'Lemon', 'Lime'];\nconst options = Array(1000)\n .fill('')\n .map((_, index) => {\n return {\n id: `${index + 1}`,\n text: `${colors[index % colors.length]} ${fruits[index % fruits.length]} ${index + 1}`,\n };\n });\n\nexport const InitialSelectedItems = () => {\n const [value, setValue] = React.useState('');\n\n const {model, loader} = useComboboxLoader(\n {\n // You can start with any number that makes sense.\n total: 0,\n initialSelectedIds: ['3', '5'],\n\n // Pick whatever number makes sense for your API\n pageSize: 500,\n\n // A load function that will be called by the loader. You must return a promise that returns\n // an object like `{items: [], total: 0}`. The `items` will be merged into the loader's cache\n async load({pageNumber, pageSize, filter}) {\n return new Promise<LoadReturn<(typeof options)[0]>>(resolve => {\n // simulate a server response by resolving after a period of time\n setTimeout(() => {\n // simulate paging and filtering based on pre-computed items\n const start = (pageNumber - 1) * pageSize;\n const end = start + pageSize;\n const filteredItems = options.filter(item => {\n if (filter === '' || typeof filter !== 'string') {\n return true;\n }\n return item.text.toLowerCase().includes(filter.toLowerCase());\n });\n\n const total = filteredItems.length;\n const items = filteredItems.slice(start, end);\n\n resolve({\n items,\n total,\n });\n }, 300);\n });\n },\n onShow() {\n // The `shouldLoad` cancels while the combobox menu is hidden, so let's load when it is\n // visible\n loader.load();\n },\n },\n useMultiSelectModel\n );\n\n useEffect(() => {\n loader.load();\n }, [loader]);\n\n return (\n <CanvasProvider>\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n >\n <main className={mainContentStyles}>\n <MultiSelect model={model}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Fruits</FormField.Label>\n <FormField.Input\n as={MultiSelect.SearchInput}\n placeholder=\"Search\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={e => {\n setValue(e.currentTarget.value);\n }}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n {model.state.items.length === 0 && (\n <StyledMenuItem as=\"span\">No Results Found</StyledMenuItem>\n )}\n {model.state.items.length > 0 && (\n <MultiSelect.List maxHeight={200}>\n {item =>\n item ? (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n ) : undefined\n }\n </MultiSelect.List>\n )}\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </main>\n </form>\n <div>Selected: {value}</div>\n </>\n </CanvasProvider>\n );\n};\n```\n"
|
|
141
|
+
},
|
|
142
|
+
"loading-sparkles-(ai)": {
|
|
143
|
+
title: "Preview/Loading Sparkles (AI)",
|
|
144
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-loading-sparkles-(ai)--docs",
|
|
145
|
+
mdxPath: "modules/preview-react/loading-sparkles/stories/LoadingSparkles.mdx",
|
|
146
|
+
mdxProse: "# Canvas Kit Loading Sparkles\n\n`LoadingSparkles` is a loading animation that makes users aware an AI operation is in progress.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-react\n```\n\n## Usage\n\n### Basic Example\n\n`LoadingSparkles` is designed to work out-of-the-box, but you'll need to add some wiring for screen\nreaders. In the example below, we're simulating a loading state with a `setTimeout` that's triggered\nwhen the \"Generate Quote\" button is clicked.\n\nThe ARIA live region uses the `aria-label` on `LoadingSparkles` to announce the loading state. And\nit uses the text in `AccessibleHide` to announce when loading is complete. In a real-world\napplication, you would probably add another state for loading failures. Also note that generated\ntext should live outside the live region. This content doesn't need to be announced to screen\nreaders.\n\n#### Consolidating ARIA Live Regions\n\nIn the example, we wrapped `LoadingSparkles` inside our `AriaLiveRegion` component, but in general\nyou should not have multiple ARIA live regions on the page at once. If you already have a live\nregion, consider sending these loading messages there instead of adding another region.\n```tsx\nimport React from 'react';\nimport {SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {LoadingSparkles} from '@workday/canvas-kit-preview-react/loading-sparkles';\nimport {AccessibleHide, AriaLiveRegion} from '@workday/canvas-kit-react/common';\nimport {createStyles} from '@workday/canvas-kit-styling';\n\nconst containerStyles = createStyles({\n minHeight: '3.5rem',\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n});\n\nexport const Basic = () => {\n const [loadingStatus, setLoadingStatus] = React.useState<'idle' | 'loading' | 'success'>('idle');\n const [quote, setQuote] = React.useState('');\n\n React.useEffect(() => {\n if (loadingStatus === 'loading') {\n const mockLoading = setTimeout(() => {\n setLoadingStatus('success');\n setQuote(getQuote());\n }, 3000);\n\n return () => {\n clearTimeout(mockLoading);\n };\n }\n }, [loadingStatus]);\n\n const handleClick = () => {\n setQuote('');\n setLoadingStatus('loading');\n };\n\n return (\n <div>\n <div className={containerStyles}>\n {quote && <Text cs={{maxWidth: '60ch'}}>{quote}</Text>}\n <AriaLiveRegion>\n {loadingStatus === 'loading' && <LoadingSparkles aria-label=\"loading\" />}\n {loadingStatus === 'success' && (\n <AccessibleHide role=\"status\">loading complete</AccessibleHide>\n )}\n </AriaLiveRegion>\n </div>\n <SecondaryButton onClick={handleClick}>Generate Quote</SecondaryButton>\n </div>\n );\n};\n\nconst robotQuotes = [\n 'The Zeroth Law: A robot may not harm humanity, or, by inaction, allow humanity to come to harm.',\n 'Law 1: A robot may not injure a human being or, through inaction, allow a human being to come to harm.',\n 'Law 2: A robot must obey the orders given it by human beings except where such orders would conflict with the First Law.',\n 'Law 3: A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.',\n 'There is nothing so eternally adhesive as the memory of power.',\n];\n\nconst getQuote = () => {\n const index = Math.floor(Math.random() * robotQuotes.length);\n return robotQuotes[index];\n};\n```\n\n### Right-to-Left (RTL)\n```tsx\nimport React from 'react';\nimport {LoadingSparkles} from '@workday/canvas-kit-preview-react/loading-sparkles';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\n\nexport const RTL = () => {\n return (\n <CanvasProvider dir=\"rtl\">\n <LoadingSparkles />\n </CanvasProvider>\n );\n};\n```\n\n## Component API\n\n"
|
|
147
|
+
},
|
|
148
|
+
"information-highlight": {
|
|
149
|
+
title: "Preview/Information Highlight",
|
|
150
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-information-highlight--docs",
|
|
151
|
+
mdxPath: "modules/preview-react/information-highlight/stories/InformationHighlight.mdx",
|
|
152
|
+
mdxProse: "# Canvas Kit Information Highlight\n\nA container to call out important information on a page or a section of a page that the user should\nbe aware of.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n`InformationHighlight` should be used to call out important information to the user and are paired\nwith a meaningful icon and color to differentiate information type. It should not be removed from\nthe interface until some system or admin level action has been taken to do so.\n\nYou can use an `InformationHighlight` to:\n\n- Prevent unwanted consequences from destructive actions\n- Reassure users in their next steps\n- Provide detail into information on the page\n- Show changes in page content\n\n### When to Consider Something Else\n\n- Consider a\n [Banner](https://workday.github.io/canvas-kit/?path=/docs/components-indicators-banner--docs) if\n the message is about system-wide errors or alerts, or if the message appears in response to user\n action.\n- Consider a\n [Dialog](https://workday.github.io/canvas-kit/?path=/docs/components-popups-dialog--docs) if the\n message is critical and requires user action or decision before proceeding\n- Consider a [Toast](https://workday.github.io/canvas-kit/?path=/docs/components-popups-toast--docs)\n if the message is timely, such as communicating updates on the process of an application.\n\n### Basic Example\n```tsx\nimport React from 'react';\n\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\n\nexport const Basic = () => {\n return (\n <InformationHighlight>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>Information Highlight</InformationHighlight.Heading>\n <InformationHighlight.Body>\n {' '}\n This is what an information highlight would look like with with the default settings and\n every field filled in{' '}\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n );\n};\n```\n\n## Variants\n\n`InformationHighlight` has three variants and each `variant` has two types of `emphasis`.\n\nVariants: `informational`, `caution`, `critical`\n\nEmphasis: `low`, `high`\n\nThe variants have different icons and colors to convey severity and the emphasis changes the\nbackground color to have a lower or higher contrast. If no `variant` or `emphasis` is selected the\nlayout will default to `Variant: informational, Emphasis: low`.\n\nThe following examples will show the `low` and `high` emphasis of the three variants. `low` Emphasis\nwill be shown first and should be used when there is other more important information on the page.\n`high` Emphasis will be shown second, and should be used when the highlight is not competing with\nother, more important information.\n\n### Informational\n\nThe informational variant is for _nice to have_ information, such as related features or\nopportunities.\n```tsx\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {system} from '@workday/canvas-tokens-web';\nimport {createStyles} from '@workday/canvas-kit-styling';\n\nconst contentTextStyles = createStyles({\n margin: 0,\n});\n\nconst contentListStyles = createStyles({\n listStyle: 'inside',\n marginInlineStart: 0,\n marginBlockStart: system.space.x2,\n marginBlockEnd: 0,\n padding: 0,\n});\n\nexport const Informational = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <InformationHighlight variant={'informational'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Informational Highlight </InformationHighlight.Heading>\n <InformationHighlight.Body>\n <p className={contentTextStyles}>\n This is a low-emphasis, informational callout. You should use this for nice-to-have\n information, such as:\n </p>\n <ul className={contentListStyles}>\n <li>tangential information or context</li>\n <li>related features</li>\n <li>additional opportunities</li>\n </ul>\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">Learn More</InformationHighlight.Link>\n </InformationHighlight>\n <InformationHighlight variant={'informational'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Informational Highlight </InformationHighlight.Heading>\n <InformationHighlight.Body>\n <p className={contentTextStyles}>\n This is a high-emphasis, informational callout. You should use this for nice-to-have\n information, such as:\n </p>\n <ul className={contentListStyles}>\n <li>tangential information or context</li>\n <li>related features</li>\n <li>additional opportunities</li>\n </ul>\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">Learn More</InformationHighlight.Link>\n </InformationHighlight>\n </Flex>\n );\n};\n```\n\n### Caution\n\nThe caution variant is for _important to know_ information, such as the potential consequences of\nspecific actions.\n```tsx\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {system} from '@workday/canvas-tokens-web';\n\nexport const Caution = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <InformationHighlight variant={'caution'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Caution: Highlight Something </InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below, nothing will happen\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n <InformationHighlight variant={'caution'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Caution: Highlight Something </InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below, nothing will happen\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n </Flex>\n );\n};\n```\n\n### Critical\n\nThe critical variant is for _must know_ information that could otherwise cause failure if the user\nis unaware\n```tsx\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {system} from '@workday/canvas-tokens-web';\n\nexport const Critical = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <InformationHighlight variant={'critical'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>Attention! Highlight Something</InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below it will reroute you back to this page.\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n <InformationHighlight variant={'critical'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>Attention! Highlight Something</InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below it will reroute you back to this page.\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n </Flex>\n );\n};\n```\n\n### RTL Example\n\nInformation Highlight also supports RTL Languages. To enable RTL, set the `dir` attribute on the\nparent dom element that renders your application.\n```tsx\nimport React from 'react';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {system} from '@workday/canvas-tokens-web';\nexport const RTL = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <CanvasProvider dir=\"rtl\">\n <InformationHighlight variant={'caution'} emphasis={'low'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>\n {' '}\n \u0627\u0646\u062A\u0628\u0627\u0647! \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631{' '}\n </InformationHighlight.Heading>\n <InformationHighlight.Body>\n \u0646\u062D\u0646 \u0646\u062F\u0639\u0645 \u0627\u0644\u0644\u063A\u0627\u062A \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">\u0648\u062B\u0627\u0626\u0642</InformationHighlight.Link>\n </InformationHighlight>\n </CanvasProvider>\n <CanvasProvider dir=\"rtl\">\n <InformationHighlight variant={'caution'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>\n {' '}\n \u0627\u0646\u062A\u0628\u0627\u0647! \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631{' '}\n </InformationHighlight.Heading>\n <InformationHighlight.Body>\n \u0646\u062D\u0646 \u0646\u062F\u0639\u0645 \u0627\u0644\u0644\u063A\u0627\u062A \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">\u0648\u062B\u0627\u0626\u0642</InformationHighlight.Link>\n </InformationHighlight>\n </CanvasProvider>\n </Flex>\n );\n};\n```\n\n## Partial and Custom Information Highlights\n\n`InformationHighlight` can use custom icons or be designed to only use some of its components.\n\n### Custom Icon: Critical\n\n### Body Only Example\n```tsx\nimport React from 'react';\n\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\n\nexport const Body = () => {\n return (\n <InformationHighlight>\n <InformationHighlight.Body>\n Only the body of an information highlight\n </InformationHighlight.Body>\n </InformationHighlight>\n );\n};\n```\n\n### Heading Only Example\n```tsx\nimport React from 'react';\n\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\n\nexport const Heading = () => {\n return (\n <InformationHighlight>\n <InformationHighlight.Heading> Only Heading </InformationHighlight.Heading>\n </InformationHighlight>\n );\n};\n```\n\n### Accessible Use of the `as` Prop\n\nLike many of our components, `InformationHighlight` and it's subcomponents accept an `as` prop,\nwhich lets you change the underlying semantic element. For `InformationHighlight.Heading`, you can\nchange the heading level if you were needing to define a different level of importance. This should\nbe done with caution to ensure the best accessibility.\n\n## Component API\n\n## Specifications\n\n"
|
|
153
|
+
},
|
|
154
|
+
divider: {
|
|
155
|
+
title: "Preview/Divider",
|
|
156
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-divider--docs",
|
|
157
|
+
mdxPath: "modules/preview-react/divider/stories/Divider.mdx",
|
|
158
|
+
mdxProse: "# Divider\n\nA `Divider` segments and visually organizes content.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\nUse a `Divider` to separate content and create visual hierarchy. Typically they are used between\nparagraph sections to indicate a break or shift in content. However, they can also be used as\ndecorative elements to provide greater emphasis and visual hierarchy.\n\n### Basic Example\n\nBy default, `Divider` renders a `<hr>` (horizontal rule) element with `0.5rem` of margin on top and\nbottom. The `space` prop allows you to adjust the vertical margin evenly. In the example below, the\n`Divider`s provide a subtle deliniation between each profile card without being as visually\nprominent as a `Card`. The `space` is adjusted to `0.25rem` which applied `0.125rem` to the top and\nbottom margin.\n```tsx\nimport React from 'react';\nimport {Divider} from '@workday/canvas-kit-preview-react/divider';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\nimport {Avatar} from '@workday/canvas-kit-react/avatar';\n\nconst sectionStyles = createStyles({\n display: 'flex',\n flexDirection: 'column',\n gap: system.space.x4,\n maxWidth: '40rem',\n});\n\nexport const Basic = () => {\n const lastIndex = maintainerList.length - 1;\n return (\n <section className={sectionStyles}>\n {maintainerList.map((maintainerData, index) => (\n <>\n <ProfileCard {...maintainerData} />\n {index !== lastIndex && <Divider space={system.space.x1} />}\n </>\n ))}\n </section>\n );\n};\n\nconst maintainerList = [\n {\n id: '44883293',\n name: 'Josh Bagwell',\n bio: 'Software Development Engineer',\n },\n {\n id: '338257',\n name: 'Nicholas Boll',\n bio: 'Principal Software Development Engineer',\n },\n {\n id: '7966550',\n name: 'Manuel Carrera',\n bio: 'Sr. Software Development Engineer',\n },\n {\n id: '146020',\n name: 'James Fan',\n bio: 'Sr. Software Development Engineer',\n },\n {\n id: '48605821',\n name: 'Raisa Primerova',\n bio: 'Software Development Engineer',\n },\n {\n id: '4818182',\n name: 'Alan Smith',\n bio: 'Principal Software Development Engineer',\n },\n];\n\nconst profileCardStyles = createStyles({\n display: 'grid',\n gridGap: '0.5rem',\n gridTemplateColumns: '5rem 1fr',\n gridTemplateRows: '1fr 1fr',\n});\n\nconst profileCardAvatarStyles = createStyles({\n gridColumn: '1',\n gridRow: '1 / 3',\n});\n\nconst profileCardHeadingStyles = createStyles({\n ...system.type.body.large,\n fontWeight: system.fontWeight.bold,\n gridColumn: '2/3',\n gridRow: '1',\n margin: 0,\n});\n\nconst profileCardBodyStyles = createStyles({\n ...system.type.body.small,\n gridColumn: '2',\n gridRow: '2',\n margin: 0,\n});\n\ninterface ProfileCardProps {\n id: string;\n name: string;\n bio: string;\n}\n\nconst ProfileCard = ({id, name, bio}: ProfileCardProps) => (\n <div className={profileCardStyles}>\n <Avatar\n size=\"extraLarge\"\n url={`https://avatars.githubusercontent.com/u/${id}?v=4`}\n altText={`${name}'s avatar`}\n className={profileCardAvatarStyles}\n />\n <h3 className={profileCardHeadingStyles}>{name}</h3>\n <p className={profileCardBodyStyles}>{bio}</p>\n </div>\n);\n```\n\n### Custom Space\n\nYou might also want to apply custom space to `Divider` where the top and bottom margin are not\nequal. The best way to achieve this is with `createStyles` and the `cs` property. In the example\nbelow, the `Divider` is applied as a decorative element to add emphasis to the section heading.\nCustom styles are defined in the `createStyles` function outside the component and are passed to\n`Divider`'s `cs` prop. These styles remove the top margin and set the bottom margin to `1rem`.\n```tsx\nimport React from 'react';\nimport {Divider} from '@workday/canvas-kit-preview-react/divider';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst headingStyles = createStyles({\n ...system.type.body.large,\n fontWeight: system.fontWeight.bold,\n margin: 0,\n});\n\nconst bodyStyles = createStyles({\n ...system.type.body.small,\n margin: 0,\n});\n\nconst customDividerSpace = createStyles({\n margin: `0 0 ${system.space.x4}`,\n});\n\nexport const CustomSpace = () => {\n return (\n <section>\n <h3 className={headingStyles}>Quote of the Day</h3>\n <Divider cs={customDividerSpace} />\n <p className={bodyStyles}>\n \"It is not our differences that divide us. It is our inability to recognize, accept, and\n celebrate those differences.\" \u2013 Audre Lorde\n </p>\n </section>\n );\n};\n```\n\n## Component API\n\n"
|
|
159
|
+
},
|
|
160
|
+
avatar: {
|
|
161
|
+
title: "Preview/Avatar",
|
|
162
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-avatar--docs",
|
|
163
|
+
mdxPath: "modules/preview-react/avatar/stories/Avatar.mdx",
|
|
164
|
+
mdxProse: '# Avatar\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\nThe most basic usage requires only a `name` prop. The component automatically extracts and displays\nthe initials. If you want to display a different set of initials, you can use the `preferredInitials` prop.\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\n\nexport const Basic = () => {\n return <Avatar name="John Doe" />;\n};\n```\n\n### Image Avatar\n\nYou can display a profile image by providing the `url` prop.\n\n> Note: The `url` and the `name` prop is required for the image avatar. The `name` is used for the `alt` attribute on the image.\n\n#### Image Fallback Behavior\n\nThe Avatar component includes intelligent fallback handling:\n\n- While the image loads, the user\'s initials are displayed using the `name` prop\n- If the image fails to load, initials remain visible\n- The `name` prop serves as both the alt text and fallback content\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\n\nexport const Image = () => {\n return (\n <Avatar\n name="Happy Doggo"\n url={\'https://picsum.photos/id/237/300/200\'}\n objectFit="cover"\n size="medium"\n />\n );\n};\n```\n\n### Sizes\n\nThe Avatar component supports the following sizes:\n- `extraExtraSmall` is 24px x 24px\n- `extraSmall` is 32px x 32px\n- `small` is 40px x 40px\n- `medium` is 48px x 48px\n- `large` is 72px x 72px\n- `extraLarge` is 96px x 96px\n- `extraExtraLarge` is 120px x 120px\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst containerStyles = createStyles({\n display: \'inline-flex\',\n gap: system.space.x2,\n});\n\nexport const Size = () => {\n return (\n <div className={containerStyles}>\n <Avatar name="John Doe" size="extraExtraSmall" />\n <Avatar name="Logan McNeil" size="extraSmall" />\n <Avatar name="Wonder Woman" size="small" />\n <Avatar name="Iron Man" size="medium" />\n <Avatar name="Peter Parker" size="large" />\n <Avatar name="Bruce Banner" size="extraLarge" />\n <Avatar name="Elektra" size="extraExtraLarge" />\n </div>\n );\n};\n```\n\n### Variants\n\nChoose from four predefined color schemes:\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst containerStyles = createStyles({\n display: \'inline-flex\',\n gap: system.space.x2,\n});\n\nexport const Variant = () => {\n return (\n <div className={containerStyles}>\n <Avatar name="John Doe" variant="blue" />\n <Avatar name="Logan McNeil" variant="amber" />\n <Avatar name="Wonder Woman" variant="teal" />\n <Avatar name="Elektra" variant="purple" />\n </div>\n );\n};\n```\n\n### Advanced Custom Component\n\nFor complete control over styling and behavior, use the `BaseAvatar` component:\n```tsx\nimport {BaseAvatar} from \'@workday/canvas-kit-preview-react/avatar\';\nimport {createStyles, px2rem} from \'@workday/canvas-kit-styling\';\nimport {base} from \'@workday/canvas-tokens-web\';\n\nconst customStyles = createStyles({\n cursor: \'pointer\',\n backgroundColor: base.magenta300,\n color: base.magenta700,\n borderRadius: \'50%\',\n border: \'none\',\n padding: \'0\',\n margin: \'0\',\n display: \'flex\',\n alignItems: \'center\',\n span: {\n cursor: \'pointer\',\n },\n});\n\nexport const Custom = () => {\n return (\n <BaseAvatar\n size={px2rem(56)}\n cs={customStyles}\n as="button"\n onClick={() => console.log(\'clicked\')}\n >\n <BaseAvatar.Name name="John Doe Jane" />\n </BaseAvatar>\n );\n};\n```\n\n### Accessibility\nIf the Avatar is purely decorative, you can set the `isDecorative` prop to `true` to prevent the `name` prop from being forwarded to the `alt` attribute of the image.\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\n// @ts-ignore\nimport nicholasAvatar from \'./nicholas-avatar.jpg\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {Text} from \'@workday/canvas-kit-react/text\';\nimport {system} from \'@workday/canvas-tokens-web\';\nconst containerStyles = createStyles({\n display: \'inline-flex\',\n gap: system.space.x2,\n alignItems: \'center\',\n});\nexport const Decorative = () => {\n return (\n <div className={containerStyles}>\n <Avatar\n name="Nicholas Smith"\n isDecorative\n url={nicholasAvatar}\n objectFit="cover"\n size="small"\n />\n <Text>Nicholas Smith</Text>\n </div>\n );\n};\n```\n\n## Component API\n\n'
|
|
165
|
+
},
|
|
166
|
+
"side-panel-(new)": {
|
|
167
|
+
title: "Labs/Side Panel (New)",
|
|
168
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/labs-side-panel-(new)--docs",
|
|
169
|
+
mdxPath: "modules/labs-react/side-panel/stories/SidePanel.mdx",
|
|
170
|
+
mdxProse: "# Canvas Kit Side Panel <StorybookStatusIndicator type=\"new\" />\n\n`SidePanel` is a collapsible container that anchors to the left or right side of the screen. It uses\nthe model pattern for state management and is fully accessible.\n\n[> Workday Design Reference](https://design.workday.com/components/containers/side-panel)\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-labs-react\n```\n\n## Migrating from Preview\n\nIf you're migrating from `@workday/canvas-kit-preview-react/side-panel`, here are the key API\nchanges:\n\n### Import Changes\n\n```tsx\n// Before (preview-react)\n\n// After (labs-react)\n```\n\n### Hook API Changes\n\n| Preview (`useSidePanel`) | Labs (`useSidePanelModel`) |\n| -------------------------------- | ------------------------------------------------------- |\n| `initialExpanded: boolean` | `initialTransitionState: 'expanded' \\| 'collapsed'` |\n| `origin: 'left' \\| 'right'` | `origin: 'start' \\| 'end'` |\n| Returns `expanded: boolean` | Returns `model.state.transitionState` |\n| Returns `setExpanded(bool)` | Use `model.events.expand()` / `model.events.collapse()` |\n| Returns `panelProps` to spread | Props applied automatically via `elemPropsHook` |\n| Returns `labelProps` to spread | Use `id={model.state.labelId}` on label element |\n| Returns `controlProps` to spread | Props applied automatically to `SidePanel.ToggleButton` |\n\n### Component API Changes\n\n| Preview | Labs |\n| ---------------------------------------------- | ------------------------------------------------- |\n| `<SidePanel {...panelProps}>` | `<SidePanel model={model}>` or just `<SidePanel>` |\n| `<SidePanel.ToggleButton {...controlProps} />` | `<SidePanel.ToggleButton />` |\n| `<Heading {...labelProps}>` | `<Heading id={model.state.labelId}>` |\n| `expanded` prop on SidePanel | Managed by model's `transitionState` |\n| `touched` prop on SidePanel | Managed internally |\n| `onExpandedChange` callback | Use `onStateTransition` and derive expanded state |\n| `onStateTransition` on component | `onStateTransition` on model config |\n\n### Code Migration Example\n\n```tsx\n// Before (preview-react)\nconst {expanded, panelProps, labelProps, controlProps} = useSidePanel({\n initialExpanded: false,\n});\n\n<SidePanel {...panelProps} origin=\"right\" onExpandedChange={exp => console.log(exp)}>\n <SidePanel.ToggleButton {...controlProps} />\n <Heading {...labelProps}>Panel Title</Heading>\n {expanded && <Content />}\n</SidePanel>;\n\n// After (labs-react)\nconst model = useSidePanelModel({\n initialTransitionState: 'collapsed',\n origin: 'end',\n onStateTransition: state => {\n const isExpanded = state === 'expanded' || state === 'expanding';\n console.log(isExpanded);\n },\n});\n\n<SidePanel model={model}>\n <SidePanel.ToggleButton />\n <Heading id={model.state.labelId}>Panel Title</Heading>\n {model.state.transitionState === 'expanded' && <Content />}\n</SidePanel>;\n```\n\n### Checking Expanded State\n\n```tsx\n// Before (preview-react)\nif (expanded) {\n /* ... */\n}\n\n// After (labs-react) - for exact state\nif (model.state.transitionState === 'expanded') {\n /* ... */\n}\n\n// After (labs-react) - including animation states\nconst isExpanded =\n model.state.transitionState === 'expanded' || model.state.transitionState === 'expanding';\n```\n\n## Usage\n\n### Basic Example\n\n`SidePanel` is composed of three parts:\n\n- The panel container (with an optional `model` prop)\n- A heading (`SidePanel.Heading`) for the panel that is visually hidden when the panel is collapsed\n- A toggle button (`SidePanel.ToggleButton`) to control the expand / collapse states\n\nBidirectional support is built into `SidePanel`. As seen in the example below, CSS Flexbox flips the\npage layout and the panel's contents. `SidePanel` also has logic to flip the position and direction\nof the `ToggleButton` as well as the direction of the expand / collapse animation. If you're using\nCSS Flexbox for layouts and using the provided components, you shouldn't have to provide any custom\nlogic or styling for bidirectional support.\n```tsx\nimport * as React from 'react';\n\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {AccentIcon} from '@workday/canvas-kit-react/icon';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\nimport {rocketIcon} from '@workday/canvas-accent-icons-web';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexHeadingStyles = createStyles({\n alignItems: 'center',\n gap: system.space.x2,\n});\n\nconst viewPortStyles = createStyles({\n height: px2rem(320),\n});\n\nexport const Basic = () => {\n const model = useSidePanelModel();\n\n return (\n <Flex cs={viewPortStyles}>\n <SidePanel model={model}>\n <SidePanel.Heading size=\"small\">\n <Flex cs={flexHeadingStyles}>\n <AccentIcon icon={rocketIcon} />\n Tasks Panel\n </Flex>\n </SidePanel.Heading>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n </SidePanel>\n </Flex>\n );\n};\n```\n\n### Hidden Name\n\n`SidePanel`'s `<section>` element container should always have an accessible name to help screen\nreader users understand the purpose of the panel. For this reason, we recommend using the\n`SidePanel.Heading` component and setting the `hidden` prop to `true`. This will visually hide the\nheading while keeping it accessible to screen readers.\n```tsx\nimport * as React from 'react';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nexport const Heading = () => {\n const model = useSidePanelModel({\n onStateTransition: state => {\n console.log(`state is: ${state}`);\n },\n });\n\n return (\n <Flex cs={stylesOverride.viewport}>\n <SidePanel model={model}>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n <SidePanel.Heading hidden size=\"small\">\n Tasks Panel\n </SidePanel.Heading>\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Side Panel with a hidden title text.\n </Text>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Alternate Variant\n\n`SidePanel` has one variant, `alternate`, which you can supply as a top-level prop. Default depth of\n`alternate` variant is 5, if `alternate` SidePanel has an overlay behavior the depth 6 should be\nused (this case is covered in the Examples section).\n\n### External Control\n\nSometimes you'll want to control `SidePanel`'s expand / collapse behavior from outside the\ncomponent. You can use the model's events (`model.events.expand()` and `model.events.collapse()`) to\nprogrammatically control the panel.\n\n#### Notes about accessibility\n\nWhen using external controls, be mindful of accessibility:\n\n- Use `aria-pressed` on toggle buttons to indicate the current state\n- The `SidePanel.ToggleButton` inside the panel automatically receives the correct ARIA attributes\n- External buttons should have their own accessible labels (don't rely on `aria-labelledby` pointing\n to the panel's label)\n\nIn the following example, we use the model's `transitionState` to determine the button's pressed\nstate and call `model.events.expand()` or `model.events.collapse()` on click.\n```tsx\nimport * as React from 'react';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n panel: createStyles({\n alignItems: 'center',\n padding: system.space.x4,\n }),\n panelHeading: createStyles({\n color: system.color.fg.muted.stronger,\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nexport const ExternalControl = () => {\n const model = useSidePanelModel({\n initialTransitionState: 'collapsed',\n labelId: 'tasks-panel-label',\n });\n\n return (\n <Flex cs={stylesOverride.viewport}>\n <SidePanel model={model}>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n <SidePanel.Heading size=\"small\" cs={stylesOverride.panelHeading}>\n Task Panel\n </SidePanel.Heading>\n {model.state.transitionState === 'expanded' && (\n <Flex cs={stylesOverride.panel}>Contents</Flex>\n )}\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Control the panel externally\n </Text>\n <SecondaryButton\n onClick={\n model.state.transitionState === 'expanded' ? model.events.collapse : model.events.expand\n }\n aria-pressed={model.state.transitionState === 'expanded'}\n >\n {model.state.transitionState === 'expanded' ? 'Hide Side Panel' : 'Show Side Panel'}\n </SecondaryButton>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Right Origin\n\nBy default, `SidePanel` uses a `start` origin (left in LTR, right in RTL). This sets the\n`ToggleButton`'s position and direction as well as the direction of the animation. You can set the\norigin to `\"end\"` to flip these. The origin uses logical properties (`start`/`end`) for proper\nbidirectional support.\n```tsx\nimport {SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\n// local helper hook for setting content direction;\nimport {useDirection} from './useDirection';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n panelContainer: createStyles({\n marginInlineStart: 'auto',\n }),\n panel: createStyles({\n alignItems: 'center',\n justifyContent: 'flex-end',\n padding: system.space.x4,\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nconst RightPanel = () => {\n const model = useSidePanelModel({\n origin: 'end',\n });\n\n return (\n <SidePanel model={model} className={stylesOverride.panelContainer}>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n <Flex cs={stylesOverride.panel}>\n <SidePanel.Heading size=\"small\">Tasks Panel</SidePanel.Heading>\n </Flex>\n </SidePanel>\n );\n};\n\nexport const RightOrigin = () => {\n const {direction, toggleDirection} = useDirection();\n\n return (\n <CanvasProvider dir={direction}>\n <Flex cs={stylesOverride.viewport}>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Toggle the content direction\n </Text>\n <SecondaryButton onClick={toggleDirection}>\n Set to {direction === 'ltr' ? 'Right-to-Left' : 'Left-to-Right'}\n </SecondaryButton>\n </Flex>\n\n <RightPanel />\n </Flex>\n </CanvasProvider>\n );\n};\n```\n\n### Always Open\n\nIf you do not need `SidePanel`'s expand / collapse behavior, you can simply omit the `ToggleButton`.\n```tsx\nimport {AccentIcon} from '@workday/canvas-kit-react/icon';\nimport {rocketIcon} from '@workday/canvas-accent-icons-web';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {system} from '@workday/canvas-tokens-web';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\n\nconst stylesOverride = {\n accentIcon: createStyles({\n marginRight: system.space.x4,\n }),\n pageContainer: createStyles({\n gap: system.space.x4,\n height: px2rem(320),\n }),\n panelContainer: createStyles({\n alignItems: 'center',\n padding: system.space.x4,\n }),\n panelHeading: createStyles({\n color: system.color.fg.default,\n }),\n mainContent: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexBasis: 'auto',\n flex: 1,\n }),\n};\n\nexport const AlwaysOpen = () => {\n const model = useSidePanelModel();\n\n return (\n <Flex cs={stylesOverride.pageContainer}>\n <SidePanel model={model}>\n <Flex cs={stylesOverride.panelContainer}>\n <AccentIcon icon={rocketIcon} cs={stylesOverride.accentIcon} />\n <SidePanel.Heading size=\"small\" cs={stylesOverride.panelHeading}>\n Tasks Panel\n </SidePanel.Heading>\n </Flex>\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.mainContent}>\n <Text as=\"p\" typeLevel=\"body.large\">\n This is the main content section.\n </Text>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Deriving Expanded State\n\nIf you need a simple boolean `expanded` state (similar to the preview-react `onExpandedChange`\ncallback), you can derive it from the `transitionState` using the `onStateTransition` callback on\nthe model.\n\n### onStateTransition\n\nThe `onStateTransition` callback is called whenever the panel's transition state changes. This\nincludes all four states: `expanding`, `expanded`, `collapsing`, and `collapsed`. You can pass this\ncallback directly to the `SidePanel` component or to the `useSidePanelModel` hook.\n\nThe transition flow is:\n\n1. **Collapsing**: `expanded` \u2192 `collapsing` \u2192 `collapsed`\n2. **Expanding**: `collapsed` \u2192 `expanding` \u2192 `expanded`\n\nThis is useful for:\n\n- Triggering side effects when the panel state changes\n- Syncing the panel state with external state management\n- Animating child components based on the transition state\n```tsx\nimport * as React from 'react';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {\n SidePanel,\n useSidePanelModel,\n SidePanelTransitionStates,\n} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {AccessibleHide} from '@workday/canvas-kit-react/common';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nexport const OnStateTransition = () => {\n const [transitionState, setTransitionState] =\n React.useState<SidePanelTransitionStates>('expanded');\n\n const model = useSidePanelModel({\n onStateTransition: state => {\n setTransitionState(state);\n console.log('Expanded changed to:', state);\n },\n });\n\n return (\n <Flex cs={stylesOverride.viewport}>\n <SidePanel model={model}>\n <SidePanel.ToggleButton />\n <SidePanel.Heading hidden size=\"small\">\n Hidden Title\n </SidePanel.Heading>\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Side panel is {transitionState}.\n </Text>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Accessibility\n\n`SidePanel` renders a `<section>` element with an accessible name provided by `aria-labelledby`,\nwhich references the `SidePanel.Heading` component. This ensures screen reader users understand the\npurpose of the panel.\n\n#### Panel and Heading\n\n- The `SidePanel.Heading` provides the accessible name for the panel via `aria-labelledby`\n- When the panel is collapsed, the heading is automatically hidden visually but remains accessible\n to screen readers\n- Use the `hidden` prop on `SidePanel.Heading` if you want the heading always visually hidden\n\n#### Toggle Button\n\n- `SidePanel.ToggleButton` automatically includes `aria-controls` (references the panel's `id`),\n `aria-pressed` (indicates current state), and `aria-describedby` (references the panel's heading)\n- Developers must provide a static `aria-label` string on `SidePanel.ToggleButton` to describe the\n button's purpose (e.g., \"Collapse View\"). Avoid using ambiguous terms like \"Toggle\" in the label.\n Since `aria-pressed` communicates the state, avoid dynamically updating `aria-label`\n- The button includes a Tooltip with customizable text via `tooltipTextExpand` and\n `tooltipTextCollapse` props (defaults: \"Expand View\" and \"Collapse View\")\n- For optimal keyboard navigation, place `SidePanel.ToggleButton` as the first focusable element in\n the panel\n\n## Component API\n\n## Hooks\n\n### useSidePanelModel\n\nThe `useSidePanelModel` hook creates a model for managing the SidePanel's state and events. You can\npass this model to the `SidePanel` component, or let the component create one internally.\n\n```tsx\n\n// Create a model with custom configuration\nconst model = useSidePanelModel({\n initialTransitionState: 'collapsed',\n origin: 'end',\n onStateTransition: state => console.log('State:', state),\n});\n\n// Access state\nmodel.state.transitionState; // 'expanded' | 'expanding' | 'collapsed' | 'collapsing'\nmodel.state.panelId; // unique ID for the panel\nmodel.state.labelId; // unique ID for the label\n\n// Trigger events\nmodel.events.expand(); // Set to expanded (no animation)\nmodel.events.collapse(); // Set to collapsed (no animation)\nmodel.events.handleAnimationStart(); // Start expand/collapse animation\n```\n\n### useSidePanelContainer\n\nThe `useSidePanelContainer` elemProps hook provides the necessary props for the SidePanel container\nelement, including `id`, `aria-labelledby`, and `onTransitionEnd`.\n\n### useSidePanelToggleButtonElemProps\n\nThe `useSidePanelToggleButtonElemProps` elemProps hook provides ARIA attributes for the toggle\nbutton, including `aria-controls`, `aria-expanded`, and `aria-labelledby`.\n\n## Specifications\n\n"
|
|
171
|
+
},
|
|
172
|
+
"ai-ingress-button-(ai)": {
|
|
173
|
+
title: "Labs/AI Ingress Button (AI)",
|
|
174
|
+
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/labs-ai-ingress-button-(ai)--docs",
|
|
175
|
+
mdxPath: "modules/labs-react/ai-ingress-button/stories/AIIngressButton.mdx",
|
|
176
|
+
mdxProse: "# AI Ingress Button\n\nCTA to open and close AI Ingress Button\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-labs-react\n```\n\n## Usage\n\n### Basic Example\n\nYou can click to toggle the AI Ingress Button.\n```tsx\nimport {useState} from 'react';\n\nimport {AIIngressButton} from '@workday/canvas-kit-labs-react/ai-ingress-button';\n\nexport const Basic = () => {\n const [toggled, setToggled] = useState(false);\n return (\n <div>\n <AIIngressButton\n aria-label={toggled ? 'Hide AI Ingress' : 'Show AI Ingress'}\n onClick={() => setToggled(!toggled)}\n toggled={toggled}\n />\n </div>\n );\n};\n```\n\n### Inverse Example\n\nThe Button can also be used on dark backgrounds.\n```tsx\nimport {useState} from 'react';\n\nimport {AIIngressButton} from '@workday/canvas-kit-labs-react/ai-ingress-button';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst darkBackground = createStyles({\n background: system.color.bg.contrast.strong,\n padding: system.space.x8,\n});\n\nexport const Inverse = () => {\n const [toggled, setToggled] = useState(false);\n return (\n <div className={darkBackground}>\n <AIIngressButton\n variant=\"inverse\"\n onClick={() => setToggled(!toggled)}\n aria-label={toggled ? 'Hide Ingress' : 'Show Ingress'}\n toggled={toggled}\n />\n </div>\n );\n};\n```\n\n## Component API\n\n"
|
|
177
|
+
},
|
|
112
178
|
tooltip: {
|
|
113
179
|
title: "Components/Popups/Tooltip",
|
|
114
180
|
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/components-popups-tooltip--docs",
|
|
@@ -301,72 +367,6 @@ var stories_config_default = {
|
|
|
301
367
|
mdxPath: "modules/react/action-bar/stories/ActionBar.mdx",
|
|
302
368
|
mdxProse: "# Canvas Kit Action Bar\n\nAction Bar is a [compound component](/get-started/for-developers/documentation/compound-components/)\nthat contains primary and secondary actions related to a page or task.\n\n[> Workday Design Reference](https://design.workday.com/components/buttons/action-bar)\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-react\n```\n\n## Usage\n\n### Basic Example\n\n`ActionBar` includes a container `ActionBar` component and the following subcomponent:\n`ActionBar.List` which should contains `ActionBar.Item`.\n\nIn a basic example of an `ActionBar` there are two buttons. The primary action button should be used\nonly once and left aligned if content is left to right, followed by secondary buttons. Tertiary\nbuttons should not be used in the Action Bar.\n```tsx\nimport {ActionBar} from '@workday/canvas-kit-react/action-bar';\nimport {PrimaryButton} from '@workday/canvas-kit-react/button';\n\nexport const Basic = () => {\n return (\n <ActionBar>\n <ActionBar.List position=\"relative\" as=\"section\" aria-label=\"Action Bar\">\n <ActionBar.Item as={PrimaryButton} onClick={() => console.log('first action')}>\n First Action\n </ActionBar.Item>\n <ActionBar.Item>Second Action</ActionBar.Item>\n </ActionBar.List>\n </ActionBar>\n );\n};\n```\n\n### Icons Example\n\n`ActionBar.Item` renders a `SecondaryButton` as default, so it's possible to use other Button props\nwith `ActionBar.Item` such as `icon` or `size`.\n```tsx\nimport {ActionBar} from '@workday/canvas-kit-react/action-bar';\nimport {notificationsIcon, alarmClockIcon} from '@workday/canvas-system-icons-web';\nimport {PrimaryButton} from '@workday/canvas-kit-react/button';\n\nexport const Icons = () => {\n return (\n <ActionBar>\n <ActionBar.List position=\"relative\" as=\"section\" aria-label=\"Action Bar\">\n <ActionBar.Item as={PrimaryButton} icon={notificationsIcon}>\n First Action\n </ActionBar.Item>\n <ActionBar.Item icon={alarmClockIcon}>Second Action</ActionBar.Item>\n </ActionBar.List>\n </ActionBar>\n );\n};\n```\n\n### Delete Action Example\n\n`ActionBar.Item` is a `SecondaryButton` by default but it's posible to change it to another element,\nsuch as `DeleteButton`, by using `as` prop.\n```tsx\nimport {ActionBar} from '@workday/canvas-kit-react/action-bar';\nimport {DeleteButton} from '@workday/canvas-kit-react/button';\n\nexport const DeleteAction = () => {\n return (\n <ActionBar>\n <ActionBar.List position=\"relative\" as=\"section\" aria-label=\"Action Bar\">\n <ActionBar.Item as={DeleteButton}>Delete Action</ActionBar.Item>\n <ActionBar.Item>Second Action</ActionBar.Item>\n </ActionBar.List>\n </ActionBar>\n );\n};\n```\n\n### Overflow Example\n\n`ActionBar` container can contain up to 3 actions and an Overflow Menu if there are more than 3\nactions, the other remaining actions should be placed into an Overflow Menu that is launched by\nclicking the Overflow Button.\n\nAlso, ActionBar is a responsive component based on the width of its container. If the rendered\nactions exceed the width of the `ActionBar.List`, an overflow menu will be rendered. This only works\nagainst the dynamic API where you give the `ActionBarModel` an array of items to be rendered. The\ndynamic API handles the React `key` for you based on the item's identifier. The dynamic API requires\neither an `id` on each item object or a `getId` function that returns an identifier based on the\nitem. The below example uses an `id` property on each item.\n\nThe dynamic API takes in any object, but since nothing is known about your object, a\n[render prop](https://reactjs.org/docs/render-props.html) is necessary to instruct a list how it\nshould render.\n```tsx\nimport React from 'react';\nimport {breakpoints} from '@workday/canvas-kit-react/common';\nimport {ActionBar, useActionBarModel} from '@workday/canvas-kit-react/action-bar';\nimport {PrimaryButton} from '@workday/canvas-kit-react/button';\nimport {SegmentedControl} from '@workday/canvas-kit-preview-react/segmented-control';\nimport {Box} from '@workday/canvas-kit-react/layout';\n\ntype MyActionItem = {\n id: string;\n text: React.ReactNode;\n};\n\nexport const OverflowActionBar = () => {\n const [items] = React.useState<MyActionItem[]>([\n {id: 'first', text: 'First Action'},\n {id: 'second', text: 'Second Action'},\n {id: 'third', text: 'Third Action'},\n {id: 'fourth', text: 'Fourth Action'},\n {id: 'fifth', text: 'Fifth Action'},\n ]);\n\n const model = useActionBarModel({items});\n const [containerWidth, setContainerWidth] = React.useState<string | number>('100%');\n\n return (\n <div>\n <Box maxWidth={containerWidth} marginBottom=\"xl\">\n <ActionBar model={model}>\n <ActionBar.List\n position=\"relative\"\n as=\"section\"\n aria-label=\"Action Bar\"\n overflowButton={<ActionBar.OverflowButton aria-label=\"More actions\" />}\n >\n {(item: MyActionItem, index) => (\n <ActionBar.Item\n as={index === 0 ? PrimaryButton : undefined}\n onClick={() => console.log(item.id)}\n >\n {item.text}\n </ActionBar.Item>\n )}\n </ActionBar.List>\n <ActionBar.Menu.Popper>\n <ActionBar.Menu.Card maxWidth={300} maxHeight={200}>\n <ActionBar.Menu.List>\n {(item: MyActionItem) => (\n <ActionBar.Menu.Item onClick={() => console.log(item.id)}>\n {item.text}\n </ActionBar.Menu.Item>\n )}\n </ActionBar.Menu.List>\n </ActionBar.Menu.Card>\n </ActionBar.Menu.Popper>\n </ActionBar>\n </Box>\n <footer>\n <h4>Change Action Bar container size</h4>\n <SegmentedControl onSelect={data => setContainerWidth(data.id)}>\n <SegmentedControl.List role=\"group\" aria-label=\"container width control\" marginBottom=\"m\">\n <SegmentedControl.Item data-id=\"100%\">100%</SegmentedControl.Item>\n <SegmentedControl.Item data-id={`${breakpoints.m}px`}>Small</SegmentedControl.Item>\n <SegmentedControl.Item data-id=\"420px\">420px</SegmentedControl.Item>\n <SegmentedControl.Item data-id={`${breakpoints.s}px`}>\n Extra Small\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n <p>Selected: {containerWidth}</p>\n </footer>\n </div>\n );\n};\n```\n\nThe number of visible buttons can also be adjusted by using the model's `maximumVisible` attribute.\nYou can change it from the default of 3 to any number greater than 1 and less than items.length.\n```tsx\nimport React from 'react';\nimport {ActionBar} from '@workday/canvas-kit-react/action-bar';\n\ntype MyActionItem = {\n id: string;\n text: React.ReactNode;\n};\n\nexport const OverflowActionBarCustomButtonCount = () => {\n const [items] = React.useState<MyActionItem[]>([\n {id: 'view', text: 'View'},\n {id: 'edit', text: 'Edit'},\n {id: 'delete', text: 'Delete'},\n ]);\n\n return (\n <ActionBar items={items} maximumVisible={2}>\n <ActionBar.List\n as=\"section\"\n aria-label=\"Custom button count overflow example\"\n position=\"relative\"\n overflowButton={<ActionBar.OverflowButton aria-label=\"More actions\" />}\n >\n {(item: MyActionItem) => (\n <ActionBar.Item onClick={() => console.log(item.id)}>{item.text}</ActionBar.Item>\n )}\n </ActionBar.List>\n <ActionBar.Menu.Popper>\n <ActionBar.Menu.Card>\n <ActionBar.Menu.List>\n {(item: MyActionItem) => (\n <ActionBar.Menu.Item onClick={() => console.log(item.id)}>\n {item.text}\n </ActionBar.Menu.Item>\n )}\n </ActionBar.Menu.List>\n </ActionBar.Menu.Card>\n </ActionBar.Menu.Popper>\n </ActionBar>\n );\n};\n```\n\n## Accessibility\n\nGrouping the actions into an HTML `<section>` element with an `aria-label` string is recommended.\nThis can be useful for helping screen reader users quickly jump down to the actions at the bottom of\na page.\n\nRefer to [Button](/components/buttons/button/#accessibility) and\n[Menus](/components/popups/menu/#accessibility) for more information about accessibiliy of these\ncomponents in the Action Bar.\n\n## Component API\n\n"
|
|
303
369
|
},
|
|
304
|
-
"status-indicator": {
|
|
305
|
-
title: "Preview/Status Indicator",
|
|
306
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-status-indicator--docs",
|
|
307
|
-
mdxPath: "modules/preview-react/status-indicator/stories/StatusIndicator.mdx",
|
|
308
|
-
mdxProse: "# Canvas Kit Status Indicator\n\nStatus Indicators help the user quickly identify the status of a task, action, or page element.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\n`StatusIndicator` includes a container `StatusIndicator` component and the following subcomponents\nwhich can be composed in a variety of ways: `StatusIndicator.Label` and `StatusIndicator.Icon`.\n\nA basic `StatusIndicator` with a `StatusIndicator.Label` will render text with a gray background and\nlow emphasis.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\n\nexport const Basic = () => {\n return (\n <StatusIndicator>\n <StatusIndicator.Label>Unpublished</StatusIndicator.Label>\n </StatusIndicator>\n );\n};\n```\n\n### Emphasis\n\nSet the `emphasis` prop of `StatusIndicator` to adjust the contrast between the text and background\ncolor. Emphasis is typically used to convey more visual urgency.\n\n`emphasis` accepts `high` or `low`.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst parentContainerStyles = createStyles({\n gap: system.space.x4,\n});\n\nexport const Emphasis = () => {\n return (\n <Flex cs={parentContainerStyles}>\n <StatusIndicator emphasis=\"high\">\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n <StatusIndicator.Label>High Emphasis</StatusIndicator.Label>\n </StatusIndicator>\n <StatusIndicator emphasis=\"low\">\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n <StatusIndicator.Label>Low Emphasis</StatusIndicator.Label>\n </StatusIndicator>\n </Flex>\n );\n};\n```\n\n### Icon\n\nUse `StatusIndicator.Icon` to add an icon to the `StatusIndicator` as a visual decorator. The\nposition of the icon may be adjusted depending on where you place it in the markup.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst parentContainerStyles = createStyles({\n gap: system.space.x4,\n});\n\nexport const Icon = () => {\n return (\n <Flex cs={parentContainerStyles}>\n <StatusIndicator>\n <StatusIndicator.Icon aria-label=\"unpublished\" icon={uploadCloudIcon} />\n <StatusIndicator.Label>Unpublished</StatusIndicator.Label>\n </StatusIndicator>\n <StatusIndicator variant=\"positive\">\n <StatusIndicator.Label>published</StatusIndicator.Label>\n <StatusIndicator.Icon aria-label=\"published\" icon={uploadCloudIcon} />\n </StatusIndicator>\n </Flex>\n );\n};\n```\n\n### Overflow\n\nWe **strongly** discourage using text in a `StatusIndicator` which will cause it to exceed its\nmaximum width of `200px`. In situations where this cannot be avoided and text must be overflowed, we\nsuggest wrapping `StatusIndicator` in an `OverflowTooltip` and applying `tabIndex={0}` to it so the\noverflowed text is accessible via keyboard and mouse. You may also override the default `maxWidth`\nof `StatusIndicator` via [style props](/get-started/for-developers/documentation/style-props/).\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {OverflowTooltip} from '@workday/canvas-kit-react/tooltip';\nimport {calc, createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst statusIndicatorStyles = createStyles({\n maxWidth: calc.add(system.space.x20, system.space.x4),\n});\n\nexport const Overflow = () => {\n return (\n <OverflowTooltip>\n <StatusIndicator tabIndex={0} cs={statusIndicatorStyles}>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n <StatusIndicator.Label>\n Your workbook is currently in process of saving\n </StatusIndicator.Label>\n </StatusIndicator>\n </OverflowTooltip>\n );\n};\n```\n\n### Variants\n\nSet the `variant` prop of `StatusIndicator` to adjust its background color. `variant` accepts the\nfollowing values:\n\n- `gray`\n- `orange`\n- `blue`\n- `green`\n- `red`\n- `transparent`\n\nThe background color dictated by the `variant` will be dark or light based on the `emphasis`.\n```tsx\nimport React from 'react';\n\nimport {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';\nimport {uploadCloudIcon} from '@workday/canvas-system-icons-web';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst styleOverrides = {\n parentContainerStyles: createStyles({\n gap: system.space.x4,\n flexDirection: 'column',\n }),\n innerContainerStyles: createStyles({\n gap: system.space.x4,\n }),\n};\n\nexport const Variants = () => {\n return (\n <Flex cs={styleOverrides.parentContainerStyles}>\n <Flex cs={styleOverrides.innerContainerStyles}>\n <StatusIndicator>\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"caution\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"info\">\n <StatusIndicator.Label>Lorem ipsum dolor </StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"positive\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"critical\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator variant=\"transparent\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n </Flex>\n <Flex cs={styleOverrides.innerContainerStyles}>\n <StatusIndicator emphasis=\"high\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"caution\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"info\">\n <StatusIndicator.Label>Lorem ipsum dolor </StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"positive\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"critical\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n <StatusIndicator emphasis=\"high\" variant=\"transparent\">\n <StatusIndicator.Label>Lorem ipsum dolor</StatusIndicator.Label>\n <StatusIndicator.Icon icon={uploadCloudIcon} />\n </StatusIndicator>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Custom Styles\n\nStatus Indicator and its subcomponents support custom styling via the `cs` prop. For more\ninformation, check our\n[\"How To Customize Styles\"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs).\n\n## Component API\n\n"
|
|
309
|
-
},
|
|
310
|
-
"segmented-control": {
|
|
311
|
-
title: "Preview/Segmented Control",
|
|
312
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-segmented-control--docs",
|
|
313
|
-
mdxPath: "modules/preview-react/segmented-control/stories/SegmentedControl.mdx",
|
|
314
|
-
mdxProse: '# Canvas Kit Segmented Control\n\nSegmented Control is a\n[compound component](/get-started/for-developers/documentation/compound-components/) that represents\na linear group of multiple buttons allowing the selection of a specific value.\n\n[> Workday Design Reference](https://design.workday.com/components/buttons/segmented-control)\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\n`SegmentedControl` includes a container `SegmentedControl` component and the following\nsubcomponents: `SegmentedControl.List` and `SegmentedControl.Item`.\n\nThe example below contains a `SegmentedControl` with four icon-only buttons. Each button is rendered\nusing a `SegmentedControl.Item` and is paired with a tooltip describing the button\'s function. Only\none button can be active at a time.\n```tsx\nimport React from \'react\';\n\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {BodyText} from \'@workday/canvas-kit-react/text\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Basic = () => {\n const [viewType, setViewType] = React.useState(\'table\');\n\n return (\n <>\n <SegmentedControl initialValue={viewType} onSelect={data => setViewType(data.id)}>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon} tooltipProps={{title: \'Table\'}} />\n <SegmentedControl.Item\n data-id="list-view"\n icon={listViewIcon}\n tooltipProps={{title: \'List\'}}\n />\n <SegmentedControl.Item\n data-id="list-detail"\n icon={listDetailIcon}\n tooltipProps={{title: \'Detail\'}}\n />\n <SegmentedControl.Item\n data-id="diagrams"\n icon={pieChartIcon}\n tooltipProps={{title: \'Diagram\'}}\n />\n </SegmentedControl.List>\n </SegmentedControl>\n <BodyText size="small" marginTop="s">\n Selected: {viewType}\n </BodyText>\n </>\n );\n};\n```\n\nWe **strongly** discourage including more than four buttons in a single `SegmentedControl`.\n\n### Accessibility\n\nOur `SegmentedControl` component renders semantic HTML `<button>` elements to the browser DOM,\nwrapped inside of a `<div>` with an explicit ARIA `role="group"`. This is equivalent to an HTML\n`<fieldset>` element, and useful for screen readers to describe the relationship between the\nbuttons.\n\n- Each button is a 2-state toggle button with `aria-pressed={true | false}` to indicate the current\n state to screen readers.\n- Providing your own `aria-label`string to `SegmentedControl.List` is recommended for describing the\n purpose of the component.\n\n#### Screen Reader Experience\n\nWhen users interact with a `SegmentedControl` using screen readers:\n\n- The group context is announced (e.g., "View options, group" when using\n `aria-label="View options"`)\n- Each button announces its text/label, "toggle button" role, and pressed/unpressed state (e.g.,\n "List view, toggle button, pressed" or "Grid view, toggle button, not pressed")\n- For icon-only buttons with tooltips, the tooltip text is announced along with the button role and\n state\n- When a button is activated, screen readers should announce the new state\n\nRefer to [Button](?path=/docs/components-buttons--docs#accessibility) for more information about\naccessibility of these components.\n\n### Variations\n\n`SegmentedControl` supports three variations based on whether or not its `SegmentedControl.Item`\ncomponents have an `icon` prop and/or text content: icon-only, text-only, and text-and-icon.\n\nAll `SegmentedControl.Item` components within a given `SegmentedControl` must be of the same\nvariation.\n\n#### Icon-Only\n\nTo render an icon-only `SegmentedControl`, apply the `icon` prop to `SegmentedControl.Item` and do\nnot provide it with text content. Refer to the [basic example](#basic-example) above for an instance\nof an icon-only `SegmentedControl`.\n\nThe icon-only variation is the only variation which supports a vertical orientation in addition to\nthe default horizontal orientation. Set the `orientation` prop of `SegmentedControl` to `vertical`\nto configure the component to render vertically.\n```tsx\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Vertical = () => (\n <SegmentedControl orientation="vertical">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon} tooltipProps={{title: \'Table\'}} />\n <SegmentedControl.Item\n data-id="list-view"\n icon={listViewIcon}\n tooltipProps={{title: \'List\'}}\n />\n <SegmentedControl.Item\n data-id="list-detail"\n icon={listDetailIcon}\n tooltipProps={{title: \'Detail\'}}\n />\n <SegmentedControl.Item\n data-id="diagram"\n icon={pieChartIcon}\n tooltipProps={{title: \'Diagram\'}}\n />\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n#### Text-Only\n\nTo render a text-only `SegmentedControl`, omit the `icon` prop from `SegmentedControl.Item` and\nprovide it with text content.\n```tsx\nimport React from \'react\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\n\nexport const TextOnly = () => (\n <SegmentedControl>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table">Table</SegmentedControl.Item>\n <SegmentedControl.Item data-id="list">List</SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagram">Diagram</SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n#### Text-and-Icon\n\nTo render a text-and-icon `SegmentedControl`, apply the `icon` prop to `SegmentedControl.Item` and\nprovide it with text content.\n```tsx\nimport React from \'react\';\nimport {gridIcon, listViewIcon, pieChartIcon} from \'@workday/canvas-system-icons-web\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\n\nexport const TextAndIcon = () => (\n <SegmentedControl>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagram" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n### Sizes\n\n`SegmentedControl` accepts a `size` prop which supports the following values:\n\n- `small`\n- `medium` (Default)\n- `large`\n```tsx\nimport React from \'react\';\nimport {Box} from \'@workday/canvas-kit-react/layout\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {BodyText} from \'@workday/canvas-kit-react/text\';\n\nexport const Sizes = () => (\n <>\n <Box>\n <BodyText size="medium" fontWeight="bold" marginTop={0}>\n Small\n </BodyText>\n <SegmentedControl size="small">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n Detail\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </Box>\n <Box>\n <BodyText size="medium" fontWeight="bold">\n Medium\n </BodyText>\n <SegmentedControl size="medium">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n Detail\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </Box>\n <Box>\n <BodyText size="medium" fontWeight="bold">\n Large\n </BodyText>\n <SegmentedControl size="large">\n <SegmentedControl.List aria-label="Content view type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n Table\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n List\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n Detail\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n Diagram\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </Box>\n </>\n);\n```\n\n### Disabled\n\nSet the `disabled` prop of `SegmentedControl` to disable the entire component including its buttons.\n```tsx\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Disabled = () => (\n <SegmentedControl disabled>\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon} tooltipProps={{title: \'Table\'}} />\n <SegmentedControl.Item\n data-id="list-view"\n icon={listViewIcon}\n tooltipProps={{title: \'List\'}}\n />\n <SegmentedControl.Item\n data-id="list-detail"\n icon={listDetailIcon}\n tooltipProps={{title: \'Detail\'}}\n />\n <SegmentedControl.Item\n data-id="diagrams"\n icon={pieChartIcon}\n tooltipProps={{title: \'Diagram\'}}\n />\n </SegmentedControl.List>\n </SegmentedControl>\n);\n```\n\n### Right-to-Left (RTL)\n\n`SegmentedControl` supports right-to-left languages when specified in the `CanvasProvider` `theme`.\n```tsx\nimport {CanvasProvider} from \'@workday/canvas-kit-react/common\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\nimport {SegmentedControl} from \'@workday/canvas-kit-preview-react/segmented-control\';\n\nexport const RTL = () => (\n <CanvasProvider dir="rtl">\n <SegmentedControl initialValue="list-detail">\n <SegmentedControl.List aria-label="View type">\n <SegmentedControl.Item data-id="table" icon={gridIcon}>\n \u05E9\u05D5\u05DC\u05D7\u05DF\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-view" icon={listViewIcon}>\n \u05E8\u05E9\u05D9\u05DE\u05D4\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="list-detail" icon={listDetailIcon}>\n \u05E4\u05E8\u05D8\u05D9\u05DD\n </SegmentedControl.Item>\n <SegmentedControl.Item data-id="diagrams" icon={pieChartIcon}>\n \u05EA\u05E8\u05E9\u05D9\u05DD\n </SegmentedControl.Item>\n </SegmentedControl.List>\n </SegmentedControl>\n </CanvasProvider>\n);\n```\n\n### Dynamic Items\n\n`SegmentedControl` supports a\n[dynamic API](/get-started/for-developers/guides/collection-api/#dynamic-items) where instead\nof statically providing the JSX for each `SegmentedControl.Item`, you pass an array of `items` in\nthe `model` state and provide a render function to display the items.\n```tsx\nimport React from \'react\';\nimport {\n SegmentedControl,\n useSegmentedControlModel,\n} from \'@workday/canvas-kit-preview-react/segmented-control\';\nimport {\n gridIcon,\n listViewIcon,\n listDetailIcon,\n pieChartIcon,\n} from \'@workday/canvas-system-icons-web\';\n\nexport const Dynamic = () => {\n const [viewType, setViewType] = React.useState(\'table\');\n\n const model = useSegmentedControlModel({\n items: [\n {id: \'table\', icon: gridIcon, label: \'Table\'},\n {id: \'list\', icon: listViewIcon, label: \'List\'},\n {id: \'detail\', icon: listDetailIcon, label: \'Detail\'},\n {id: \'diagram\', icon: pieChartIcon, label: \'Diagram\'},\n ],\n size: \'small\',\n initialValue: viewType,\n onSelect: data => {\n console.log(`${data.id} is selected`);\n setViewType(data.id);\n },\n });\n\n return (\n <SegmentedControl model={model}>\n <SegmentedControl.List aria-label="View type">\n {item => (\n <SegmentedControl.Item data-id={item.id} icon={item.icon}>\n {item.label}\n </SegmentedControl.Item>\n )}\n </SegmentedControl.List>\n </SegmentedControl>\n );\n};\n```\n\n## Component API\n\n## Specifications\n\n'
|
|
315
|
-
},
|
|
316
|
-
radio: {
|
|
317
|
-
title: "Preview/Inputs/Radio",
|
|
318
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-inputs-radio--docs",
|
|
319
|
-
mdxPath: "modules/preview-react/radio/stories/Radio.mdx",
|
|
320
|
-
mdxProse: '# Canvas Kit Radio\n\nRadio Buttons allow a user to select one value from a predefined list of 7 or fewer options.\n\n[> Workday Design Reference](https://design.workday.com/components/inputs/radio-buttons)\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\nOur radio component includes a `RadioGroup` container and `RadioGroup.RadioButton`, which renders an\nindividual radio button. Nest related `RadioGroup.RadioButton` buttons within a `RadioGroup` and\nprovide a `name` prop to the `RadioGroup` to group the radio buttons together. Each\n`RadioGroup.Radio` must have a unique `value`. This value is used in conjunction with the `value`\nprop set on the `RadioGroup` to determine which radio button is selected. To tie it all together,\nprovide an `onChange` handler to the `RadioGroup` to track the selected value as it changes.\n\n`RadioGroup` should be used in tandem with [Form Field](/components/inputs/form-field/) where the\n`useFieldset` prop is set to `true` to meet accessibility standards. This ensures the `label` text\nfrom `FormField` is attached to the `RadioGroup` and read out as a group for voiceover.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\nimport {Flex} from \'@workday/canvas-kit-react/layout\';\nimport {createStyles, px2rem} from \'@workday/canvas-kit-styling\';\n\nconst formfieldInputStyles = createStyles({\n width: px2rem(200),\n});\n\nexport const Basic = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Flex flexDirection="column">\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n cs={formfieldInputStyles}\n as={RadioGroup}\n name="pizza-crust"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="custom">\n Butter - the best thing to put on bread\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n Value selected: {value}\n </Flex>\n );\n};\n```\n\nOur example uses [React state](<(https://react.dev/learn/state-a-components-memory)>) to track the\nvalue of the `RadioGroup`.\n\n`RadioGroup` and `RadioGroup.Radio` support keyboard navigation through the proper use of WAI-ARIA\n[properties](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/radiogroup_role#associated_wai-aria_roles_states_and_properties).\n\n### Inverse\n\nSet the `variant` prop of `RadioGroup.RadioButton` to `inverse` to ensure proper contrast on dark\nbackgrounds.\n```tsx\nimport React from \'react\';\nimport {Box} from \'@workday/canvas-kit-react/layout\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst styleOverrides = {\n containerStyles: createStyles({\n backgroundColor: system.color.bg.primary.default,\n padding: system.space.x4,\n }),\n formFieldStyles: createStyles({\n legend: {\n color: system.color.text.inverse,\n },\n }),\n};\n\nexport const Inverse = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Box cs={styleOverrides.containerStyles}>\n <RadioGroup name="crust-inverse" onChange={handleChange} value={value}>\n <RadioGroup.RadioButton variant="inverse" value="deep-dish">\n Deep dish\n </RadioGroup.RadioButton>\n <RadioGroup.RadioButton variant="inverse" value="thin">\n Thin\n </RadioGroup.RadioButton>\n <RadioGroup.RadioButton variant="inverse" value="gluten-free">\n Gluten free\n </RadioGroup.RadioButton>\n <RadioGroup.RadioButton variant="inverse" value="cauliflower">\n Cauliflower\n </RadioGroup.RadioButton>\n </RadioGroup>\n </Box>\n );\n};\n```\n\n### Radio Group with No Value\n\nOmit the `value` prop from `RadioGroup` to render the group with no selected\n`RadioGroup.RadioButton`.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const NoValue = () => {\n const [value, setValue] = React.useState<string | number>(0);\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup>\n <FormFieldGroup.Label as="legend">Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-no-value"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup>\n );\n};\n```\n\n### Ref Forwarding\n\n`RadioGroup.RadioButton` supports [ref forwarding](https://reactjs.org/docs/forwarding-refs.html).\nIt will forward `ref` to its underlying `<input type="radio">` element.\n```tsx\nimport React from \'react\';\nimport {PrimaryButton} from \'@workday/canvas-kit-react/button\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const RefForwarding = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n const glutenFreeRef = React.useRef(null);\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n const handleClick = () => {\n glutenFreeRef.current.click();\n };\n\n return (\n <>\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.List as={RadioGroup} name="crust-ref" onChange={handleChange} value={value}>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free" ref={glutenFreeRef}>\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup>\n <PrimaryButton onClick={handleClick}>Select Gluten Free</PrimaryButton>\n </>\n );\n};\n```\n\n### Label Position\n\nSet the `orientation` prop of the Form Field to designate the position of the label relative to the\ninput component. By default, the orientation will be set to `vertical`.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const LabelPosition = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup orientation="horizontalStart">\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-label"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n### Required\n\nSet the `required` prop of the wrapping `FormField` to `true` to indicate that the field is\nrequired. Labels for required fields are suffixed by a red asterisk.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Required = () => {\n const [value, setValue] = React.useState<string | number>(\'\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup isRequired={true}>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-required"\n onChange={handleChange}\n value={value}\n aria-describedby="choose-crust"\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n <FormFieldGroup.Hint>You must choose a crust</FormFieldGroup.Hint>\n </FormFieldGroup>\n );\n};\n```\n\n### Disabled\n\nSet the `disabled` prop of `RadioGroup.RadioButton` to prevent users from interacting with it. Be\ncareful not to disable a pre-selected radio button as this will block keyboard access to the entire\n`RadioGroup`.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Disabled = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n return (\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-disabled"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} disabled value="gluten-free">\n Gluten free (sold out)\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n### Custom Radio Button\n\nUse `RadioGroup.Label` instead of `RadioGroup.RadioButton` if you need direct access to the label\nand the radio input. This will allow you to apply custom styling to the text and radio input.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\nimport {Flex} from \'@workday/canvas-kit-react/layout\';\nimport {createStyles, px2rem} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst styleOverrides = {\n formfieldInputStyles: createStyles({\n width: px2rem(200),\n }),\n radioGroupLabelTextStyles: createStyles({\n color: system.color.fg.default,\n }),\n};\n\nexport const Custom = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Flex flexDirection="column">\n <FormFieldGroup>\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="pizza-crust-custom"\n onChange={handleChange}\n cs={styleOverrides.formfieldInputStyles}\n value={value}\n >\n <RadioGroup.Label>\n <FormFieldGroup.Input as={RadioGroup.Label.Input} value="deep-dish" />\n <RadioGroup.Label.Text cs={styleOverrides.radioGroupLabelTextStyles}>\n Deep dish\n </RadioGroup.Label.Text>\n </RadioGroup.Label>\n <RadioGroup.Label>\n <FormFieldGroup.Input as={RadioGroup.Label.Input} value="gluten-free" />\n <RadioGroup.Label.Text cs={styleOverrides.radioGroupLabelTextStyles}>\n Gluten free\n </RadioGroup.Label.Text>\n </RadioGroup.Label>\n <RadioGroup.Label>\n <FormFieldGroup.Input as={RadioGroup.Label.Input} value="cauliflower" />\n <RadioGroup.Label.Text cs={styleOverrides.radioGroupLabelTextStyles}>\n Cauliflower\n </RadioGroup.Label.Text>\n </RadioGroup.Label>\n </FormFieldGroup.List>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n Value selected: {value}\n </Flex>\n );\n};\n```\n\n### Standalone Radio Button\n\nUse `StyledRadioButton` when you want a styled radio button on its own without using `RadioGroup`.\nYou will need to handle behavior and accessibility.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {StyledRadioButton} from \'@workday/canvas-kit-preview-react/radio\';\nimport {Flex} from \'@workday/canvas-kit-react/layout\';\n\nexport const StandaloneRadio = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <Flex flexDirection="column">\n <FormFieldGroup as="fieldset">\n <FormFieldGroup.Label as="legend">Choose Your Pizza Crust</FormFieldGroup.Label>\n <Flex gap="m">\n <Flex as="label" gap="xs">\n <FormFieldGroup.Input\n as={StyledRadioButton}\n onChange={handleChange}\n value="deep-dish"\n name="pizza-crust-standalone"\n checked={value === \'deep-dish\'}\n />\n Deep dish\n </Flex>\n <Flex as="label" gap="xs">\n <FormFieldGroup.Input\n as={StyledRadioButton}\n onChange={handleChange}\n value="gluten-free"\n checked={value === \'gluten-free\'}\n name="pizza-crust-standalone"\n />\n Gluten free\n </Flex>\n </Flex>\n </FormFieldGroup>\n Value selected: {value}\n </Flex>\n );\n};\n```\n\nUse `RadioGroup.Label` when you want more control styling the text and radio input but still want\nsome behavior handled for you.\n\n### Error States\n\nSet the `error` prop of the wrapping `FormField` to `"caution"` or\n`"error"` to set the `RadioGroup` to the alert or error state, respectively. You\nwill also need to set the `hintId` and `hintText` props on the `FormField` to meet accessibility\nstandards. You must set an `aria-describedby` attribute on the `RadioGroup` element that matches the\nvalue of `hintId` set on the `FormField` element. These attributes ensure that the alert message is\nassociated to the `RadioGroup` and read out by voiceover.\n\n#### Caution\n\nUse the alert state when a selection is valid but there is additional information.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Caution = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <FormFieldGroup error="caution" id="hint-alert">\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-alert"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n <FormFieldGroup.Hint>Deep dish is an extra $2.99.</FormFieldGroup.Hint>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n#### Error\n\nUse the error state when the selection is no longer valid.\n```tsx\nimport React from \'react\';\nimport {FormFieldGroup} from \'@workday/canvas-kit-react/form-field\';\nimport {RadioGroup} from \'@workday/canvas-kit-preview-react/radio\';\n\nexport const Error = () => {\n const [value, setValue] = React.useState<string | number>(\'deep-dish\');\n\n const handleChange = (e: React.ChangeEvent) => {\n const target = e.currentTarget;\n if (target instanceof HTMLInputElement) {\n setValue(target.value);\n }\n };\n\n return (\n <FormFieldGroup error="error">\n <FormFieldGroup.Label>Choose Your Pizza Crust</FormFieldGroup.Label>\n <FormFieldGroup.Field>\n <FormFieldGroup.List\n as={RadioGroup}\n name="crust-error"\n onChange={handleChange}\n value={value}\n >\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="deep-dish">\n Deep dish\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="thin">\n Thin\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="gluten-free">\n Gluten free\n </FormFieldGroup.Input>\n <FormFieldGroup.Input as={RadioGroup.RadioButton} value="cauliflower">\n Cauliflower\n </FormFieldGroup.Input>\n </FormFieldGroup.List>\n <FormFieldGroup.Hint>Deep dish is currently sold out.</FormFieldGroup.Hint>\n </FormFieldGroup.Field>\n </FormFieldGroup>\n );\n};\n```\n\n### React Hook Form\n\nUsing a form library like [React Hook Form](https://www.react-hook-form.com/) is a common use case.\nReference this [CodeSandbox](https://codesandbox.io/s/radio-preview-with-react-hook-form-stn5vr) on\nhow to use `RadioGroup` with React Hook Form.\n\n### Custom Styles\n\nRadio and its subcomponents support custom styling via the `cs` prop. For more information, check\nour\n["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs).\n\n## Component API\n\n'
|
|
321
|
-
},
|
|
322
|
-
pill: {
|
|
323
|
-
title: "Preview/Pill",
|
|
324
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-pill--docs",
|
|
325
|
-
mdxPath: "modules/preview-react/pill/stories/Pill.mdx",
|
|
326
|
-
mdxProse: "# Canvas Kit Pill\n\n`Pill`s are static or interactive indicators that allow users to input, filter, or label\ninformation.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n`Pill`s are used to visually label objects on a page for quick recognition. They\u2019re offered as both\nstatic (read-only) and interactive elements. They allow users to filter a list or table, or label\ninformation to help with scanning and organization.\n\n### Basic Pills\n\nBy default a Pill is considered interactive. All leading elements (icons or avatars) are intended to\nbe descriptive, helping support the label. Do not rely on the leading element to indicate the\ninteraction behavior.\n\n#### Icon\n\nYou can render an icon inside the `Pill` with `Pill.Icon`. It will render a `plusIcon` by default,\nbut it can be customized by providing an icon to the `icon` prop. Because it uses `SystemIcon` under\nthe hood, you also have access to all `SystemIconProps`.\n\n#### Accessibility\n\nYou must provide an `aria-label` to the `Pill.Icon` for proper accessibility.\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\n\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const Basic = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill onClick={() => setText('The first pill is clicked!')}>\n <Pill.Icon aria-label=\"Add user\" />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n <Pill disabled>\n <Pill.Icon aria-label=\"Add user\" />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n#### Avatar\n\nYou can render an avatar image inside the `Pill` with `Pill.Avatar`. It should appear before the\n`Pill` text. Because it uses `Avatar` under the hood, you also have access to all `AvatarProps`.\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\n// @ts-ignore: Cannot find module error\nimport testAvatar from './test-avatar.png';\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithAvatar = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill onClick={() => setText('The first pill is clicked!')}>\n <Pill.Avatar name=\"Regina Skeltor\" url={testAvatar} />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n <Pill disabled>\n <Pill.Avatar name=\"Regina Skeltor\" />\n <Pill.Label>Regina Skeltor</Pill.Label>\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n#### Count\n\nThe count appears after the label. It is usually associated with the label. If you have a category,\nthe count will directly correlate to that category.\n```tsx\nimport React from 'react';\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithCount = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill onClick={() => setText('The first pill is clicked!')}>\n Shoes\n <Pill.Count>30</Pill.Count>\n </Pill>\n <Pill disabled>\n Shoes\n <Pill.Count>30</Pill.Count>\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n### Read Only\n\nThe `readOnly` variant is a non-interactive element that is used to display information.\n\nYou can define a read only `Pill` by providing a `variant='readOnly'` prop.\n```tsx\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithReadOnly = () => (\n <div className={flexStyles} id=\"read-only-list\">\n <Pill variant=\"readOnly\">Read-only</Pill>\n <Pill variant=\"readOnly\" maxWidth={150}>\n Read-only but with super long text in case you want to read a paragraph in a Pill which we\n don't recommend\n </Pill>\n </div>\n);\n```\n\n### Removable Pills\n\nRemovable `Pill`s display an `X` icon after the label. They have a smaller, more specific focus\nstate and click target to be more intentional about their actions and to avoid unintended removal.\n\nYou can define a removable `Pill` by providing a `variant='removable'` prop.\n\n```tsx\n<Pill variant=\"removable\">\n Pink Shirts\n <Pill.IconButton onClick={() => console.warn('clicked')} />\n</Pill>\n```\n\nIn this case, we use a `Pill.IconButton` because the `X` becomes the focusable and clickable\nelement.\n\nThe default icon for `Pill.IconButton` is `xSmallIcon` but this can also be overwritten by passing\nan `icon` prop to `Pill.IconButton`\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\n// @ts-ignore: Cannot find module error\nimport testAvatar from './test-avatar.png';\nimport {BodyText} from '@workday/canvas-kit-react/text';\nimport {system} from '@workday/canvas-tokens-web';\nimport {createStyles} from '@workday/canvas-kit-styling';\n\nconst flexStyles = createStyles({\n display: 'flex',\n gap: system.space.x2,\n});\n\nexport const WithRemovable = () => {\n const [text, setText] = React.useState('');\n return (\n <div>\n <div className={flexStyles}>\n <Pill variant=\"removable\">\n <Pill.Label>Pink Shirts</Pill.Label>\n <Pill.IconButton\n aria-label=\"Remove\"\n onClick={() => setText('The first pill is clicked!')}\n />\n </Pill>\n <Pill variant=\"removable\">\n <Pill.Avatar name=\"Avatar\" url={testAvatar} />\n <Pill.Label>Carolyn Grimaldi</Pill.Label>\n <Pill.IconButton\n aria-label=\"Remove\"\n onClick={() => setText('The second pill is clicked!')}\n />\n </Pill>\n <Pill variant=\"removable\" disabled>\n <Pill.Label>This is a category that should not exist because it is too long</Pill.Label>\n <Pill.IconButton aria-label=\"Remove\" />\n </Pill>\n </div>\n <BodyText size=\"medium\">{text}</BodyText>\n </div>\n );\n};\n```\n\n### List of Pills\n\n`Pill`s can often represent multiple pieces of information such as a filtered list of categories or\nskills.\n\nIn order to achieve this, use our `Flex` component to wrap each `Pill` and space them out\naccordingly.\n```tsx\nimport React from 'react';\n\nimport {Pill} from '@workday/canvas-kit-preview-react/pill';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst data = [\n 'Shoes',\n 'Pants',\n 'Dress Shoes',\n 'Color',\n 'Accessories',\n 'Luxury',\n 'Casual',\n 'Hats',\n 'Beanies',\n 'Glasses',\n 'Jewelry',\n];\n\nconst flexWrapStyles = createStyles({\n display: 'flex',\n flexWrap: 'wrap',\n gap: system.space.x2,\n});\n\nexport const WithList = () => {\n const [items, setItems] = React.useState(data);\n\n return (\n <div className={flexWrapStyles}>\n {items.map((cat, index) => {\n return (\n <Pill key={index} variant=\"removable\">\n <Pill.Label>{cat}</Pill.Label>\n <Pill.IconButton\n aria-label=\"Remove\"\n onClick={() => setItems(items.filter(i => i !== cat))}\n />\n </Pill>\n );\n })}\n </div>\n );\n};\n```\n\n### Custom Styles\n\n`Pill` supports custom styling via the `cs` prop. For more information, check our\n[\"How To Customize Styles\"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs)\nor view the example below.\n```tsx\nimport {Pill, pillCountStencil, pillStencil} from '@workday/canvas-kit-preview-react/pill';\n\nimport {createStencil} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\nimport {systemIconStencil} from '@workday/canvas-kit-react/icon';\n\nconst customPillStencil = createStencil({\n base: {\n [pillStencil.vars.background]: system.color.static.green.default,\n [pillStencil.vars.border]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.default,\n [pillCountStencil.vars.borderColor]: system.color.static.green.default,\n\n '&:hover, &.hover': {\n [pillStencil.vars.background]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.stronger,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.borderColor]: system.color.static.green.stronger,\n },\n '&:active, &.active': {\n [pillStencil.vars.background]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.stronger,\n },\n '&:focus, &.focus, &:focus-visible': {\n [pillStencil.vars.background]: system.color.static.green.stronger,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n [pillCountStencil.vars.backgroundColor]: system.color.static.green.stronger,\n },\n '&:disabled, &.disabled': {\n [pillStencil.vars.background]: system.color.static.green.default,\n [pillStencil.vars.label]: system.color.static.white,\n [systemIconStencil.vars.color]: system.color.static.white,\n },\n },\n});\n\nexport const CustomStyles = () => {\n return (\n <div>\n <Pill cs={customPillStencil()}>\n <Pill.Icon aria-label=\"Add user\" />\n <Pill.Label>Custom Pill Color</Pill.Label>\n <Pill.Count>10</Pill.Count>\n </Pill>\n </div>\n );\n};\n```\n\n## Component API\n\n"
|
|
327
|
-
},
|
|
328
|
-
multiselect: {
|
|
329
|
-
title: "Preview/MultiSelect",
|
|
330
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-multiselect--docs",
|
|
331
|
-
mdxPath: "modules/preview-react/multi-select/stories/MultiSelect.mdx",
|
|
332
|
-
mdxProse: "# Canvas Kit MultiSelect\n\nMultiSelect inputs allow users to choose multiple options from a list of items.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\n`MultiSelect` supports a\n[dynamic API](/get-started/for-developers/guides/collection-api/#dynamic-items) where you\npass an array of items via the `items` prop and provide a render function to display the items. The\nitems may be provided as an\n[array of strings](/get-started/for-developers/guides/collection-api/#array-of-strings) or an\n[array of objects](/get-started/for-developers/guides/collection-api/#array-of-objects).\n\n`MultiSelect` should be used in tandem with [Form Field](/components/inputs/form-field/) where the\n`MultiSelect` wraps the `FormField` element and the `FormField` element wraps the children of\n`MultiSelect` to meet accessibility standards. This ensures the `label` text from `FormField` is\nattached to the `MultiSelect.Input` and read out as a group for voiceover.\n\n```tsx\n<MultiSelect items={options}>\n <FormField label=\"Your Label\">\n <MultiSelect.Input onChange={e => handleChange(e)} id=\"contact-multi-select\" />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => <MultiSelect.Item>{item.id}</MultiSelect.Item>}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n</MultiSelect>\n```\n\n### Disabled Example\n\nDisabling `MultiSelect` involves passing the `disabled` prop to the `MultiSelect.Input` component.\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = ['Cheese', 'Olives', 'Onions', 'Pepperoni', 'Peppers'];\n\nexport const Disabled = () => {\n return (\n <>\n <MultiSelect items={items} initialSelectedIds={['Olives', 'Onions', 'Pepperoni']}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n disabled\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item}>\n <MultiSelect.Item.Text>{item}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </>\n );\n};\n```\n\n### Error States\n\nThe `MultiSelect.Input` and `MultiSelect.SearchInput` support the `ErrorType` from the Common\npackage. The error styling is identical to the `TextInput` error styling. The `error` prop is\ntypically passed from the `FormField` component.\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {MultiSelect, useMultiSelectModel} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = ['Cheese', 'Olives', 'Onions', 'Pepperoni', 'Peppers'];\n\nexport const Error = () => {\n const model = useMultiSelectModel({\n items,\n initialSelectedIds: [],\n });\n return (\n <>\n <MultiSelect model={model}>\n <FormField\n orientation=\"horizontalStart\"\n error={\n model.state.selectedIds.length < 1\n ? 'error'\n : model.state.selectedIds.length > 3\n ? 'caution'\n : undefined\n }\n >\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Field>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item}>\n <MultiSelect.Item.Text>{item}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n\n <FormField.Hint>\n {model.state.selectedIds.length < 1\n ? 'Select at least one topping.'\n : model.state.selectedIds.length > 3\n ? 'More than 3 toppings cost extra.'\n : undefined}\n </FormField.Hint>\n </FormField.Field>\n </FormField>\n </MultiSelect>\n </>\n );\n};\n```\n\n### Complex\n\nWhen registering items in an array of objects, it's common to have the text that is displayed to the\nuser be different than an id. In this example, `serverId` and `label` properties need to be remapped\nto `id` and `text` hence the usage of `getId` and `getTextValue`. If your object has the properties\n`text` and `id`, there would be no need for this.\n```tsx\nimport React from 'react';\n\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {FormField} from '@workday/canvas-kit-react/form-field';\n\nimport {system} from '@workday/canvas-tokens-web';\n\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst mainContentStyles = createStyles({\n padding: system.space.x4,\n});\n\nconst items = [\n {id: '1', text: 'Cheese'},\n {id: '2', text: 'Olives'},\n {id: '3', text: 'Onions'},\n {id: '4', text: 'Pepperoni'},\n {id: '5', text: 'Peppers'},\n];\n\nexport const Complex = () => {\n const [value, setValue] = React.useState('');\n const [label, setLabel] = React.useState('');\n return (\n <CanvasProvider>\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n >\n <main className={mainContentStyles}>\n <MultiSelect items={items} getId={i => i.id} getTextValue={i => i.text}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={e => {\n const value = e.currentTarget.value;\n setValue(value);\n setLabel(\n value\n .split(', ')\n .map(item => items.find(i => i.id === item)?.text || 'Not Found')\n .join(', ')\n );\n }}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </main>\n </form>\n <div>Selected IDs: {value}</div>\n <div>Selected Labels: {label}</div>\n </>\n </CanvasProvider>\n );\n};\n```\n\n### With Icons\n\nUse `MultiSelect.Item.Icon` to render an icon for a `MultiSelect.Item`. The `icon` prop for\n`MultiSelect.Item.Icon` accepts [system icons](/assets/system-icons/) from\n`@workday/canvas-system-icons-web`.\n\n> **Note: `data-id` on `MultiSelect.Item` must match the `id` property in your array of objects.\n> This ensures proper keyboard handling and type-ahead.**\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {\n mediaPauseIcon,\n mediaPlayIcon,\n mediaTopicsIcon,\n skipIcon,\n previousIcon,\n} from '@workday/canvas-system-icons-web';\n\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = [\n {id: '1', text: 'Pause', icon: mediaPauseIcon},\n {id: '2', text: 'Play', icon: mediaPlayIcon},\n {id: '3', text: 'Skip', icon: skipIcon},\n {id: '4', text: 'Previous', icon: previousIcon},\n];\n\nexport const Icons = () => {\n return (\n <MultiSelect items={items}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Controls</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Icon icon={item.icon} />\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n <MultiSelect.Item.Icon icon={mediaTopicsIcon} />\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n );\n};\n```\n\n### Controlled\n\nThe MultiSelect can be a controlled input component by passing the `value` and `onChange` to either\nthe `<MultiSelect>` component or the `<MultiSelect.Input>` component. Internally, the\n`MultiSelect.Input` watches for changes on the `value` React prop as well as the `value` DOM\nproperty and will update the model accordingly.\n```tsx\nimport React from 'react';\n\nimport {FormField} from '@workday/canvas-kit-react/form-field';\nimport {PrimaryButton, SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {Flex} from '@workday/canvas-kit-react/layout';\n\nimport {MultiSelect} from '@workday/canvas-kit-preview-react/multi-select';\n\nconst items = [\n {id: '1', text: 'Cheese'},\n {id: '2', text: 'Olives'},\n {id: '3', text: 'Onions'},\n {id: '4', text: 'Pepperoni'},\n {id: '5', text: 'Peppers'},\n];\n\nexport const Controlled = () => {\n const formRef = React.useRef<HTMLFormElement>(null);\n const [value, setValue] = React.useState('1');\n const [label, setLabel] = React.useState('Cheese');\n\n function handleOnChange(event: React.ChangeEvent<HTMLInputElement>) {\n const value = event.currentTarget.value;\n setValue(value);\n setLabel(\n value\n .split(', ')\n .map(item => items.find(i => i.id === item)?.text || 'Not Found')\n .join(', ')\n );\n }\n\n return (\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n ref={formRef}\n >\n <Flex gap=\"s\" flexDirection=\"column\">\n <MultiSelect items={items}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Toppings</FormField.Label>\n <FormField.Input\n as={MultiSelect.Input}\n placeholder=\"Select Multiple\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={handleOnChange}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n <MultiSelect.List>\n {item => (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n )}\n </MultiSelect.List>\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n <Flex gap=\"s\">\n <SecondaryButton\n onClick={e => {\n setValue('1, 2, 3');\n }}\n >\n Set to \"Cheese, Olives, Onions\" via React `value`\n </SecondaryButton>\n <SecondaryButton\n onClick={e => {\n const input = formRef.current.querySelector('[name=toppings]') as HTMLInputElement;\n input.value = '1, 2';\n }}\n >\n Set to \"Cheese, Olives\" via DOM `value`\n </SecondaryButton>\n </Flex>\n <div>\n <PrimaryButton type=\"submit\">Submit</PrimaryButton>\n </div>\n <div>Selected ID: {value}</div>\n <div>Selected Label: {label}</div>\n </Flex>\n </form>\n </>\n );\n};\n```\n\n### Searching\n\nA MultiSelect input can be used as a filter for results. Most likely this also means there are many\nitems that may not be all be loaded from the server at once. The `useComboboxLoader` can be used to\ndynamically load items as the user navigates the available options.\n\n> **Note:** The behavior of search is experimental. The example should continue to work without\n> modification, but how the searchable input is presented to the user may change with user testing.\n> Don't rely too much on the exact behavior of the search input. For example, the search input may\n> be cleared when the user blurs the field.\n```tsx\nimport React from 'react';\n\nimport {system} from '@workday/canvas-tokens-web';\n\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {LoadReturn} from '@workday/canvas-kit-react/collection';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {useComboboxLoader} from '@workday/canvas-kit-react/combobox';\nimport {FormField} from '@workday/canvas-kit-react/form-field';\n\nimport {MultiSelect, useMultiSelectModel} from '@workday/canvas-kit-preview-react/multi-select';\nimport {StyledMenuItem} from '@workday/canvas-kit-react/menu';\n\nconst mainContentStyles = createStyles({\n padding: system.space.x4,\n});\n\nconst colors = ['Red', 'Blue', 'Purple', 'Green', 'Pink'];\nconst fruits = ['Apple', 'Orange', 'Banana', 'Grape', 'Lemon', 'Lime'];\nconst options = Array(1000)\n .fill('')\n .map((_, index) => {\n return {\n id: `${index + 1}`,\n text: `${colors[index % colors.length]} ${fruits[index % fruits.length]} ${index + 1}`,\n };\n });\n\nexport const Searching = () => {\n const [value, setValue] = React.useState('');\n\n const {model, loader} = useComboboxLoader(\n {\n // You can start with any number that makes sense.\n total: 0,\n\n // Pick whatever number makes sense for your API\n pageSize: 20,\n\n // A load function that will be called by the loader. You must return a promise that returns\n // an object like `{items: [], total: 0}`. The `items` will be merged into the loader's cache\n async load({pageNumber, pageSize, filter}) {\n return new Promise<LoadReturn<(typeof options)[0]>>(resolve => {\n // simulate a server response by resolving after a period of time\n setTimeout(() => {\n // simulate paging and filtering based on pre-computed items\n const start = (pageNumber - 1) * pageSize;\n const end = start + pageSize;\n const filteredItems = options.filter(item => {\n if (filter === '' || typeof filter !== 'string') {\n return true;\n }\n return item.text.toLowerCase().includes(filter.toLowerCase());\n });\n\n const total = filteredItems.length;\n const items = filteredItems.slice(start, end);\n\n resolve({\n items,\n total,\n });\n }, 300);\n });\n },\n onShow() {\n // The `shouldLoad` cancels while the combobox menu is hidden, so let's load when it is\n // visible\n loader.load();\n },\n },\n useMultiSelectModel\n );\n\n return (\n <CanvasProvider>\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n >\n <main className={mainContentStyles}>\n <MultiSelect model={model}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Fruits</FormField.Label>\n <FormField.Input\n as={MultiSelect.SearchInput}\n placeholder=\"Search\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={e => {\n setValue(e.currentTarget.value);\n }}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n {model.state.items.length === 0 && (\n <StyledMenuItem as=\"span\">No Results Found</StyledMenuItem>\n )}\n {model.state.items.length > 0 && (\n <MultiSelect.List maxHeight={200}>\n {item =>\n item ? (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n ) : undefined\n }\n </MultiSelect.List>\n )}\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </main>\n </form>\n <div>Selected: {value}</div>\n </>\n </CanvasProvider>\n );\n};\n```\n\n### Initial Selected Items\n\nYou can set `initialSelectedIds` to the value that you want initially selected.\n```tsx\nimport React, {useEffect} from 'react';\n\nimport {system} from '@workday/canvas-tokens-web';\n\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {LoadReturn} from '@workday/canvas-kit-react/collection';\nimport {CanvasProvider, useMountLayout} from '@workday/canvas-kit-react/common';\nimport {useComboboxLoader} from '@workday/canvas-kit-react/combobox';\nimport {FormField} from '@workday/canvas-kit-react/form-field';\n\nimport {MultiSelect, useMultiSelectModel} from '@workday/canvas-kit-preview-react/multi-select';\nimport {StyledMenuItem} from '@workday/canvas-kit-react/menu';\n\nconst mainContentStyles = createStyles({\n padding: system.space.x4,\n});\n\nconst colors = ['Red', 'Blue', 'Purple', 'Green', 'Pink'];\nconst fruits = ['Apple', 'Orange', 'Banana', 'Grape', 'Lemon', 'Lime'];\nconst options = Array(1000)\n .fill('')\n .map((_, index) => {\n return {\n id: `${index + 1}`,\n text: `${colors[index % colors.length]} ${fruits[index % fruits.length]} ${index + 1}`,\n };\n });\n\nexport const InitialSelectedItems = () => {\n const [value, setValue] = React.useState('');\n\n const {model, loader} = useComboboxLoader(\n {\n // You can start with any number that makes sense.\n total: 0,\n initialSelectedIds: ['3', '5'],\n\n // Pick whatever number makes sense for your API\n pageSize: 500,\n\n // A load function that will be called by the loader. You must return a promise that returns\n // an object like `{items: [], total: 0}`. The `items` will be merged into the loader's cache\n async load({pageNumber, pageSize, filter}) {\n return new Promise<LoadReturn<(typeof options)[0]>>(resolve => {\n // simulate a server response by resolving after a period of time\n setTimeout(() => {\n // simulate paging and filtering based on pre-computed items\n const start = (pageNumber - 1) * pageSize;\n const end = start + pageSize;\n const filteredItems = options.filter(item => {\n if (filter === '' || typeof filter !== 'string') {\n return true;\n }\n return item.text.toLowerCase().includes(filter.toLowerCase());\n });\n\n const total = filteredItems.length;\n const items = filteredItems.slice(start, end);\n\n resolve({\n items,\n total,\n });\n }, 300);\n });\n },\n onShow() {\n // The `shouldLoad` cancels while the combobox menu is hidden, so let's load when it is\n // visible\n loader.load();\n },\n },\n useMultiSelectModel\n );\n\n useEffect(() => {\n loader.load();\n }, [loader]);\n\n return (\n <CanvasProvider>\n <>\n <form\n onSubmit={e => {\n console.log('form submitted');\n e.preventDefault();\n }}\n >\n <main className={mainContentStyles}>\n <MultiSelect model={model}>\n <FormField orientation=\"horizontalStart\">\n <FormField.Label>Fruits</FormField.Label>\n <FormField.Input\n as={MultiSelect.SearchInput}\n placeholder=\"Search\"\n removeLabel=\"Remove\"\n name=\"toppings\"\n onChange={e => {\n setValue(e.currentTarget.value);\n }}\n value={value}\n />\n <MultiSelect.Popper>\n <MultiSelect.Card>\n {model.state.items.length === 0 && (\n <StyledMenuItem as=\"span\">No Results Found</StyledMenuItem>\n )}\n {model.state.items.length > 0 && (\n <MultiSelect.List maxHeight={200}>\n {item =>\n item ? (\n <MultiSelect.Item data-id={item.id}>\n <MultiSelect.Item.Text>{item.text}</MultiSelect.Item.Text>\n </MultiSelect.Item>\n ) : undefined\n }\n </MultiSelect.List>\n )}\n </MultiSelect.Card>\n </MultiSelect.Popper>\n </FormField>\n </MultiSelect>\n </main>\n </form>\n <div>Selected: {value}</div>\n </>\n </CanvasProvider>\n );\n};\n```\n"
|
|
333
|
-
},
|
|
334
|
-
"loading-sparkles-(ai)": {
|
|
335
|
-
title: "Preview/Loading Sparkles (AI)",
|
|
336
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-loading-sparkles-(ai)--docs",
|
|
337
|
-
mdxPath: "modules/preview-react/loading-sparkles/stories/LoadingSparkles.mdx",
|
|
338
|
-
mdxProse: "# Canvas Kit Loading Sparkles\n\n`LoadingSparkles` is a loading animation that makes users aware an AI operation is in progress.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-react\n```\n\n## Usage\n\n### Basic Example\n\n`LoadingSparkles` is designed to work out-of-the-box, but you'll need to add some wiring for screen\nreaders. In the example below, we're simulating a loading state with a `setTimeout` that's triggered\nwhen the \"Generate Quote\" button is clicked.\n\nThe ARIA live region uses the `aria-label` on `LoadingSparkles` to announce the loading state. And\nit uses the text in `AccessibleHide` to announce when loading is complete. In a real-world\napplication, you would probably add another state for loading failures. Also note that generated\ntext should live outside the live region. This content doesn't need to be announced to screen\nreaders.\n\n#### Consolidating ARIA Live Regions\n\nIn the example, we wrapped `LoadingSparkles` inside our `AriaLiveRegion` component, but in general\nyou should not have multiple ARIA live regions on the page at once. If you already have a live\nregion, consider sending these loading messages there instead of adding another region.\n```tsx\nimport React from 'react';\nimport {SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {LoadingSparkles} from '@workday/canvas-kit-preview-react/loading-sparkles';\nimport {AccessibleHide, AriaLiveRegion} from '@workday/canvas-kit-react/common';\nimport {createStyles} from '@workday/canvas-kit-styling';\n\nconst containerStyles = createStyles({\n minHeight: '3.5rem',\n display: 'flex',\n flexDirection: 'column',\n gap: '0.5rem',\n});\n\nexport const Basic = () => {\n const [loadingStatus, setLoadingStatus] = React.useState<'idle' | 'loading' | 'success'>('idle');\n const [quote, setQuote] = React.useState('');\n\n React.useEffect(() => {\n if (loadingStatus === 'loading') {\n const mockLoading = setTimeout(() => {\n setLoadingStatus('success');\n setQuote(getQuote());\n }, 3000);\n\n return () => {\n clearTimeout(mockLoading);\n };\n }\n }, [loadingStatus]);\n\n const handleClick = () => {\n setQuote('');\n setLoadingStatus('loading');\n };\n\n return (\n <div>\n <div className={containerStyles}>\n {quote && <Text cs={{maxWidth: '60ch'}}>{quote}</Text>}\n <AriaLiveRegion>\n {loadingStatus === 'loading' && <LoadingSparkles aria-label=\"loading\" />}\n {loadingStatus === 'success' && (\n <AccessibleHide role=\"status\">loading complete</AccessibleHide>\n )}\n </AriaLiveRegion>\n </div>\n <SecondaryButton onClick={handleClick}>Generate Quote</SecondaryButton>\n </div>\n );\n};\n\nconst robotQuotes = [\n 'The Zeroth Law: A robot may not harm humanity, or, by inaction, allow humanity to come to harm.',\n 'Law 1: A robot may not injure a human being or, through inaction, allow a human being to come to harm.',\n 'Law 2: A robot must obey the orders given it by human beings except where such orders would conflict with the First Law.',\n 'Law 3: A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.',\n 'There is nothing so eternally adhesive as the memory of power.',\n];\n\nconst getQuote = () => {\n const index = Math.floor(Math.random() * robotQuotes.length);\n return robotQuotes[index];\n};\n```\n\n### Right-to-Left (RTL)\n```tsx\nimport React from 'react';\nimport {LoadingSparkles} from '@workday/canvas-kit-preview-react/loading-sparkles';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\n\nexport const RTL = () => {\n return (\n <CanvasProvider dir=\"rtl\">\n <LoadingSparkles />\n </CanvasProvider>\n );\n};\n```\n\n## Component API\n\n"
|
|
339
|
-
},
|
|
340
|
-
"information-highlight": {
|
|
341
|
-
title: "Preview/Information Highlight",
|
|
342
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-information-highlight--docs",
|
|
343
|
-
mdxPath: "modules/preview-react/information-highlight/stories/InformationHighlight.mdx",
|
|
344
|
-
mdxProse: "# Canvas Kit Information Highlight\n\nA container to call out important information on a page or a section of a page that the user should\nbe aware of.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n`InformationHighlight` should be used to call out important information to the user and are paired\nwith a meaningful icon and color to differentiate information type. It should not be removed from\nthe interface until some system or admin level action has been taken to do so.\n\nYou can use an `InformationHighlight` to:\n\n- Prevent unwanted consequences from destructive actions\n- Reassure users in their next steps\n- Provide detail into information on the page\n- Show changes in page content\n\n### When to Consider Something Else\n\n- Consider a\n [Banner](https://workday.github.io/canvas-kit/?path=/docs/components-indicators-banner--docs) if\n the message is about system-wide errors or alerts, or if the message appears in response to user\n action.\n- Consider a\n [Dialog](https://workday.github.io/canvas-kit/?path=/docs/components-popups-dialog--docs) if the\n message is critical and requires user action or decision before proceeding\n- Consider a [Toast](https://workday.github.io/canvas-kit/?path=/docs/components-popups-toast--docs)\n if the message is timely, such as communicating updates on the process of an application.\n\n### Basic Example\n```tsx\nimport React from 'react';\n\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\n\nexport const Basic = () => {\n return (\n <InformationHighlight>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>Information Highlight</InformationHighlight.Heading>\n <InformationHighlight.Body>\n {' '}\n This is what an information highlight would look like with with the default settings and\n every field filled in{' '}\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n );\n};\n```\n\n## Variants\n\n`InformationHighlight` has three variants and each `variant` has two types of `emphasis`.\n\nVariants: `informational`, `caution`, `critical`\n\nEmphasis: `low`, `high`\n\nThe variants have different icons and colors to convey severity and the emphasis changes the\nbackground color to have a lower or higher contrast. If no `variant` or `emphasis` is selected the\nlayout will default to `Variant: informational, Emphasis: low`.\n\nThe following examples will show the `low` and `high` emphasis of the three variants. `low` Emphasis\nwill be shown first and should be used when there is other more important information on the page.\n`high` Emphasis will be shown second, and should be used when the highlight is not competing with\nother, more important information.\n\n### Informational\n\nThe informational variant is for _nice to have_ information, such as related features or\nopportunities.\n```tsx\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {system} from '@workday/canvas-tokens-web';\nimport {createStyles} from '@workday/canvas-kit-styling';\n\nconst contentTextStyles = createStyles({\n margin: 0,\n});\n\nconst contentListStyles = createStyles({\n listStyle: 'inside',\n marginInlineStart: 0,\n marginBlockStart: system.space.x2,\n marginBlockEnd: 0,\n padding: 0,\n});\n\nexport const Informational = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <InformationHighlight variant={'informational'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Informational Highlight </InformationHighlight.Heading>\n <InformationHighlight.Body>\n <p className={contentTextStyles}>\n This is a low-emphasis, informational callout. You should use this for nice-to-have\n information, such as:\n </p>\n <ul className={contentListStyles}>\n <li>tangential information or context</li>\n <li>related features</li>\n <li>additional opportunities</li>\n </ul>\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">Learn More</InformationHighlight.Link>\n </InformationHighlight>\n <InformationHighlight variant={'informational'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Informational Highlight </InformationHighlight.Heading>\n <InformationHighlight.Body>\n <p className={contentTextStyles}>\n This is a high-emphasis, informational callout. You should use this for nice-to-have\n information, such as:\n </p>\n <ul className={contentListStyles}>\n <li>tangential information or context</li>\n <li>related features</li>\n <li>additional opportunities</li>\n </ul>\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">Learn More</InformationHighlight.Link>\n </InformationHighlight>\n </Flex>\n );\n};\n```\n\n### Caution\n\nThe caution variant is for _important to know_ information, such as the potential consequences of\nspecific actions.\n```tsx\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {system} from '@workday/canvas-tokens-web';\n\nexport const Caution = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <InformationHighlight variant={'caution'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Caution: Highlight Something </InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below, nothing will happen\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n <InformationHighlight variant={'caution'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading> Caution: Highlight Something </InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below, nothing will happen\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n </Flex>\n );\n};\n```\n\n### Critical\n\nThe critical variant is for _must know_ information that could otherwise cause failure if the user\nis unaware\n```tsx\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {system} from '@workday/canvas-tokens-web';\n\nexport const Critical = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <InformationHighlight variant={'critical'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>Attention! Highlight Something</InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below it will reroute you back to this page.\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n <InformationHighlight variant={'critical'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>Attention! Highlight Something</InformationHighlight.Heading>\n <InformationHighlight.Body>\n If you select the link below it will reroute you back to this page.\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">View the Docs</InformationHighlight.Link>\n </InformationHighlight>\n </Flex>\n );\n};\n```\n\n### RTL Example\n\nInformation Highlight also supports RTL Languages. To enable RTL, set the `dir` attribute on the\nparent dom element that renders your application.\n```tsx\nimport React from 'react';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {system} from '@workday/canvas-tokens-web';\nexport const RTL = () => {\n return (\n <Flex flexDirection={'column'} gap={system.space.x2}>\n <CanvasProvider dir=\"rtl\">\n <InformationHighlight variant={'caution'} emphasis={'low'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>\n {' '}\n \u0627\u0646\u062A\u0628\u0627\u0647! \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631{' '}\n </InformationHighlight.Heading>\n <InformationHighlight.Body>\n \u0646\u062D\u0646 \u0646\u062F\u0639\u0645 \u0627\u0644\u0644\u063A\u0627\u062A \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">\u0648\u062B\u0627\u0626\u0642</InformationHighlight.Link>\n </InformationHighlight>\n </CanvasProvider>\n <CanvasProvider dir=\"rtl\">\n <InformationHighlight variant={'caution'} emphasis={'high'}>\n <InformationHighlight.Icon />\n <InformationHighlight.Heading>\n {' '}\n \u0627\u0646\u062A\u0628\u0627\u0647! \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631{' '}\n </InformationHighlight.Heading>\n <InformationHighlight.Body>\n \u0646\u062D\u0646 \u0646\u062F\u0639\u0645 \u0627\u0644\u0644\u063A\u0627\u062A \u0645\u0646 \u0627\u0644\u064A\u0645\u064A\u0646 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631\n </InformationHighlight.Body>\n <InformationHighlight.Link href=\"#hyperlink\">\u0648\u062B\u0627\u0626\u0642</InformationHighlight.Link>\n </InformationHighlight>\n </CanvasProvider>\n </Flex>\n );\n};\n```\n\n## Partial and Custom Information Highlights\n\n`InformationHighlight` can use custom icons or be designed to only use some of its components.\n\n### Custom Icon: Critical\n\n### Body Only Example\n```tsx\nimport React from 'react';\n\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\n\nexport const Body = () => {\n return (\n <InformationHighlight>\n <InformationHighlight.Body>\n Only the body of an information highlight\n </InformationHighlight.Body>\n </InformationHighlight>\n );\n};\n```\n\n### Heading Only Example\n```tsx\nimport React from 'react';\n\nimport {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';\n\nexport const Heading = () => {\n return (\n <InformationHighlight>\n <InformationHighlight.Heading> Only Heading </InformationHighlight.Heading>\n </InformationHighlight>\n );\n};\n```\n\n### Accessible Use of the `as` Prop\n\nLike many of our components, `InformationHighlight` and it's subcomponents accept an `as` prop,\nwhich lets you change the underlying semantic element. For `InformationHighlight.Heading`, you can\nchange the heading level if you were needing to define a different level of importance. This should\nbe done with caution to ensure the best accessibility.\n\n## Component API\n\n## Specifications\n\n"
|
|
345
|
-
},
|
|
346
|
-
divider: {
|
|
347
|
-
title: "Preview/Divider",
|
|
348
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-divider--docs",
|
|
349
|
-
mdxPath: "modules/preview-react/divider/stories/Divider.mdx",
|
|
350
|
-
mdxProse: "# Divider\n\nA `Divider` segments and visually organizes content.\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\nUse a `Divider` to separate content and create visual hierarchy. Typically they are used between\nparagraph sections to indicate a break or shift in content. However, they can also be used as\ndecorative elements to provide greater emphasis and visual hierarchy.\n\n### Basic Example\n\nBy default, `Divider` renders a `<hr>` (horizontal rule) element with `0.5rem` of margin on top and\nbottom. The `space` prop allows you to adjust the vertical margin evenly. In the example below, the\n`Divider`s provide a subtle deliniation between each profile card without being as visually\nprominent as a `Card`. The `space` is adjusted to `0.25rem` which applied `0.125rem` to the top and\nbottom margin.\n```tsx\nimport React from 'react';\nimport {Divider} from '@workday/canvas-kit-preview-react/divider';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\nimport {Avatar} from '@workday/canvas-kit-react/avatar';\n\nconst sectionStyles = createStyles({\n display: 'flex',\n flexDirection: 'column',\n gap: system.space.x4,\n maxWidth: '40rem',\n});\n\nexport const Basic = () => {\n const lastIndex = maintainerList.length - 1;\n return (\n <section className={sectionStyles}>\n {maintainerList.map((maintainerData, index) => (\n <>\n <ProfileCard {...maintainerData} />\n {index !== lastIndex && <Divider space={system.space.x1} />}\n </>\n ))}\n </section>\n );\n};\n\nconst maintainerList = [\n {\n id: '44883293',\n name: 'Josh Bagwell',\n bio: 'Software Development Engineer',\n },\n {\n id: '338257',\n name: 'Nicholas Boll',\n bio: 'Principal Software Development Engineer',\n },\n {\n id: '7966550',\n name: 'Manuel Carrera',\n bio: 'Sr. Software Development Engineer',\n },\n {\n id: '146020',\n name: 'James Fan',\n bio: 'Sr. Software Development Engineer',\n },\n {\n id: '48605821',\n name: 'Raisa Primerova',\n bio: 'Software Development Engineer',\n },\n {\n id: '4818182',\n name: 'Alan Smith',\n bio: 'Principal Software Development Engineer',\n },\n];\n\nconst profileCardStyles = createStyles({\n display: 'grid',\n gridGap: '0.5rem',\n gridTemplateColumns: '5rem 1fr',\n gridTemplateRows: '1fr 1fr',\n});\n\nconst profileCardAvatarStyles = createStyles({\n gridColumn: '1',\n gridRow: '1 / 3',\n});\n\nconst profileCardHeadingStyles = createStyles({\n ...system.type.body.large,\n fontWeight: system.fontWeight.bold,\n gridColumn: '2/3',\n gridRow: '1',\n margin: 0,\n});\n\nconst profileCardBodyStyles = createStyles({\n ...system.type.body.small,\n gridColumn: '2',\n gridRow: '2',\n margin: 0,\n});\n\ninterface ProfileCardProps {\n id: string;\n name: string;\n bio: string;\n}\n\nconst ProfileCard = ({id, name, bio}: ProfileCardProps) => (\n <div className={profileCardStyles}>\n <Avatar\n size=\"extraLarge\"\n url={`https://avatars.githubusercontent.com/u/${id}?v=4`}\n altText={`${name}'s avatar`}\n className={profileCardAvatarStyles}\n />\n <h3 className={profileCardHeadingStyles}>{name}</h3>\n <p className={profileCardBodyStyles}>{bio}</p>\n </div>\n);\n```\n\n### Custom Space\n\nYou might also want to apply custom space to `Divider` where the top and bottom margin are not\nequal. The best way to achieve this is with `createStyles` and the `cs` property. In the example\nbelow, the `Divider` is applied as a decorative element to add emphasis to the section heading.\nCustom styles are defined in the `createStyles` function outside the component and are passed to\n`Divider`'s `cs` prop. These styles remove the top margin and set the bottom margin to `1rem`.\n```tsx\nimport React from 'react';\nimport {Divider} from '@workday/canvas-kit-preview-react/divider';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst headingStyles = createStyles({\n ...system.type.body.large,\n fontWeight: system.fontWeight.bold,\n margin: 0,\n});\n\nconst bodyStyles = createStyles({\n ...system.type.body.small,\n margin: 0,\n});\n\nconst customDividerSpace = createStyles({\n margin: `0 0 ${system.space.x4}`,\n});\n\nexport const CustomSpace = () => {\n return (\n <section>\n <h3 className={headingStyles}>Quote of the Day</h3>\n <Divider cs={customDividerSpace} />\n <p className={bodyStyles}>\n \"It is not our differences that divide us. It is our inability to recognize, accept, and\n celebrate those differences.\" \u2013 Audre Lorde\n </p>\n </section>\n );\n};\n```\n\n## Component API\n\n"
|
|
351
|
-
},
|
|
352
|
-
avatar: {
|
|
353
|
-
title: "Preview/Avatar",
|
|
354
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/preview-avatar--docs",
|
|
355
|
-
mdxPath: "modules/preview-react/avatar/stories/Avatar.mdx",
|
|
356
|
-
mdxProse: '# Avatar\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-preview-react\n```\n\n## Usage\n\n### Basic Example\n\nThe most basic usage requires only a `name` prop. The component automatically extracts and displays\nthe initials. If you want to display a different set of initials, you can use the `preferredInitials` prop.\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\n\nexport const Basic = () => {\n return <Avatar name="John Doe" />;\n};\n```\n\n### Image Avatar\n\nYou can display a profile image by providing the `url` prop.\n\n> Note: The `url` and the `name` prop is required for the image avatar. The `name` is used for the `alt` attribute on the image.\n\n#### Image Fallback Behavior\n\nThe Avatar component includes intelligent fallback handling:\n\n- While the image loads, the user\'s initials are displayed using the `name` prop\n- If the image fails to load, initials remain visible\n- The `name` prop serves as both the alt text and fallback content\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\n\nexport const Image = () => {\n return (\n <Avatar\n name="Happy Doggo"\n url={\'https://picsum.photos/id/237/300/200\'}\n objectFit="cover"\n size="medium"\n />\n );\n};\n```\n\n### Sizes\n\nThe Avatar component supports the following sizes:\n- `extraExtraSmall` is 24px x 24px\n- `extraSmall` is 32px x 32px\n- `small` is 40px x 40px\n- `medium` is 48px x 48px\n- `large` is 72px x 72px\n- `extraLarge` is 96px x 96px\n- `extraExtraLarge` is 120px x 120px\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst containerStyles = createStyles({\n display: \'inline-flex\',\n gap: system.space.x2,\n});\n\nexport const Size = () => {\n return (\n <div className={containerStyles}>\n <Avatar name="John Doe" size="extraExtraSmall" />\n <Avatar name="Logan McNeil" size="extraSmall" />\n <Avatar name="Wonder Woman" size="small" />\n <Avatar name="Iron Man" size="medium" />\n <Avatar name="Peter Parker" size="large" />\n <Avatar name="Bruce Banner" size="extraLarge" />\n <Avatar name="Elektra" size="extraExtraLarge" />\n </div>\n );\n};\n```\n\n### Variants\n\nChoose from four predefined color schemes:\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {system} from \'@workday/canvas-tokens-web\';\n\nconst containerStyles = createStyles({\n display: \'inline-flex\',\n gap: system.space.x2,\n});\n\nexport const Variant = () => {\n return (\n <div className={containerStyles}>\n <Avatar name="John Doe" variant="blue" />\n <Avatar name="Logan McNeil" variant="amber" />\n <Avatar name="Wonder Woman" variant="teal" />\n <Avatar name="Elektra" variant="purple" />\n </div>\n );\n};\n```\n\n### Advanced Custom Component\n\nFor complete control over styling and behavior, use the `BaseAvatar` component:\n```tsx\nimport {BaseAvatar} from \'@workday/canvas-kit-preview-react/avatar\';\nimport {createStyles, px2rem} from \'@workday/canvas-kit-styling\';\nimport {base} from \'@workday/canvas-tokens-web\';\n\nconst customStyles = createStyles({\n cursor: \'pointer\',\n backgroundColor: base.magenta300,\n color: base.magenta700,\n borderRadius: \'50%\',\n border: \'none\',\n padding: \'0\',\n margin: \'0\',\n display: \'flex\',\n alignItems: \'center\',\n span: {\n cursor: \'pointer\',\n },\n});\n\nexport const Custom = () => {\n return (\n <BaseAvatar\n size={px2rem(56)}\n cs={customStyles}\n as="button"\n onClick={() => console.log(\'clicked\')}\n >\n <BaseAvatar.Name name="John Doe Jane" />\n </BaseAvatar>\n );\n};\n```\n\n### Accessibility\nIf the Avatar is purely decorative, you can set the `isDecorative` prop to `true` to prevent the `name` prop from being forwarded to the `alt` attribute of the image.\n```tsx\nimport {Avatar} from \'@workday/canvas-kit-preview-react/avatar\';\n// @ts-ignore\nimport nicholasAvatar from \'./nicholas-avatar.jpg\';\nimport {createStyles} from \'@workday/canvas-kit-styling\';\nimport {Text} from \'@workday/canvas-kit-react/text\';\nimport {system} from \'@workday/canvas-tokens-web\';\nconst containerStyles = createStyles({\n display: \'inline-flex\',\n gap: system.space.x2,\n alignItems: \'center\',\n});\nexport const Decorative = () => {\n return (\n <div className={containerStyles}>\n <Avatar\n name="Nicholas Smith"\n isDecorative\n url={nicholasAvatar}\n objectFit="cover"\n size="small"\n />\n <Text>Nicholas Smith</Text>\n </div>\n );\n};\n```\n\n## Component API\n\n'
|
|
357
|
-
},
|
|
358
|
-
"side-panel-(new)": {
|
|
359
|
-
title: "Labs/Side Panel (New)",
|
|
360
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/labs-side-panel-(new)--docs",
|
|
361
|
-
mdxPath: "modules/labs-react/side-panel/stories/SidePanel.mdx",
|
|
362
|
-
mdxProse: "# Canvas Kit Side Panel <StorybookStatusIndicator type=\"new\" />\n\n`SidePanel` is a collapsible container that anchors to the left or right side of the screen. It uses\nthe model pattern for state management and is fully accessible.\n\n[> Workday Design Reference](https://design.workday.com/components/containers/side-panel)\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-labs-react\n```\n\n## Migrating from Preview\n\nIf you're migrating from `@workday/canvas-kit-preview-react/side-panel`, here are the key API\nchanges:\n\n### Import Changes\n\n```tsx\n// Before (preview-react)\n\n// After (labs-react)\n```\n\n### Hook API Changes\n\n| Preview (`useSidePanel`) | Labs (`useSidePanelModel`) |\n| -------------------------------- | ------------------------------------------------------- |\n| `initialExpanded: boolean` | `initialTransitionState: 'expanded' \\| 'collapsed'` |\n| `origin: 'left' \\| 'right'` | `origin: 'start' \\| 'end'` |\n| Returns `expanded: boolean` | Returns `model.state.transitionState` |\n| Returns `setExpanded(bool)` | Use `model.events.expand()` / `model.events.collapse()` |\n| Returns `panelProps` to spread | Props applied automatically via `elemPropsHook` |\n| Returns `labelProps` to spread | Use `id={model.state.labelId}` on label element |\n| Returns `controlProps` to spread | Props applied automatically to `SidePanel.ToggleButton` |\n\n### Component API Changes\n\n| Preview | Labs |\n| ---------------------------------------------- | ------------------------------------------------- |\n| `<SidePanel {...panelProps}>` | `<SidePanel model={model}>` or just `<SidePanel>` |\n| `<SidePanel.ToggleButton {...controlProps} />` | `<SidePanel.ToggleButton />` |\n| `<Heading {...labelProps}>` | `<Heading id={model.state.labelId}>` |\n| `expanded` prop on SidePanel | Managed by model's `transitionState` |\n| `touched` prop on SidePanel | Managed internally |\n| `onExpandedChange` callback | Use `onStateTransition` and derive expanded state |\n| `onStateTransition` on component | `onStateTransition` on model config |\n\n### Code Migration Example\n\n```tsx\n// Before (preview-react)\nconst {expanded, panelProps, labelProps, controlProps} = useSidePanel({\n initialExpanded: false,\n});\n\n<SidePanel {...panelProps} origin=\"right\" onExpandedChange={exp => console.log(exp)}>\n <SidePanel.ToggleButton {...controlProps} />\n <Heading {...labelProps}>Panel Title</Heading>\n {expanded && <Content />}\n</SidePanel>;\n\n// After (labs-react)\nconst model = useSidePanelModel({\n initialTransitionState: 'collapsed',\n origin: 'end',\n onStateTransition: state => {\n const isExpanded = state === 'expanded' || state === 'expanding';\n console.log(isExpanded);\n },\n});\n\n<SidePanel model={model}>\n <SidePanel.ToggleButton />\n <Heading id={model.state.labelId}>Panel Title</Heading>\n {model.state.transitionState === 'expanded' && <Content />}\n</SidePanel>;\n```\n\n### Checking Expanded State\n\n```tsx\n// Before (preview-react)\nif (expanded) {\n /* ... */\n}\n\n// After (labs-react) - for exact state\nif (model.state.transitionState === 'expanded') {\n /* ... */\n}\n\n// After (labs-react) - including animation states\nconst isExpanded =\n model.state.transitionState === 'expanded' || model.state.transitionState === 'expanding';\n```\n\n## Usage\n\n### Basic Example\n\n`SidePanel` is composed of three parts:\n\n- The panel container (with an optional `model` prop)\n- A heading (`SidePanel.Heading`) for the panel that is visually hidden when the panel is collapsed\n- A toggle button (`SidePanel.ToggleButton`) to control the expand / collapse states\n\nBidirectional support is built into `SidePanel`. As seen in the example below, CSS Flexbox flips the\npage layout and the panel's contents. `SidePanel` also has logic to flip the position and direction\nof the `ToggleButton` as well as the direction of the expand / collapse animation. If you're using\nCSS Flexbox for layouts and using the provided components, you shouldn't have to provide any custom\nlogic or styling for bidirectional support.\n```tsx\nimport * as React from 'react';\n\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {AccentIcon} from '@workday/canvas-kit-react/icon';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\nimport {rocketIcon} from '@workday/canvas-accent-icons-web';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst flexHeadingStyles = createStyles({\n alignItems: 'center',\n gap: system.space.x2,\n});\n\nconst viewPortStyles = createStyles({\n height: px2rem(320),\n});\n\nexport const Basic = () => {\n const model = useSidePanelModel();\n\n return (\n <Flex cs={viewPortStyles}>\n <SidePanel model={model}>\n <SidePanel.Heading size=\"small\">\n <Flex cs={flexHeadingStyles}>\n <AccentIcon icon={rocketIcon} />\n Tasks Panel\n </Flex>\n </SidePanel.Heading>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n </SidePanel>\n </Flex>\n );\n};\n```\n\n### Hidden Name\n\n`SidePanel`'s `<section>` element container should always have an accessible name to help screen\nreader users understand the purpose of the panel. For this reason, we recommend using the\n`SidePanel.Heading` component and setting the `hidden` prop to `true`. This will visually hide the\nheading while keeping it accessible to screen readers.\n```tsx\nimport * as React from 'react';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nexport const Heading = () => {\n const model = useSidePanelModel({\n onStateTransition: state => {\n console.log(`state is: ${state}`);\n },\n });\n\n return (\n <Flex cs={stylesOverride.viewport}>\n <SidePanel model={model}>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n <SidePanel.Heading hidden size=\"small\">\n Tasks Panel\n </SidePanel.Heading>\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Side Panel with a hidden title text.\n </Text>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Alternate Variant\n\n`SidePanel` has one variant, `alternate`, which you can supply as a top-level prop. Default depth of\n`alternate` variant is 5, if `alternate` SidePanel has an overlay behavior the depth 6 should be\nused (this case is covered in the Examples section).\n\n### External Control\n\nSometimes you'll want to control `SidePanel`'s expand / collapse behavior from outside the\ncomponent. You can use the model's events (`model.events.expand()` and `model.events.collapse()`) to\nprogrammatically control the panel.\n\n#### Notes about accessibility\n\nWhen using external controls, be mindful of accessibility:\n\n- Use `aria-pressed` on toggle buttons to indicate the current state\n- The `SidePanel.ToggleButton` inside the panel automatically receives the correct ARIA attributes\n- External buttons should have their own accessible labels (don't rely on `aria-labelledby` pointing\n to the panel's label)\n\nIn the following example, we use the model's `transitionState` to determine the button's pressed\nstate and call `model.events.expand()` or `model.events.collapse()` on click.\n```tsx\nimport * as React from 'react';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n panel: createStyles({\n alignItems: 'center',\n padding: system.space.x4,\n }),\n panelHeading: createStyles({\n color: system.color.fg.muted.stronger,\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nexport const ExternalControl = () => {\n const model = useSidePanelModel({\n initialTransitionState: 'collapsed',\n labelId: 'tasks-panel-label',\n });\n\n return (\n <Flex cs={stylesOverride.viewport}>\n <SidePanel model={model}>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n <SidePanel.Heading size=\"small\" cs={stylesOverride.panelHeading}>\n Task Panel\n </SidePanel.Heading>\n {model.state.transitionState === 'expanded' && (\n <Flex cs={stylesOverride.panel}>Contents</Flex>\n )}\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Control the panel externally\n </Text>\n <SecondaryButton\n onClick={\n model.state.transitionState === 'expanded' ? model.events.collapse : model.events.expand\n }\n aria-pressed={model.state.transitionState === 'expanded'}\n >\n {model.state.transitionState === 'expanded' ? 'Hide Side Panel' : 'Show Side Panel'}\n </SecondaryButton>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Right Origin\n\nBy default, `SidePanel` uses a `start` origin (left in LTR, right in RTL). This sets the\n`ToggleButton`'s position and direction as well as the direction of the animation. You can set the\norigin to `\"end\"` to flip these. The origin uses logical properties (`start`/`end`) for proper\nbidirectional support.\n```tsx\nimport {SecondaryButton} from '@workday/canvas-kit-react/button';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {CanvasProvider} from '@workday/canvas-kit-react/common';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\n// local helper hook for setting content direction;\nimport {useDirection} from './useDirection';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n panelContainer: createStyles({\n marginInlineStart: 'auto',\n }),\n panel: createStyles({\n alignItems: 'center',\n justifyContent: 'flex-end',\n padding: system.space.x4,\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nconst RightPanel = () => {\n const model = useSidePanelModel({\n origin: 'end',\n });\n\n return (\n <SidePanel model={model} className={stylesOverride.panelContainer}>\n <SidePanel.ToggleButton aria-label=\"Collapse View\" />\n <Flex cs={stylesOverride.panel}>\n <SidePanel.Heading size=\"small\">Tasks Panel</SidePanel.Heading>\n </Flex>\n </SidePanel>\n );\n};\n\nexport const RightOrigin = () => {\n const {direction, toggleDirection} = useDirection();\n\n return (\n <CanvasProvider dir={direction}>\n <Flex cs={stylesOverride.viewport}>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Toggle the content direction\n </Text>\n <SecondaryButton onClick={toggleDirection}>\n Set to {direction === 'ltr' ? 'Right-to-Left' : 'Left-to-Right'}\n </SecondaryButton>\n </Flex>\n\n <RightPanel />\n </Flex>\n </CanvasProvider>\n );\n};\n```\n\n### Always Open\n\nIf you do not need `SidePanel`'s expand / collapse behavior, you can simply omit the `ToggleButton`.\n```tsx\nimport {AccentIcon} from '@workday/canvas-kit-react/icon';\nimport {rocketIcon} from '@workday/canvas-accent-icons-web';\nimport {SidePanel, useSidePanelModel} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {system} from '@workday/canvas-tokens-web';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\n\nconst stylesOverride = {\n accentIcon: createStyles({\n marginRight: system.space.x4,\n }),\n pageContainer: createStyles({\n gap: system.space.x4,\n height: px2rem(320),\n }),\n panelContainer: createStyles({\n alignItems: 'center',\n padding: system.space.x4,\n }),\n panelHeading: createStyles({\n color: system.color.fg.default,\n }),\n mainContent: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexBasis: 'auto',\n flex: 1,\n }),\n};\n\nexport const AlwaysOpen = () => {\n const model = useSidePanelModel();\n\n return (\n <Flex cs={stylesOverride.pageContainer}>\n <SidePanel model={model}>\n <Flex cs={stylesOverride.panelContainer}>\n <AccentIcon icon={rocketIcon} cs={stylesOverride.accentIcon} />\n <SidePanel.Heading size=\"small\" cs={stylesOverride.panelHeading}>\n Tasks Panel\n </SidePanel.Heading>\n </Flex>\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.mainContent}>\n <Text as=\"p\" typeLevel=\"body.large\">\n This is the main content section.\n </Text>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Deriving Expanded State\n\nIf you need a simple boolean `expanded` state (similar to the preview-react `onExpandedChange`\ncallback), you can derive it from the `transitionState` using the `onStateTransition` callback on\nthe model.\n\n### onStateTransition\n\nThe `onStateTransition` callback is called whenever the panel's transition state changes. This\nincludes all four states: `expanding`, `expanded`, `collapsing`, and `collapsed`. You can pass this\ncallback directly to the `SidePanel` component or to the `useSidePanelModel` hook.\n\nThe transition flow is:\n\n1. **Collapsing**: `expanded` \u2192 `collapsing` \u2192 `collapsed`\n2. **Expanding**: `collapsed` \u2192 `expanding` \u2192 `expanded`\n\nThis is useful for:\n\n- Triggering side effects when the panel state changes\n- Syncing the panel state with external state management\n- Animating child components based on the transition state\n```tsx\nimport * as React from 'react';\nimport {Flex} from '@workday/canvas-kit-react/layout';\nimport {\n SidePanel,\n useSidePanelModel,\n SidePanelTransitionStates,\n} from '@workday/canvas-kit-labs-react/side-panel';\nimport {Text} from '@workday/canvas-kit-react/text';\nimport {AccessibleHide} from '@workday/canvas-kit-react/common';\nimport {createStyles, px2rem} from '@workday/canvas-kit-styling';\n\nconst stylesOverride = {\n viewport: createStyles({\n height: px2rem(320),\n }),\n main: createStyles({\n alignItems: 'center',\n justifyContent: 'center',\n flexDirection: 'column',\n flex: 1,\n flexBasis: 'auto',\n }),\n};\n\nexport const OnStateTransition = () => {\n const [transitionState, setTransitionState] =\n React.useState<SidePanelTransitionStates>('expanded');\n\n const model = useSidePanelModel({\n onStateTransition: state => {\n setTransitionState(state);\n console.log('Expanded changed to:', state);\n },\n });\n\n return (\n <Flex cs={stylesOverride.viewport}>\n <SidePanel model={model}>\n <SidePanel.ToggleButton />\n <SidePanel.Heading hidden size=\"small\">\n Hidden Title\n </SidePanel.Heading>\n </SidePanel>\n <Flex as=\"main\" cs={stylesOverride.main}>\n <Text as=\"p\" typeLevel=\"body.large\">\n Side panel is {transitionState}.\n </Text>\n </Flex>\n </Flex>\n );\n};\n```\n\n### Accessibility\n\n`SidePanel` renders a `<section>` element with an accessible name provided by `aria-labelledby`,\nwhich references the `SidePanel.Heading` component. This ensures screen reader users understand the\npurpose of the panel.\n\n#### Panel and Heading\n\n- The `SidePanel.Heading` provides the accessible name for the panel via `aria-labelledby`\n- When the panel is collapsed, the heading is automatically hidden visually but remains accessible\n to screen readers\n- Use the `hidden` prop on `SidePanel.Heading` if you want the heading always visually hidden\n\n#### Toggle Button\n\n- `SidePanel.ToggleButton` automatically includes `aria-controls` (references the panel's `id`),\n `aria-pressed` (indicates current state), and `aria-describedby` (references the panel's heading)\n- Developers must provide a static `aria-label` string on `SidePanel.ToggleButton` to describe the\n button's purpose (e.g., \"Collapse View\"). Avoid using ambiguous terms like \"Toggle\" in the label.\n Since `aria-pressed` communicates the state, avoid dynamically updating `aria-label`\n- The button includes a Tooltip with customizable text via `tooltipTextExpand` and\n `tooltipTextCollapse` props (defaults: \"Expand View\" and \"Collapse View\")\n- For optimal keyboard navigation, place `SidePanel.ToggleButton` as the first focusable element in\n the panel\n\n## Component API\n\n## Hooks\n\n### useSidePanelModel\n\nThe `useSidePanelModel` hook creates a model for managing the SidePanel's state and events. You can\npass this model to the `SidePanel` component, or let the component create one internally.\n\n```tsx\n\n// Create a model with custom configuration\nconst model = useSidePanelModel({\n initialTransitionState: 'collapsed',\n origin: 'end',\n onStateTransition: state => console.log('State:', state),\n});\n\n// Access state\nmodel.state.transitionState; // 'expanded' | 'expanding' | 'collapsed' | 'collapsing'\nmodel.state.panelId; // unique ID for the panel\nmodel.state.labelId; // unique ID for the label\n\n// Trigger events\nmodel.events.expand(); // Set to expanded (no animation)\nmodel.events.collapse(); // Set to collapsed (no animation)\nmodel.events.handleAnimationStart(); // Start expand/collapse animation\n```\n\n### useSidePanelContainer\n\nThe `useSidePanelContainer` elemProps hook provides the necessary props for the SidePanel container\nelement, including `id`, `aria-labelledby`, and `onTransitionEnd`.\n\n### useSidePanelToggleButtonElemProps\n\nThe `useSidePanelToggleButtonElemProps` elemProps hook provides ARIA attributes for the toggle\nbutton, including `aria-controls`, `aria-expanded`, and `aria-labelledby`.\n\n## Specifications\n\n"
|
|
363
|
-
},
|
|
364
|
-
"ai-ingress-button-(ai)": {
|
|
365
|
-
title: "Labs/AI Ingress Button (AI)",
|
|
366
|
-
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/labs-ai-ingress-button-(ai)--docs",
|
|
367
|
-
mdxPath: "modules/labs-react/ai-ingress-button/stories/AIIngressButton.mdx",
|
|
368
|
-
mdxProse: "# AI Ingress Button\n\nCTA to open and close AI Ingress Button\n\n## Installation\n\n```sh\nyarn add @workday/canvas-kit-labs-react\n```\n\n## Usage\n\n### Basic Example\n\nYou can click to toggle the AI Ingress Button.\n```tsx\nimport {useState} from 'react';\n\nimport {AIIngressButton} from '@workday/canvas-kit-labs-react/ai-ingress-button';\n\nexport const Basic = () => {\n const [toggled, setToggled] = useState(false);\n return (\n <div>\n <AIIngressButton\n aria-label={toggled ? 'Hide AI Ingress' : 'Show AI Ingress'}\n onClick={() => setToggled(!toggled)}\n toggled={toggled}\n />\n </div>\n );\n};\n```\n\n### Inverse Example\n\nThe Button can also be used on dark backgrounds.\n```tsx\nimport {useState} from 'react';\n\nimport {AIIngressButton} from '@workday/canvas-kit-labs-react/ai-ingress-button';\nimport {createStyles} from '@workday/canvas-kit-styling';\nimport {system} from '@workday/canvas-tokens-web';\n\nconst darkBackground = createStyles({\n background: system.color.bg.contrast.strong,\n padding: system.space.x8,\n});\n\nexport const Inverse = () => {\n const [toggled, setToggled] = useState(false);\n return (\n <div className={darkBackground}>\n <AIIngressButton\n variant=\"inverse\"\n onClick={() => setToggled(!toggled)}\n aria-label={toggled ? 'Hide Ingress' : 'Show Ingress'}\n toggled={toggled}\n />\n </div>\n );\n};\n```\n\n## Component API\n\n"
|
|
369
|
-
},
|
|
370
370
|
"color-preview": {
|
|
371
371
|
title: "Components/Inputs/Color Picker/Color Preview",
|
|
372
372
|
storybookUrl: "https://workday.github.io/canvas-kit/?path=/docs/components-inputs-color-picker-color-preview--docs",
|