From ac6650733f65e70c52ab00e6fd162d4bff62a057 Mon Sep 17 00:00:00 2001 From: Jess Telford Date: Tue, 23 Apr 2024 15:07:35 +1000 Subject: [PATCH 1/4] Add csf-v3 internal migration --- .../csf-v3/tests/transform.input.tsx | 32 ++++++ .../csf-v3/tests/transform.output.tsx | 38 +++++++ .../migrations/csf-v3/tests/transform.test.ts | 11 ++ .../src/migrations/csf-v3/transform.ts | 101 ++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 polaris-migrator/src/migrations/csf-v3/tests/transform.input.tsx create mode 100644 polaris-migrator/src/migrations/csf-v3/tests/transform.output.tsx create mode 100644 polaris-migrator/src/migrations/csf-v3/tests/transform.test.ts create mode 100644 polaris-migrator/src/migrations/csf-v3/transform.ts diff --git a/polaris-migrator/src/migrations/csf-v3/tests/transform.input.tsx b/polaris-migrator/src/migrations/csf-v3/tests/transform.input.tsx new file mode 100644 index 00000000000..9ec54304be5 --- /dev/null +++ b/polaris-migrator/src/migrations/csf-v3/tests/transform.input.tsx @@ -0,0 +1,32 @@ +import React from 'react'; + +// eslint-disable-next-line import/no-anonymous-default-export +export default { + foo: 'bar', +}; + +export const Blah = () => { + return
hello
; +}; + +Blah.parameters = {}; + +export function App() { + return
hello
; +} + +App.parameters = {}; + +export const Comp = { + render() { + return
hello
; + }, +}; + +Comp.parameters = {}; + +export const Zip = () => ( +
+

hello

+
+); diff --git a/polaris-migrator/src/migrations/csf-v3/tests/transform.output.tsx b/polaris-migrator/src/migrations/csf-v3/tests/transform.output.tsx new file mode 100644 index 00000000000..601a920e8fa --- /dev/null +++ b/polaris-migrator/src/migrations/csf-v3/tests/transform.output.tsx @@ -0,0 +1,38 @@ +import React from 'react'; + +// eslint-disable-next-line import/no-anonymous-default-export +export default { + foo: 'bar', +}; + +export const Blah = { + render: () => { + return
hello
; + }, + + parameters: {}, +}; + +export const App = { + render() { + return
hello
; + }, + + parameters: {}, +}; + +export const Comp = { + render() { + return
hello
; + }, +}; + +Comp.parameters = {}; + +export const Zip = { + render: () => ( +
+

hello

+
+ ), +}; diff --git a/polaris-migrator/src/migrations/csf-v3/tests/transform.test.ts b/polaris-migrator/src/migrations/csf-v3/tests/transform.test.ts new file mode 100644 index 00000000000..e2e922d3c54 --- /dev/null +++ b/polaris-migrator/src/migrations/csf-v3/tests/transform.test.ts @@ -0,0 +1,11 @@ +import {check} from '../../../utilities/check'; + +const transform = 'csf-v3'; +const fixtures = ['transform']; + +for (const fixture of fixtures) { + check(__dirname, { + fixture, + transform, + }); +} diff --git a/polaris-migrator/src/migrations/csf-v3/transform.ts b/polaris-migrator/src/migrations/csf-v3/transform.ts new file mode 100644 index 00000000000..d423a586870 --- /dev/null +++ b/polaris-migrator/src/migrations/csf-v3/transform.ts @@ -0,0 +1,101 @@ +import type {API, FileInfo} from 'jscodeshift'; + +export default function transformer(file: FileInfo, {jscodeshift: j}: API) { + const source = j(file.source); + + source.find(j.ExportNamedDeclaration).replaceWith(({value: node}) => { + let id; + let storyFn; + let isArrowFunction = false; + + if ( + // export function App() {..} + j.match(node, { + // @ts-expect-error -- shh + declaration: {type: 'FunctionDeclaration'}, + }) + ) { + // @ts-expect-error -- shh + id = node.declaration.id; + storyFn = j.functionExpression( + null, + // @ts-expect-error -- shh + node.declaration.params, + // @ts-expect-error -- shh + node.declaration.body, + ); + } else if ( + // export const App = () => {..} + j.match(node, { + declaration: { + type: 'VariableDeclaration', + // @ts-expect-error -- shh + declarations: [{init: {type: 'ArrowFunctionExpression'}}], + }, + }) + ) { + // @ts-expect-error -- shh + id = node.declaration?.declarations?.[0]?.id; + storyFn = j.arrowFunctionExpression( + // @ts-expect-error -- shh + node.declaration.declarations[0].init.params, + // @ts-expect-error -- shh + node.declaration.declarations[0].init.body, + ); + isArrowFunction = true; + } else { + return node; + } + + // App.parameters = {..}, etc + const storyData = source.find(j.ExpressionStatement, { + expression: { + type: 'AssignmentExpression', + left: { + type: 'MemberExpression', + object: { + name: id.name, + }, + }, + }, + }); + + // Convert it into object properties: + // parameters: {..}, etc + const storyProps = storyData.nodes().map((node) => + j.property( + 'init', + // @ts-expect-error -- shh + node.expression.left.property, + // @ts-expect-error -- shh + node.expression.right, + ), + ); + + // They'll be added to the newly exported object later, so don't need them + // anymore + storyData.remove(); + + // render() { ... } + // or + // render: () => { ... } + const renderProp = j.property('init', j.identifier('render'), storyFn); + + if (!isArrowFunction) { + // Use the ES6 shorthand + renderProp.method = true; + } + + // export const App = { render() { ... }, parameters: { .. } } + return j.exportNamedDeclaration( + j.variableDeclaration('const', [ + j.variableDeclarator( + id, + j.objectExpression([renderProp, ...storyProps]), + ), + ]), + ); + }); + + return source.toSource(); +} From 183472a4cb34a0b037ecb2721ae177d41c2f5a8b Mon Sep 17 00:00:00 2001 From: Jess Telford Date: Tue, 23 Apr 2024 15:55:48 +1000 Subject: [PATCH 2/4] Add storybook lint rules --- .eslintrc.js | 5 ++ package.json | 1 + pnpm-lock.yaml | 92 ++++++++++++++++++++++++++++ polaris-react/playground/stories.tsx | 2 +- 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 662aa33855f..d50397e9ab2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -148,6 +148,11 @@ module.exports = { 'polaris-react/playground/*.tsx', 'polaris-react/src/components/**/*.stories.tsx', ], + extends: [ + 'plugin:storybook/recommended', + 'plugin:storybook/csf', + 'plugin:storybook/csf-strict', + ], rules: { 'react/prefer-stateless-function': 'off', '@shopify/jsx-no-hardcoded-content': 'off', diff --git a/package.json b/package.json index be3afe85f98..4ff17dee4ef 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "@types/node": "^20.10.0", "babel-loader": "^9.1.2", "eslint": "^8.3.0", + "eslint-plugin-storybook": "^0.8.0", "execa": "^5.0.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0fcb74bc79..8b8fdcc318a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,6 +83,9 @@ importers: eslint: specifier: ^8.3.0 version: 8.10.0 + eslint-plugin-storybook: + specifier: ^0.8.0 + version: 0.8.0(eslint@8.10.0)(typescript@4.9.3) execa: specifier: ^5.0.0 version: 5.1.1 @@ -6217,6 +6220,12 @@ packages: - supports-color dev: true + /@storybook/csf@0.0.1: + resolution: {integrity: sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==} + dependencies: + lodash: 4.17.21 + dev: true + /@storybook/csf@0.1.2: resolution: {integrity: sha512-ePrvE/pS1vsKR9Xr+o+YwdqNgHUyXvg+1Xjx0h9LrVx7Zq4zNe06pd63F5EvzTbCbJsHj7GHr9tkiaqm7U8WRA==} dependencies: @@ -7285,6 +7294,14 @@ packages: '@typescript-eslint/visitor-keys': 5.56.0 dev: true + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + dev: true + /@typescript-eslint/type-utils@5.56.0(eslint@8.10.0)(typescript@4.9.3): resolution: {integrity: sha512-8WxgOgJjWRy6m4xg9KoSHPzBNZeQbGlQOH7l2QEhQID/+YseaFxg5J/DLwWSsi9Axj4e/cCiKx7PVzOq38tY4A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7310,6 +7327,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@typescript-eslint/typescript-estree@5.56.0(typescript@4.9.3): resolution: {integrity: sha512-41CH/GncsLXOJi0jb74SnC7jVPWeVJ0pxQj8bOjH1h2O26jXN3YHKDT1ejkVz5YeTEQPeLCCRY0U2r68tfNOcg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7331,6 +7353,27 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.3): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@4.9.3) + typescript: 4.9.3 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils@5.56.0(eslint@8.10.0)(typescript@4.9.3): resolution: {integrity: sha512-XhZDVdLnUJNtbzaJeDSCIYaM+Tgr59gZGbFuELgF7m0IY03PlciidS7UQNKLE0+WpUTn1GlycEr6Ivb/afjbhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7351,6 +7394,26 @@ packages: - typescript dev: true + /@typescript-eslint/utils@5.62.0(eslint@8.10.0)(typescript@4.9.3): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.3.0(eslint@8.10.0) + '@types/json-schema': 7.0.11 + '@types/semver': 7.5.6 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.3) + eslint: 8.10.0 + eslint-scope: 5.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys@5.56.0: resolution: {integrity: sha512-1mFdED7u5bZpX6Xxf5N9U2c18sb+8EvU3tyOIj6LQZ5OOvnmj8BVeNNP603OFPm5KkS1a7IvCIcwrdHXaEMG/Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7359,6 +7422,14 @@ packages: eslint-visitor-keys: 3.3.0 dev: true + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.3.0 + dev: true + /@use-it/event-listener@0.1.7(react@18.2.0): resolution: {integrity: sha512-hgfExDzUU9uTRTPDCpw2s9jWTxcxmpJya3fK5ADpf5VDpSy8WYwY/kh28XE0tUcbsljeP8wfan48QvAQTSSa3Q==} peerDependencies: @@ -11456,6 +11527,22 @@ packages: eslint: 8.10.0 dev: true + /eslint-plugin-storybook@0.8.0(eslint@8.10.0)(typescript@4.9.3): + resolution: {integrity: sha512-CZeVO5EzmPY7qghO2t64oaFM+8FTaD4uzOEjHKp516exyTKo+skKAL9GI3QALS2BXhyALJjNtwbmr1XinGE8bA==} + engines: {node: '>= 18'} + peerDependencies: + eslint: '>=6' + dependencies: + '@storybook/csf': 0.0.1 + '@typescript-eslint/utils': 5.62.0(eslint@8.10.0)(typescript@4.9.3) + eslint: 8.10.0 + requireindex: 1.2.0 + ts-dedent: 2.2.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /eslint-rule-composer@0.3.0: resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==} engines: {node: '>=4.0.0'} @@ -20092,6 +20179,11 @@ packages: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} dev: true + /requireindex@1.2.0: + resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} + engines: {node: '>=0.10.5'} + dev: true + /requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: true diff --git a/polaris-react/playground/stories.tsx b/polaris-react/playground/stories.tsx index 2bc111bca80..46b0c692d9b 100644 --- a/polaris-react/playground/stories.tsx +++ b/polaris-react/playground/stories.tsx @@ -2,8 +2,8 @@ import {Playground} from './Playground'; import {KitchenSink} from './KitchenSink'; import {DetailsPage} from './DetailsPage'; -// eslint-disable-next-line import/no-anonymous-default-export export default { + // eslint-disable-next-line storybook/no-title-property-in-meta title: 'Playground', parameters: { layout: 'fullscreen', From 36a3520b34987da9e9749175a28e32092ef6d131 Mon Sep 17 00:00:00 2001 From: Jess Telford Date: Tue, 23 Apr 2024 15:57:08 +1000 Subject: [PATCH 3/4] Migrate to CSF v3 --- polaris-react/playground/DetailsPage.tsx | 1500 +- polaris-react/playground/KitchenSink.tsx | 70 +- polaris-react/playground/Playground.tsx | 16 +- .../AccountConnection.stories.tsx | 152 +- .../ActionList/ActionList.stories.tsx | 736 +- .../AppProvider/AppProvider.stories.tsx | 286 +- .../Autocomplete/Autocomplete.stories.tsx | 1598 +- .../src/components/Avatar/Avatar.stories.tsx | 324 +- .../src/components/Badge/Badge.stories.tsx | 286 +- .../src/components/Banner/Banner.stories.tsx | 720 +- .../src/components/Bleed/Bleed.stories.tsx | 224 +- .../BlockStack/BlockStack.stories.tsx | 304 +- .../src/components/Box/Box.stories.tsx | 484 +- .../BulkActions/BulkActions.stories.tsx | 260 +- .../src/components/Button/Button.stories.tsx | 1520 +- .../ButtonGroup/ButtonGroup.stories.tsx | 368 +- .../CalloutCard/CalloutCard.stories.tsx | 178 +- .../src/components/Card/Card.stories.tsx | 1368 +- .../components/Checkbox/Checkbox.stories.tsx | 282 +- .../ChoiceList/ChoiceList.stories.tsx | 394 +- .../Collapsible/Collapsible.stories.tsx | 80 +- .../ColorPicker/ColorPicker.stories.tsx | 171 +- .../components/Combobox/Combobox.stories.tsx | 1496 +- .../ContextualSaveBar.stories.tsx | 204 +- .../DataTable/DataTable.stories.tsx | 1770 +- .../DatePicker/DatePicker.stories.tsx | 344 +- .../DescriptionList.stories.tsx | 102 +- .../components/Divider/Divider.stories.tsx | 58 +- .../components/DropZone/DropZone.stories.tsx | 1052 +- .../EmptyState/EmptyState.stories.tsx | 156 +- .../ExceptionList/ExceptionList.stories.tsx | 122 +- .../components/Filters/Filters.stories.tsx | 3937 ++--- .../FooterHelp/FooterHelp.stories.tsx | 66 +- .../src/components/Form/Form.stories.tsx | 122 +- .../FormLayout/FormLayout.stories.tsx | 220 +- .../src/components/Frame/Frame.stories.tsx | 4 +- .../FullscreenBar/FullscreenBar.stories.tsx | 192 +- .../src/components/Grid/Grid.stories.tsx | 244 +- .../src/components/Icon/Icon.stories.tsx | 314 +- .../IndexFilters/IndexFilters.stories.tsx | 4183 ++--- .../IndexTable/IndexTable.stories.tsx | 14312 ++++++++-------- .../InlineError/InlineError.stories.tsx | 12 +- .../InlineGrid/InlineGrid.stories.tsx | 246 +- .../InlineStack/InlineStack.stories.tsx | 430 +- .../KeyboardKey/KeyboardKey.stories.tsx | 170 +- .../src/components/Layout/Layout.stories.tsx | 945 +- .../LegacyCard/LegacyCard.stories.tsx | 1046 +- .../LegacyFilters/LegacyFilters.stories.tsx | 2943 ++-- .../LegacyStack/LegacyStack.stories.tsx | 174 +- .../LegacyTabs/LegacyTabs.stories.tsx | 496 +- .../src/components/Link/Link.stories.tsx | 62 +- .../src/components/List/List.stories.tsx | 64 +- .../components/Listbox/Listbox.stories.tsx | 914 +- .../components/Loading/Loading.stories.tsx | 24 +- .../MediaCard/MediaCard.stories.tsx | 432 +- .../src/components/Modal/Modal.stories.tsx | 1364 +- .../Navigation/Navigation.stories.tsx | 2711 +-- .../OptionList/OptionList.stories.tsx | 746 +- .../src/components/Page/Page.stories.tsx | 1014 +- .../PageActions/PageActions.stories.tsx | 106 +- .../Pagination/Pagination.stories.tsx | 162 +- .../components/Popover/Popover.stories.tsx | 1595 +- .../ProgressBar/ProgressBar.stories.tsx | 56 +- .../RadioButton/RadioButton.stories.tsx | 310 +- .../RangeSlider/RangeSlider.stories.tsx | 414 +- .../ResourceItem/ResourceItem.stories.tsx | 730 +- .../ResourceList/ResourceList.stories.tsx | 2800 +-- .../Scrollable/Scrollable.stories.tsx | 2756 +-- .../src/components/Select/Select.stories.tsx | 562 +- .../SelectAllActions.stories.tsx | 142 +- .../SettingToggle/SettingToggle.stories.tsx | 461 +- .../ShadowBevel/ShadowBevel.stories.tsx | 138 +- .../src/components/Sheet/Sheet.stories.tsx | 936 +- .../SkeletonBodyText.stories.tsx | 20 +- .../SkeletonDisplayText.stories.tsx | 36 +- .../SkeletonPage/SkeletonPage.stories.tsx | 424 +- .../SkeletonTabs/SkeletonTabs.stories.tsx | 100 +- .../SkeletonThumbnail.stories.tsx | 60 +- .../components/Spinner/Spinner.stories.tsx | 170 +- .../src/components/Tabs/Tabs.stories.tsx | 530 +- .../src/components/Tag/Tag.stories.tsx | 340 +- .../src/components/Text/Text.stories.tsx | 321 +- .../TextContainer/TextContainer.stories.tsx | 93 +- .../TextField/TextField.stories.tsx | 2031 +-- .../ThemeProvider/ThemeProvider.stories.tsx | 147 +- .../Thumbnail/Thumbnail.stories.tsx | 120 +- .../src/components/Toast/Toast.stories.tsx | 698 +- .../components/Tooltip/Tooltip.stories.tsx | 1041 +- .../src/components/TopBar/TopBar.stories.tsx | 164 +- .../VideoThumbnail/VideoThumbnail.stories.tsx | 166 +- 90 files changed, 36606 insertions(+), 35035 deletions(-) diff --git a/polaris-react/playground/DetailsPage.tsx b/polaris-react/playground/DetailsPage.tsx index ae1c55b4fad..5aa1d736d82 100644 --- a/polaris-react/playground/DetailsPage.tsx +++ b/polaris-react/playground/DetailsPage.tsx @@ -51,786 +51,794 @@ import type {DropZoneProps, PageProps} from '../src'; import styles from './DetailsPage.module.css'; -export function DetailsPage() { - const defaultState = useRef({ - emailFieldValue: 'dharma@jadedpixel.com', - nameFieldValue: 'Jaded Pixel', - }); - const [query, setQuery] = useState(''); - const skipToContentRef = useRef(null); - const [toastActive, setToastActive] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [isDirty, setIsDirty] = useState(false); - const [searchActive, setSearchActive] = useState(false); - const [searchValue, setSearchValue] = useState(''); - const [userMenuActive, setUserMenuActive] = useState(false); - const [mobileNavigationActive, setMobileNavigationActive] = useState(false); - const [modalActive, setModalActive] = useState(false); - const [navItemActive, setNavItemActive] = useState('products'); - const initialDescription = - 'The M60-A represents the benchmark and equilibrium between function and design for us at Rama Works. The gently exaggerated design of the frame is not understated, but rather provocative. Inspiration and evolution from previous models are evident in the beautifully articulated design and the well defined aesthetic, the fingerprint of our ‘Industrial Modern’ designs.'; - const [previewValue, setPreviewValue] = useState(initialDescription); - const [nameFieldValue, setNameFieldValue] = useState( - defaultState.current.nameFieldValue, - ); - const [emailFieldValue, setEmailFieldValue] = useState( - defaultState.current.emailFieldValue, - ); - const [addedTags, setAddedTags] = useState< - {value: string; children: string}[] - >([]); - const [addedVendors, setAddedVendors] = useState< - {value: string; children: string}[] - >([]); - - const tags = useMemo( - () => [ - {value: 'Outdoors', children: 'Outdoors'}, - {value: 'Adventure', children: 'Adventure'}, - {value: 'Hiking', children: 'Hiking'}, - {value: 'Camping', children: 'Camping'}, - {value: 'Backpacking', children: 'Backpacking'}, - {value: 'Mountaineering', children: 'Mountaineering'}, - {value: 'Skiing', children: 'Skiing'}, - {value: 'Snowboarding', children: 'Snowboarding'}, - ...addedTags, - ], - [addedTags], - ); - - const vendors = useMemo( - () => [ - {value: 'The North Face', children: 'The North Face'}, - {value: 'Patagonia', children: 'Patagonia'}, - {value: 'Arc’teryx', children: 'Arc’teryx'}, - {value: 'Marmot', children: 'Marmot'}, - {value: 'Black Diamond', children: 'Black Diamond'}, - {value: 'Mountain Hardwear', children: 'Mountain Hardwear'}, - {value: 'Columbia', children: 'Columbia'}, - {value: 'Canada Goose', children: 'Canada Goose'}, - {value: 'Merrell', children: 'Merrell'}, - {value: 'Salomon', children: 'Salomon'}, - {value: 'Burton', children: 'Burton'}, - ...addedVendors, - ], - [addedVendors], - ); - - const handleTagSelect = useCallback( - (newTag: string) => { - if ( - tags.some((tag) => tag.value === newTag) || - addedTags.some((tag) => tag.value === newTag) - ) { - return; - } - setAddedTags((addedTags) => [ +export const DetailsPage = { + render() { + const defaultState = useRef({ + emailFieldValue: 'dharma@jadedpixel.com', + nameFieldValue: 'Jaded Pixel', + }); + const [query, setQuery] = useState(''); + const skipToContentRef = useRef(null); + const [toastActive, setToastActive] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [isDirty, setIsDirty] = useState(false); + const [searchActive, setSearchActive] = useState(false); + const [searchValue, setSearchValue] = useState(''); + const [userMenuActive, setUserMenuActive] = useState(false); + const [mobileNavigationActive, setMobileNavigationActive] = useState(false); + const [modalActive, setModalActive] = useState(false); + const [navItemActive, setNavItemActive] = useState('products'); + const initialDescription = + 'The M60-A represents the benchmark and equilibrium between function and design for us at Rama Works. The gently exaggerated design of the frame is not understated, but rather provocative. Inspiration and evolution from previous models are evident in the beautifully articulated design and the well defined aesthetic, the fingerprint of our ‘Industrial Modern’ designs.'; + const [previewValue, setPreviewValue] = useState(initialDescription); + const [nameFieldValue, setNameFieldValue] = useState( + defaultState.current.nameFieldValue, + ); + const [emailFieldValue, setEmailFieldValue] = useState( + defaultState.current.emailFieldValue, + ); + const [addedTags, setAddedTags] = useState< + {value: string; children: string}[] + >([]); + const [addedVendors, setAddedVendors] = useState< + {value: string; children: string}[] + >([]); + + const tags = useMemo( + () => [ + {value: 'Outdoors', children: 'Outdoors'}, + {value: 'Adventure', children: 'Adventure'}, + {value: 'Hiking', children: 'Hiking'}, + {value: 'Camping', children: 'Camping'}, + {value: 'Backpacking', children: 'Backpacking'}, + {value: 'Mountaineering', children: 'Mountaineering'}, + {value: 'Skiing', children: 'Skiing'}, + {value: 'Snowboarding', children: 'Snowboarding'}, ...addedTags, - {value: newTag, children: newTag}, - ]); - setQuery(''); - }, - [addedTags, tags], - ); - - const handleVendorSelect = useCallback( - (newVendor: string) => { - if ( - vendors.some((vendor) => vendor.value === newVendor) || - addedVendors.some((vendor) => vendor.value === newVendor) - ) { - return; - } - setAddedVendors((addedVendors) => [ + ], + [addedTags], + ); + + const vendors = useMemo( + () => [ + {value: 'The North Face', children: 'The North Face'}, + {value: 'Patagonia', children: 'Patagonia'}, + {value: 'Arc’teryx', children: 'Arc’teryx'}, + {value: 'Marmot', children: 'Marmot'}, + {value: 'Black Diamond', children: 'Black Diamond'}, + {value: 'Mountain Hardwear', children: 'Mountain Hardwear'}, + {value: 'Columbia', children: 'Columbia'}, + {value: 'Canada Goose', children: 'Canada Goose'}, + {value: 'Merrell', children: 'Merrell'}, + {value: 'Salomon', children: 'Salomon'}, + {value: 'Burton', children: 'Burton'}, ...addedVendors, - {value: newVendor, children: newVendor}, - ]); - setQuery(''); - }, - [addedVendors, vendors], - ); - - const [storeName, setStoreName] = useState( - defaultState.current.nameFieldValue, - ); - const [supportSubject, setSupportSubject] = useState(''); - const [supportMessage, setSupportMessage] = useState(''); - - const handleDiscard = useCallback(() => { - setEmailFieldValue(defaultState.current.emailFieldValue); - setNameFieldValue(defaultState.current.nameFieldValue); - setIsDirty(false); - }, []); - const handleSave = useCallback(() => { - defaultState.current.nameFieldValue = nameFieldValue; - defaultState.current.emailFieldValue = emailFieldValue; - - setIsDirty(false); - setToastActive(true); - setStoreName(defaultState.current.nameFieldValue); - }, [emailFieldValue, nameFieldValue]); - const handleSearchResultsDismiss = useCallback(() => { - setSearchActive(false); - setSearchValue(''); - }, []); - const handleSearchFieldChange = useCallback((value: string) => { - setSearchValue(value); - setSearchActive(value.length > 0); - }, []); - const toggleToastActive = useCallback( - () => setToastActive((toastActive) => !toastActive), - [], - ); - const toggleUserMenuActive = useCallback( - () => setUserMenuActive((userMenuActive) => !userMenuActive), - [], - ); - const toggleMobileNavigationActive = useCallback( - () => - setMobileNavigationActive( - (mobileNavigationActive) => !mobileNavigationActive, - ), - [], - ); - const toggleIsLoading = useCallback( - () => setIsLoading((isLoading) => !isLoading), - [], - ); - const toggleModalActive = useCallback( - () => setModalActive((modalActive) => !modalActive), - [], - ); - - const toastMarkup = toastActive ? ( - - ) : null; - - const userMenuActions = [ - { - items: [{content: 'Community forums'}], - }, - ]; - - const contextControlMarkup = ( -
- - - - - -

Spectrally yours

-
- ); - - const contextualSaveBarMarkup = isDirty ? ( - - ) : null; - - const userMenuMarkup = ( - - ); - - const searchResultsMarkup = ( - - ); - - const searchFieldMarkup = ( - - ); - - const topBarMarkup = ( - - ); - // ---- Navigation ---- - const navigationMarkup = ( - - { + if ( + tags.some((tag) => tag.value === newTag) || + addedTags.some((tag) => tag.value === newTag) + ) { + return; + } + setAddedTags((addedTags) => [ + ...addedTags, + {value: newTag, children: newTag}, + ]); + setQuery(''); + }, + [addedTags, tags], + ); + + const handleVendorSelect = useCallback( + (newVendor: string) => { + if ( + vendors.some((vendor) => vendor.value === newVendor) || + addedVendors.some((vendor) => vendor.value === newVendor) + ) { + return; + } + setAddedVendors((addedVendors) => [ + ...addedVendors, + {value: newVendor, children: newVendor}, + ]); + setQuery(''); + }, + [addedVendors, vendors], + ); + + const [storeName, setStoreName] = useState( + defaultState.current.nameFieldValue, + ); + const [supportSubject, setSupportSubject] = useState(''); + const [supportMessage, setSupportMessage] = useState(''); + + const handleDiscard = useCallback(() => { + setEmailFieldValue(defaultState.current.emailFieldValue); + setNameFieldValue(defaultState.current.nameFieldValue); + setIsDirty(false); + }, []); + const handleSave = useCallback(() => { + defaultState.current.nameFieldValue = nameFieldValue; + defaultState.current.emailFieldValue = emailFieldValue; + + setIsDirty(false); + setToastActive(true); + setStoreName(defaultState.current.nameFieldValue); + }, [emailFieldValue, nameFieldValue]); + const handleSearchResultsDismiss = useCallback(() => { + setSearchActive(false); + setSearchValue(''); + }, []); + const handleSearchFieldChange = useCallback((value: string) => { + setSearchValue(value); + setSearchActive(value.length > 0); + }, []); + const toggleToastActive = useCallback( + () => setToastActive((toastActive) => !toastActive), + [], + ); + const toggleUserMenuActive = useCallback( + () => setUserMenuActive((userMenuActive) => !userMenuActive), + [], + ); + const toggleMobileNavigationActive = useCallback( + () => + setMobileNavigationActive( + (mobileNavigationActive) => !mobileNavigationActive, + ), + [], + ); + const toggleIsLoading = useCallback( + () => setIsLoading((isLoading) => !isLoading), + [], + ); + const toggleModalActive = useCallback( + () => setModalActive((modalActive) => !modalActive), + [], + ); + + const toastMarkup = toastActive ? ( + + ) : null; + + const userMenuActions = [ + { + items: [{content: 'Community forums'}], + }, + ]; + + const contextControlMarkup = ( +
+ + + + + +

Spectrally yours

+
+ ); + + const contextualSaveBarMarkup = isDirty ? ( + + ) : null; + + const userMenuMarkup = ( + + ); + + const searchResultsMarkup = ( + { - toggleIsLoading(); - setNavItemActive('home'); - }, - matches: navItemActive === 'home', - url: '#', - }, - { - label: 'Orders', - icon: OrderIcon, - onClick: () => { - toggleIsLoading(); - setNavItemActive('orders'); + {content: 'Shopify help center'}, + {content: 'Community forums'}, + ]} + /> + ); + + const searchFieldMarkup = ( + + ); + + const topBarMarkup = ( + + ); + // ---- Navigation ---- + const navigationMarkup = ( + + { + toggleIsLoading(); + setNavItemActive('home'); + }, + matches: navItemActive === 'home', + url: '#', }, - matches: navItemActive === 'orders', - url: '#', - subNavigationItems: [ - { - label: 'All orders', - onClick: () => { - toggleIsLoading(); - setNavItemActive('all-orders'); - }, - matches: navItemActive.includes('orders'), - url: '#', + { + label: 'Orders', + icon: OrderIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('orders'); }, - { - url: '#', - label: 'Drafts', - onClick: () => { - toggleIsLoading(); - setNavItemActive('drafts'); + matches: navItemActive === 'orders', + url: '#', + subNavigationItems: [ + { + label: 'All orders', + onClick: () => { + toggleIsLoading(); + setNavItemActive('all-orders'); + }, + matches: navItemActive.includes('orders'), + url: '#', }, - matches: navItemActive === 'drafts', - }, - { - url: '#', - label: 'Abandoned checkouts', - onClick: () => { - toggleIsLoading(); - setNavItemActive('abandoned'); + { + url: '#', + label: 'Drafts', + onClick: () => { + toggleIsLoading(); + setNavItemActive('drafts'); + }, + matches: navItemActive === 'drafts', }, - matches: navItemActive === 'abandoned', - }, - ], - }, - { - label: 'Products', - icon: ProductIcon, - onClick: () => { - toggleIsLoading(); - setNavItemActive('products'); - }, - matches: navItemActive === 'products', - url: '#', - subNavigationItems: [ - { - label: 'All products', - onClick: () => { - toggleIsLoading(); - setNavItemActive('all-products'); + { + url: '#', + label: 'Abandoned checkouts', + onClick: () => { + toggleIsLoading(); + setNavItemActive('abandoned'); + }, + matches: navItemActive === 'abandoned', }, - matches: navItemActive.includes('products'), - url: '#', + ], + }, + { + label: 'Products', + icon: ProductIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('products'); }, - { - url: '#', - label: 'Inventory', - onClick: () => { - toggleIsLoading(); - setNavItemActive('inventory'); + matches: navItemActive === 'products', + url: '#', + subNavigationItems: [ + { + label: 'All products', + onClick: () => { + toggleIsLoading(); + setNavItemActive('all-products'); + }, + matches: navItemActive.includes('products'), + url: '#', }, - matches: navItemActive === 'inventory', - }, - { - url: '#', - label: 'Transfers', - onClick: () => { - toggleIsLoading(); - setNavItemActive('transfers'); + { + url: '#', + label: 'Inventory', + onClick: () => { + toggleIsLoading(); + setNavItemActive('inventory'); + }, + matches: navItemActive === 'inventory', + }, + { + url: '#', + label: 'Transfers', + onClick: () => { + toggleIsLoading(); + setNavItemActive('transfers'); + }, + matches: navItemActive === 'transfers', }, - matches: navItemActive === 'transfers', + ], + }, + { + label: 'Customers', + icon: PersonIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('customers'); }, - ], - }, - { - label: 'Customers', - icon: PersonIcon, - onClick: () => { - toggleIsLoading(); - setNavItemActive('customers'); + matches: navItemActive === 'customers', + url: '#', }, - matches: navItemActive === 'customers', - url: '#', - }, - { - label: 'Analytics', - icon: ChartVerticalIcon, - onClick: () => { - toggleIsLoading(); - setNavItemActive('analytics'); + { + label: 'Analytics', + icon: ChartVerticalIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('analytics'); + }, + matches: navItemActive === 'analytics', + url: '#', }, - matches: navItemActive === 'analytics', - url: '#', - }, - { - label: 'Marketing', - icon: TargetIcon, - onClick: () => { - toggleIsLoading(); - setNavItemActive('marketing'); + { + label: 'Marketing', + icon: TargetIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('marketing'); + }, + matches: navItemActive === 'marketing', + url: '#', }, - matches: navItemActive === 'marketing', - url: '#', - }, - { - label: 'Discounts', - icon: DiscountIcon, - onClick: () => { - toggleIsLoading(); - setNavItemActive('discounts'); + { + label: 'Discounts', + icon: DiscountIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('discounts'); + }, + matches: navItemActive === 'discounts', + url: '#', }, - matches: navItemActive === 'discounts', - url: '#', - }, - { - label: 'Apps', - icon: AppsIcon, - onClick: () => { - toggleIsLoading(); - setNavItemActive('apps'); + { + label: 'Apps', + icon: AppsIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('apps'); + }, + matches: navItemActive === 'apps', + url: '#', }, - matches: navItemActive === 'apps', - url: '#', - }, - ]} - /> - { - toggleIsLoading(); - setNavItemActive('pos'); + ]} + /> + { - toggleIsLoading(); - setNavItemActive('pos'); - }, - matches: navItemActive.includes('pos'), - url: '#', + }} + items={[ + { + label: 'Point of sale', + icon: posIcon, + onClick: () => { + toggleIsLoading(); + setNavItemActive('pos'); }, - { - url: '#', - label: 'Staff', - onClick: () => { - toggleIsLoading(); - setNavItemActive('pos'); + matches: navItemActive === 'pos', + url: '#', + subNavigationItems: [ + { + label: 'Overview', + onClick: () => { + toggleIsLoading(); + setNavItemActive('pos'); + }, + matches: navItemActive.includes('pos'), + url: '#', }, - matches: navItemActive === 'pos', - }, - { + { + url: '#', + label: 'Staff', + onClick: () => { + toggleIsLoading(); + setNavItemActive('pos'); + }, + matches: navItemActive === 'pos', + }, + { + url: '#', + label: 'Locations', + onClick: () => { + toggleIsLoading(); + setNavItemActive('pos'); + }, + matches: navItemActive === 'pos', + external: true, + }, + ], + }, + { + label: 'Updog Marketplace', + icon: ProductIcon, + onClick: () => {}, + matches: navItemActive === 'pos', + url: '#', + secondaryAction: { url: '#', - label: 'Locations', - onClick: () => { - toggleIsLoading(); - setNavItemActive('pos'); + accessibilityLabel: 'OLp', + icon: ExternalIcon, + tooltip: { + content: 'Open Updog Marketplace', }, - matches: navItemActive === 'pos', - external: true, }, - ], - }, - { - label: 'Updog Marketplace', - icon: ProductIcon, - onClick: () => {}, - matches: navItemActive === 'pos', - url: '#', - secondaryAction: { + }, + { + label: 'Radio', + icon: WifiIcon, + onClick: () => {}, + matches: navItemActive === 'pos', url: '#', - accessibilityLabel: 'OLp', - icon: ExternalIcon, - tooltip: { - content: 'Open Updog Marketplace', + secondaryAction: { + url: '#', + accessibilityLabel: 'radio', + icon: GlobeIcon, }, }, - }, - { - label: 'Radio', - icon: WifiIcon, - onClick: () => {}, - matches: navItemActive === 'pos', - url: '#', - secondaryAction: { - url: '#', - accessibilityLabel: 'radio', - icon: GlobeIcon, + ]} + /> + + + ); + + const loadingMarkup = isLoading ? : null; + + const skipToContentTarget = ( + + + Page content + + + ); + + const [title, setTitle] = useState( + "The North Face Ventrix Active Trail Hybrid Hoodie - Men's", + ); + const [descriptionValue, setDescriptionValue] = + useState(initialDescription); + const [selected, setSelected] = useState('today'); + + const options = [ + {label: 'Keyboard', value: 'keyboard'}, + {label: 'Accessories', value: 'accessories'}, + {label: 'Last 7 days', value: 'lastWeek'}, + ]; + + const handleChange = useCallback((newValue: string) => { + setDescriptionValue(newValue); + setPreviewValue(newValue); + }, []); + + const actions1: PageProps['secondaryActions'] = [ + { + content: 'Duplicate', + onAction: () => console.log('duplicate'), + }, + { + content: 'Print', + onAction: () => console.log('print'), + }, + ]; + const actions2: PageProps['secondaryActions'] = [ + { + content: 'Print', + onAction: () => console.log('print'), + }, + ]; + + const [actions, setActions] = + useState(actions1); + + const toggleActions = () => { + if (Array.isArray(actions) && actions.length === 2) { + setActions(actions2); + } else { + setActions(actions1); + } + }; + + // ---- Dropzone ---- + const [files, setFiles] = useState([]); + + const handleDropZoneDrop = useCallback< + NonNullable + >( + (_dropFiles, acceptedFiles, _rejectedFiles) => + setFiles((files) => [...files, ...acceptedFiles]), + [], + ); + + const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + + const fileUpload = !files.length && ; + const uploadedFiles = files.length > 0 && ( + + {files.map((file, index) => ( + + 0 + ? URL.createObjectURL(file) + : 'https://cdn.shopify.com/s/files/1/0757/9955/files/New_Post.png?12678548500147524304' + } + /> +
+ {file.name}{' '} + + {file.size} bytes + +
+
+ ))} +
+ ); + + // ---- Page markup ---- + const actualPageMarkup = ( + Success badge} + primaryAction={{ + content: 'Save this page', + onAction: () => console.log('save'), + }} + additionalMetadata="Created May 8, 2020 at 7:31 am from Developer Tools (via import)" + secondaryActions={ + Array.isArray(actions) && [ + ...actions, + { + content: 'View', + onAction: () => { + console.log(previewValue); + }, }, + ] + } + actionGroups={[ + { + title: 'Promote', + actions: [ + {content: 'Promote', onAction: () => console.log('promote')}, + ], }, - ]} - /> - console.log('embed'), + }, + { + content: 'Toggle page actions', + onAction: toggleActions, + }, + ], }, ]} - /> -
- ); - - const loadingMarkup = isLoading ? : null; - - const skipToContentTarget = ( - - - Page content - - - ); - - const [title, setTitle] = useState( - "The North Face Ventrix Active Trail Hybrid Hoodie - Men's", - ); - const [descriptionValue, setDescriptionValue] = useState(initialDescription); - const [selected, setSelected] = useState('today'); - - const options = [ - {label: 'Keyboard', value: 'keyboard'}, - {label: 'Accessories', value: 'accessories'}, - {label: 'Last 7 days', value: 'lastWeek'}, - ]; - - const handleChange = useCallback((newValue: string) => { - setDescriptionValue(newValue); - setPreviewValue(newValue); - }, []); - - const actions1: PageProps['secondaryActions'] = [ - { - content: 'Duplicate', - onAction: () => console.log('duplicate'), - }, - { - content: 'Print', - onAction: () => console.log('print'), - }, - ]; - const actions2: PageProps['secondaryActions'] = [ - { - content: 'Print', - onAction: () => console.log('print'), - }, - ]; - - const [actions, setActions] = - useState(actions1); - - const toggleActions = () => { - if (Array.isArray(actions) && actions.length === 2) { - setActions(actions2); - } else { - setActions(actions1); - } - }; - - // ---- Dropzone ---- - const [files, setFiles] = useState([]); - - const handleDropZoneDrop = useCallback>( - (_dropFiles, acceptedFiles, _rejectedFiles) => - setFiles((files) => [...files, ...acceptedFiles]), - [], - ); - - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; - - const fileUpload = !files.length && ; - const uploadedFiles = files.length > 0 && ( - - {files.map((file, index) => ( - - 0 - ? URL.createObjectURL(file) - : 'https://cdn.shopify.com/s/files/1/0757/9955/files/New_Post.png?12678548500147524304' - } - /> -
- {file.name}{' '} - - {file.size} bytes - -
-
- ))} -
- ); - - // ---- Page markup ---- - const actualPageMarkup = ( - Success badge} - primaryAction={{ - content: 'Save this page', - onAction: () => console.log('save'), - }} - additionalMetadata="Created May 8, 2020 at 7:31 am from Developer Tools (via import)" - secondaryActions={ - Array.isArray(actions) && [ - ...actions, - { - content: 'View', - onAction: () => { - console.log(previewValue); - }, - }, - ] - } - actionGroups={[ - { - title: 'Promote', - actions: [ - {content: 'Promote', onAction: () => console.log('promote')}, - ], - }, - { - title: 'More actions', - actions: [ - { - content: 'Embed on a website', - onAction: () => console.log('embed'), - }, - { - content: 'Toggle page actions', - onAction: toggleActions, - }, - ], - }, - ]} - pagination={{ - hasPrevious: true, - hasNext: true, - }} - > - - {skipToContentTarget} - - - - { - setTitle(title); - setIsDirty(true); - }} - autoComplete="off" - /> - - - - - - {uploadedFiles} - {fileUpload} - - - - - - - - + + setQuery(value), + }} + options={tags} + onSelect={handleTagSelect} + addAction={{ + value: query, + children: `Add ${query}`, + }} + /> + + setQuery(value), + }} + options={vendors} + onSelect={handleVendorSelect} + addAction={{ + value: query, + children: `Add ${query}`, + }} + /> + + + + + + + + + ); + + // ---- Loading ---- + const loadingPageMarkup = ( + + + + + + + + + + + + + ); + + const pageMarkup = isLoading ? loadingPageMarkup : actualPageMarkup; + + // ---- Modal ---- + const modalMarkup = ( + + + + + + + + + ); + + return ( + + {contextualSaveBarMarkup} + {loadingMarkup} + {pageMarkup} + {toastMarkup} + {modalMarkup} + + Learn more about{' '} + + fulfilling orders + + + + ); + }, +}; const posIcon = ``; diff --git a/polaris-react/playground/KitchenSink.tsx b/polaris-react/playground/KitchenSink.tsx index bb4e9b36883..c3af23f92be 100644 --- a/polaris-react/playground/KitchenSink.tsx +++ b/polaris-react/playground/KitchenSink.tsx @@ -23,37 +23,39 @@ Object.entries(modules).forEach( }, ); -export function KitchenSink() { - return Object.entries(stories) - .filter( - ([id]) => - ![ - 'Modal', - 'ContextualSaveBar', - 'TopBar', - 'Sheet', - 'Frame', - 'Loading', - 'AppProvider', - ].includes(id.split(':')[0]), - ) - .map(([id, Story]) => { - return ( -
- - - -
-
- ); - }); -} +export const KitchenSink = { + render() { + return Object.entries(stories) + .filter( + ([id]) => + ![ + 'Modal', + 'ContextualSaveBar', + 'TopBar', + 'Sheet', + 'Frame', + 'Loading', + 'AppProvider', + ].includes(id.split(':')[0]), + ) + .map(([id, Story]) => { + return ( +
+ + + +
+
+ ); + }); + }, +}; diff --git a/polaris-react/playground/Playground.tsx b/polaris-react/playground/Playground.tsx index 355f6b984f2..66d7a594fb0 100644 --- a/polaris-react/playground/Playground.tsx +++ b/polaris-react/playground/Playground.tsx @@ -2,10 +2,12 @@ import React from 'react'; import {Page} from '../src'; -export function Playground() { - return ( - - {/* Add the code you want to test in here */} - - ); -} +export const Playground = { + render() { + return ( + + {/* Add the code you want to test in here */} + + ); + }, +}; diff --git a/polaris-react/src/components/AccountConnection/AccountConnection.stories.tsx b/polaris-react/src/components/AccountConnection/AccountConnection.stories.tsx index 710fc297ca2..111dc0fe43b 100644 --- a/polaris-react/src/components/AccountConnection/AccountConnection.stories.tsx +++ b/polaris-react/src/components/AccountConnection/AccountConnection.stories.tsx @@ -1,87 +1,95 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {AccountConnection, Box, Link, Text, BlockStack} from '@shopify/polaris'; export default { component: AccountConnection, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - <> - - - Default - - - - - - - With account connected - - - - - - ); -} +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + <> + + + Default + + + + + + + With account connected + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function Default() { - const [connected, setConnected] = useState(false); - const accountName = connected ? 'Olive Eight' : ''; +export const Default = { + render() { + const [connected, setConnected] = useState(false); + const accountName = connected ? 'Olive Eight' : ''; - const handleAction = useCallback(() => { - setConnected((connected) => !connected); - }, []); + const handleAction = useCallback(() => { + setConnected((connected) => !connected); + }, []); - const buttonText = connected ? 'Disconnect' : 'Connect'; - const details = connected ? 'Account connected' : 'No account connected'; + const buttonText = connected ? 'Disconnect' : 'Connect'; + const details = connected ? 'Account connected' : 'No account connected'; - const terms = connected ? null : ( - - By clicking Connect, you agree to accept Sample App’s{' '} - terms and conditions. You’ll pay a - commission rate of 15% on sales made through Sample App. - - ); + const terms = connected ? null : ( + + By clicking Connect, you agree to accept Sample App’s{' '} + terms and conditions. You’ll pay a + commission rate of 15% on sales made through Sample App. + + ); - return ( - - ); -} + return ( + + ); + }, +}; -export function WithAccountConnected() { - const [connected, setConnected] = useState(true); - const accountName = connected ? 'Olive Eight' : ''; +export const WithAccountConnected = { + render() { + const [connected, setConnected] = useState(true); + const accountName = connected ? 'Olive Eight' : ''; - const handleAction = useCallback(() => { - setConnected((connected) => !connected); - }, []); + const handleAction = useCallback(() => { + setConnected((connected) => !connected); + }, []); - const buttonText = connected ? 'Disconnect' : 'Connect'; - const details = connected ? 'Account connected' : 'No account connected'; + const buttonText = connected ? 'Disconnect' : 'Connect'; + const details = connected ? 'Account connected' : 'No account connected'; - return ( - - ); -} + return ( + + ); + }, +}; diff --git a/polaris-react/src/components/ActionList/ActionList.stories.tsx b/polaris-react/src/components/ActionList/ActionList.stories.tsx index 50001cb9312..78cb9e01627 100644 --- a/polaris-react/src/components/ActionList/ActionList.stories.tsx +++ b/polaris-react/src/components/ActionList/ActionList.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { ActionList, Avatar, @@ -23,389 +23,411 @@ import { export default { component: ActionList, -} as ComponentMeta; - -export function All() { - return ( - - - - - - - - - - - ); -} - -export function InAPopover() { - const [active, setActive] = useState(true); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const handleImportedAction = useCallback( - () => console.log('Imported action'), - [], - ); - - const handleExportedAction = useCallback( - () => console.log('Exported action'), - [], - ); - - const activator = ( - - ); - - return ( -
- - - -
- ); -} - -export function WithIconsOrImage() { - const [active, setActive] = useState(true); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const activator = ( - - ); - - return ( -
- - - -
- ); -} - -export function WithAnIconAndASuffix() { - const [active, setActive] = useState(true); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const activator = ( - - ); - - return ( -
- -
+} as Meta; + +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; + +export const InAPopover = { + render() { + const [active, setActive] = useState(true); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const handleImportedAction = useCallback( + () => console.log('Imported action'), + [], + ); + + const handleExportedAction = useCallback( + () => console.log('Exported action'), + [], + ); + + const activator = ( + + ); + + return ( +
+ , - }, - {content: 'Export file', icon: ExportIcon}, - { - content: 'Manage your blog articles', - icon: ImportIcon, - suffix: , + onAction: handleImportedAction, }, { - content: `Manage uploaded images`, - icon: ImportIcon, - suffix: , - truncate: true, - }, - { - disabled: true, - content: 'Disable file', - icon: ImportIcon, - suffix: , + content: 'Export file', + onAction: handleExportedAction, }, ]} /> -
- -
- ); -} - -export function WithSections() { - const [active, setActive] = useState(true); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const activator = ( - - ); - - return ( -
- - - -
- ); -} - -export function WithSectionsNoTitles() { - const [active, setActive] = useState(true); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const activator = ( - - ); - - return ( -
- - - -
- ); -} - -export function WithDestructiveItem() { - const [active, setActive] = useState(true); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const activator = ( - - ); - - return ( -
- - +
+ ); + }, +}; + +export const WithIconsOrImage = { + render() { + const [active, setActive] = useState(true); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const activator = ( + + ); + + return ( +
+ + + +
+ ); + }, +}; + +export const WithAnIconAndASuffix = { + render() { + const [active, setActive] = useState(true); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const activator = ( + + ); + + return ( +
+ +
+ , }, {content: 'Export file', icon: ExportIcon}, { - destructive: true, - content: 'Delete file', - icon: DeleteIcon, - }, - ], - }, - ]} - /> - -
- ); -} - -export function WithHelpText() { - const [active, setActive] = useState(true); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const activator = ( - - ); - - return ( -
- - , }, { - active: true, - content: 'Active blogs', - helpText: 'This is helpful text', + content: `Manage uploaded images`, icon: ImportIcon, suffix: , + truncate: true, }, { disabled: true, - content: 'Disabled blogs', - helpText: 'This is also helpful text', + content: 'Disable file', icon: ImportIcon, suffix: , }, - ], + ]} + /> +
+
+
+ ); + }, +}; + +export const WithSections = { + render() { + const [active, setActive] = useState(true); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const activator = ( + + ); + + return ( +
+ + + +
+ ); + }, +}; + +export const WithSectionsNoTitles = { + render() { + const [active, setActive] = useState(true); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const activator = ( + + ); + + return ( +
+ + + +
+ ); + }, +}; + +export const WithDestructiveItem = { + render() { + const [active, setActive] = useState(true); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const activator = ( + + ); + + return ( +
+ + + +
+ ); + }, +}; + +export const WithHelpText = { + render() { + const [active, setActive] = useState(true); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const activator = ( + + ); + + return ( +
+ + , + }, + { + disabled: true, + content: 'Disabled blogs', + helpText: 'This is also helpful text', + icon: ImportIcon, + suffix: , + }, + ], + }, + ]} + /> + +
+ ); + }, +}; + +export const WithAPrefixAndASuffix = { + render() { + return ( +
+ + ), + suffix: , + }, + { + content: 'Or there', + prefix: , + suffix: , }, ]} /> - -
- ); -} - -export function WithAPrefixAndASuffix() { - return ( -
- - ), - suffix: , - }, - { - content: 'Or there', - prefix: , - suffix: , - }, - ]} - /> -
- ); -} - -export function WithFiltering() { - return ( -
- ({ - content: `Item #${index + 1}`, - }))} - /> -
- ); -} +
+ ); + }, +}; + +export const WithFiltering = { + render() { + return ( +
+ ({ + content: `Item #${index + 1}`, + }))} + /> +
+ ); + }, +}; diff --git a/polaris-react/src/components/AppProvider/AppProvider.stories.tsx b/polaris-react/src/components/AppProvider/AppProvider.stories.tsx index 40ce18942b3..bd4954bd6f7 100644 --- a/polaris-react/src/components/AppProvider/AppProvider.stories.tsx +++ b/polaris-react/src/components/AppProvider/AppProvider.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { AppProvider, Avatar, @@ -13,153 +13,159 @@ export default { component: AppProvider, args: {omitAppProvider: true}, parameters: {layout: 'fullscreen'}, -} as ComponentMeta; +} as Meta; -export function Default(_, context) { - return ( - - - - { - const {id, url, name, location} = item; - const media = ; + }} + > + + + { + const {id, url, name, location} = item; + const media = ; - return ( - - - {name} - - - {location} - - - ); - }} - /> - - - - ); -} + return ( + + + {name} + + + {location} + + + ); + }} + /> + + + + ); + }, +}; -export function WithI18n() { - return ( - - - - { - const {id, url, name, location} = item; - const media = ; + }, + }, + }} + > + + + { + const {id, url, name, location} = item; + const media = ; - return ( - - - {name} - - - {location} - - - ); - }} - /> - - - - ); -} + return ( + + + {name} + + + {location} + + + ); + }} + /> + + + + ); + }, +}; + +export const WithLinkComponent = { + render(_, context) { + // We can do this because the AppProviderDecorator wraps all Stories, even AppProvider.stories.tsx + const CustomLinkComponent = ({children, url, ...rest}) => { + return ( + console.log('Custom link clicked')} + {...rest} + > + {children} + + ); + }; -export function WithLinkComponent(_, context) { - // We can do this because the AppProviderDecorator wraps all Stories, even AppProvider.stories.tsx - const CustomLinkComponent = ({children, url, ...rest}) => { return ( - console.log('Custom link clicked')} - {...rest} - > - {children} - + + + + Page content + + + ); - }; - - return ( - - - - Page content - - - - ); -} + }, +}; diff --git a/polaris-react/src/components/Autocomplete/Autocomplete.stories.tsx b/polaris-react/src/components/Autocomplete/Autocomplete.stories.tsx index e2029f614c1..e70ba83803a 100644 --- a/polaris-react/src/components/Autocomplete/Autocomplete.stories.tsx +++ b/polaris-react/src/components/Autocomplete/Autocomplete.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useMemo, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Autocomplete, Icon, @@ -11,842 +11,860 @@ import {PlusCircleIcon, DeleteIcon, SearchIcon} from '@shopify/polaris-icons'; export default { component: Autocomplete, -} as ComponentMeta; - -export function Default() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } - - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const updateSelection = useCallback( - (selected) => { - const selectedValue = selected.map((selectedItem) => { - const matchedOption = options.find((option) => { - return option.value.match(selectedItem); - }); - return matchedOption && matchedOption.label; - }); - - setSelectedOptions(selected); - setInputValue(selectedValue[0]); - }, - [options], - ); - - const textField = ( - } - placeholder="Search" - /> - ); - - return ( -
- -
- ); -} - -export function WithMultipleTags() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState(['rustic']); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } - - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - let endIndex = resultOptions.length - 1; - if (resultOptions.length === 0) { - endIndex = 0; - } - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const handleSelect = useCallback( - (selected) => { - setSelectedOptions(selected); - updateText(''); - }, - [updateText], - ); - - const removeTag = useCallback( - (tag) => (event) => { - event.stopPropagation(); - const options = [...selectedOptions]; - options.splice(options.indexOf(tag), 1); - setSelectedOptions(options); - }, - [selectedOptions], - ); - - const verticalContentMarkup = - selectedOptions.length > 0 ? ( - - {selectedOptions.map((option) => { - let tagLabel = ''; - tagLabel = option.replace('_', ' '); - tagLabel = titleCase(tagLabel); - return ( - - {tagLabel} - - ); - })} - - ) : null; - - const textField = ( - - ); - - return ( -
- -
- ); - - function titleCase(string) { - return string - .toLowerCase() - .split(' ') - .map((word) => word.replace(word[0], word[0].toUpperCase())) - .join(''); - } -} - -export function WithMultipleSections() { - const deselectedOptions = useMemo( - () => [ - { - title: 'Frequently used', - options: [ - {value: 'ups', label: 'UPS'}, - {value: 'usps', label: 'USPS'}, - ], - }, - { - title: 'All carriers', - options: [ - {value: 'dhl', label: 'DHL Express'}, - {value: 'canada_post', label: 'Canada Post'}, - ], - }, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } - - const filterRegex = new RegExp(value, 'i'); - const resultOptions = []; - - deselectedOptions.forEach((opt) => { - const lol = opt.options.filter((option) => - option.label.match(filterRegex), - ); - - resultOptions.push({ - title: opt.title, - options: lol, - }); - }); - - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const updateSelection = useCallback( - ([selected]) => { - let selectedValue; - - options.forEach(({options: opt}) => { - if (selectedValue) { - return; - } - - const matchedOption = opt.find((option) => - option.value.match(selected), - ); - - if (matchedOption) { - selectedValue = matchedOption.label; - } - }); - - setSelectedOptions([selected]); - setInputValue(String(selectedValue) ? String(selectedValue) : ''); - }, - [options], - ); - - const textField = ( - } - placeholder="Search" - /> - ); - - return ( -
- -
- ); -} - -export function WithLoading() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - const [loading, setLoading] = useState(false); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (!loading) { - setLoading(true); - } +} as Meta; + +export const Default = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); - setTimeout(() => { if (value === '') { setOptions(deselectedOptions); - setLoading(false); return; } + const filterRegex = new RegExp(value, 'i'); const resultOptions = deselectedOptions.filter((option) => option.label.match(filterRegex), ); setOptions(resultOptions); - setLoading(false); - }, 300); - }, - [deselectedOptions, loading], - ); - - const updateSelection = useCallback( - (selected) => { - const selectedText = selected.map((selectedItem) => { - const matchedOption = options.find((option) => { - return option.value.match(selectedItem); + }, + [deselectedOptions], + ); + + const updateSelection = useCallback( + (selected) => { + const selectedValue = selected.map((selectedItem) => { + const matchedOption = options.find((option) => { + return option.value.match(selectedItem); + }); + return matchedOption && matchedOption.label; }); - return matchedOption && matchedOption.label; - }); - setSelectedOptions(selected); - setInputValue(selectedText[0]); - }, - [options], - ); - - const textField = ( - } - placeholder="Search" - /> - ); - - return ( -
- -
- ); -} - -export function WithLazyLoading() { - const paginationInterval = 25; - const deselectedOptions = Array.from(Array(100)).map((_, index) => ({ - value: `rustic ${index + 1}`, - label: `Rustic ${index + 1}`, - })); - - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - const [isLoading, setIsLoading] = useState(false); - const [willLoadMoreResults, setWillLoadMoreResults] = useState(true); - const [visibleOptionIndex, setVisibleOptionIndex] = - useState(paginationInterval); - - const handleLoadMoreResults = useCallback(() => { - if (willLoadMoreResults) { - setIsLoading(true); - - setTimeout(() => { - const remainingOptionCount = options.length - visibleOptionIndex; - const nextVisibleOptionIndex = - remainingOptionCount >= paginationInterval - ? visibleOptionIndex + paginationInterval - : visibleOptionIndex + remainingOptionCount; - - setIsLoading(false); - setVisibleOptionIndex(nextVisibleOptionIndex); - - if (remainingOptionCount <= paginationInterval) { - setWillLoadMoreResults(false); - } - }, 1000); - } - }, [willLoadMoreResults, visibleOptionIndex, options.length]); - - const removeTag = useCallback( - (tag) => () => { - const options = [...selectedOptions]; - options.splice(options.indexOf(tag), 1); - setSelectedOptions(options); - }, - [selectedOptions], - ); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - - let endIndex = resultOptions.length - 1; - if (resultOptions.length === 0) { - endIndex = 0; - } - setOptions(resultOptions); - setInputValue; - }, - [deselectedOptions], - ); - - const textField = ( - - ); - - const hasSelectedOptions = selectedOptions.length > 0; - - const tagsMarkup = hasSelectedOptions - ? selectedOptions.map((option) => { - let tagLabel = ''; - tagLabel = option.replace('_', ' '); - tagLabel = titleCase(tagLabel); - return ( - - {tagLabel} - - ); - }) - : null; - const optionList = options.slice(0, visibleOptionIndex); - const selectedTagMarkup = hasSelectedOptions ? ( - {tagsMarkup} - ) : null; - - return ( - - {selectedTagMarkup} - } + placeholder="Search" /> - - ); - - function titleCase(string) { - return string - .toLowerCase() - .split(' ') - .map((word) => { - return word.replace(word[0], word[0].toUpperCase()); - }) - .join(' '); - } -} - -export function WithEmptyState() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - const [loading, setLoading] = useState(false); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (!loading) { - setLoading(true); - } + ); + + return ( +
+ +
+ ); + }, +}; + +export const WithMultipleTags = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState(['rustic']); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); - setTimeout(() => { if (value === '') { setOptions(deselectedOptions); - setLoading(false); return; } + const filterRegex = new RegExp(value, 'i'); const resultOptions = deselectedOptions.filter((option) => option.label.match(filterRegex), ); + let endIndex = resultOptions.length - 1; + if (resultOptions.length === 0) { + endIndex = 0; + } setOptions(resultOptions); - setLoading(false); - }, 300); - }, - [deselectedOptions, loading], - ); - - const updateSelection = useCallback( - (selected) => { - const selectedText = selected.map((selectedItem) => { - const matchedOption = options.find((option) => { - return option.value.match(selectedItem); - }); - return matchedOption && matchedOption.label; - }); - setSelectedOptions(selected); - setInputValue(selectedText[0]); - }, - [options], - ); - - const textField = ( - } - placeholder="Search" - /> - ); - - const emptyState = ( - <> - -
- Could not find any results -
- - ); - - return ( -
- { + setSelectedOptions(selected); + updateText(''); + }, + [updateText], + ); + + const removeTag = useCallback( + (tag) => (event) => { + event.stopPropagation(); + const options = [...selectedOptions]; + options.splice(options.indexOf(tag), 1); + setSelectedOptions(options); + }, + [selectedOptions], + ); + + const verticalContentMarkup = + selectedOptions.length > 0 ? ( + + {selectedOptions.map((option) => { + let tagLabel = ''; + tagLabel = option.replace('_', ' '); + tagLabel = titleCase(tagLabel); + return ( + + {tagLabel} + + ); + })} + + ) : null; + + const textField = ( + -
- ); -} - -export function WithAction() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - const [loading, setLoading] = useState(false); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (!loading) { - setLoading(true); - } + ); + + return ( +
+ +
+ ); + + function titleCase(string) { + return string + .toLowerCase() + .split(' ') + .map((word) => word.replace(word[0], word[0].toUpperCase())) + .join(''); + } + }, +}; + +export const WithMultipleSections = { + render() { + const deselectedOptions = useMemo( + () => [ + { + title: 'Frequently used', + options: [ + {value: 'ups', label: 'UPS'}, + {value: 'usps', label: 'USPS'}, + ], + }, + { + title: 'All carriers', + options: [ + {value: 'dhl', label: 'DHL Express'}, + {value: 'canada_post', label: 'Canada Post'}, + ], + }, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); - setTimeout(() => { if (value === '') { setOptions(deselectedOptions); - setLoading(false); return; } + const filterRegex = new RegExp(value, 'i'); - const resultOptions = options.filter((option) => - option.label.match(filterRegex), - ); + const resultOptions = []; + + deselectedOptions.forEach((opt) => { + const lol = opt.options.filter((option) => + option.label.match(filterRegex), + ); + + resultOptions.push({ + title: opt.title, + options: lol, + }); + }); + setOptions(resultOptions); - setLoading(false); - }, 300); - }, - [deselectedOptions, loading, options], - ); - - const updateSelection = useCallback( - (selected) => { - const selectedText = selected.map((selectedItem) => { - const matchedOption = options.find((option) => { - return option.value.match(selectedItem); + }, + [deselectedOptions], + ); + + const updateSelection = useCallback( + ([selected]) => { + let selectedValue; + + options.forEach(({options: opt}) => { + if (selectedValue) { + return; + } + + const matchedOption = opt.find((option) => + option.value.match(selected), + ); + + if (matchedOption) { + selectedValue = matchedOption.label; + } }); - return matchedOption && matchedOption.label; - }); - setSelectedOptions(selected); - setInputValue(selectedText[0]); - }, - [options], - ); - - const textField = ( - } - placeholder="Search" - /> - ); - - return ( -
- { - console.log('actionBefore clicked!'); - }, - }} - options={options} - selected={selectedOptions} - onSelect={updateSelection} - listTitle="Suggested tags" - loading={loading} - textField={textField} + + setSelectedOptions([selected]); + setInputValue(String(selectedValue) ? String(selectedValue) : ''); + }, + [options], + ); + + const textField = ( + } + placeholder="Search" /> -
- ); -} - -export function WithWrappingAction() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - const [loading, setLoading] = useState(false); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (!loading) { - setLoading(true); + ); + + return ( +
+ +
+ ); + }, +}; + +export const WithLoading = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + const [loading, setLoading] = useState(false); + + const updateText = useCallback( + (value) => { + setInputValue(value); + + if (!loading) { + setLoading(true); + } + + setTimeout(() => { + if (value === '') { + setOptions(deselectedOptions); + setLoading(false); + return; + } + const filterRegex = new RegExp(value, 'i'); + const resultOptions = deselectedOptions.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); + setLoading(false); + }, 300); + }, + [deselectedOptions, loading], + ); + + const updateSelection = useCallback( + (selected) => { + const selectedText = selected.map((selectedItem) => { + const matchedOption = options.find((option) => { + return option.value.match(selectedItem); + }); + return matchedOption && matchedOption.label; + }); + setSelectedOptions(selected); + setInputValue(selectedText[0]); + }, + [options], + ); + + const textField = ( + } + placeholder="Search" + /> + ); + + return ( +
+ +
+ ); + }, +}; + +export const WithLazyLoading = { + render() { + const paginationInterval = 25; + const deselectedOptions = Array.from(Array(100)).map((_, index) => ({ + value: `rustic ${index + 1}`, + label: `Rustic ${index + 1}`, + })); + + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + const [isLoading, setIsLoading] = useState(false); + const [willLoadMoreResults, setWillLoadMoreResults] = useState(true); + const [visibleOptionIndex, setVisibleOptionIndex] = + useState(paginationInterval); + + const handleLoadMoreResults = useCallback(() => { + if (willLoadMoreResults) { + setIsLoading(true); + + setTimeout(() => { + const remainingOptionCount = options.length - visibleOptionIndex; + const nextVisibleOptionIndex = + remainingOptionCount >= paginationInterval + ? visibleOptionIndex + paginationInterval + : visibleOptionIndex + remainingOptionCount; + + setIsLoading(false); + setVisibleOptionIndex(nextVisibleOptionIndex); + + if (remainingOptionCount <= paginationInterval) { + setWillLoadMoreResults(false); + } + }, 1000); } + }, [willLoadMoreResults, visibleOptionIndex, options.length]); + + const removeTag = useCallback( + (tag) => () => { + const options = [...selectedOptions]; + options.splice(options.indexOf(tag), 1); + setSelectedOptions(options); + }, + [selectedOptions], + ); + + const updateText = useCallback( + (value) => { + setInputValue(value); - setTimeout(() => { if (value === '') { setOptions(deselectedOptions); - setLoading(false); return; } + const filterRegex = new RegExp(value, 'i'); - const resultOptions = options.filter((option) => + const resultOptions = deselectedOptions.filter((option) => option.label.match(filterRegex), ); + + let endIndex = resultOptions.length - 1; + if (resultOptions.length === 0) { + endIndex = 0; + } setOptions(resultOptions); - setLoading(false); - }, 300); - }, - [deselectedOptions, loading, options], - ); - - const updateSelection = useCallback( - (selected) => { - const selectedText = selected.map((selectedItem) => { - const matchedOption = options.find((option) => { - return option.value.match(selectedItem); + setInputValue; + }, + [deselectedOptions], + ); + + const textField = ( + + ); + + const hasSelectedOptions = selectedOptions.length > 0; + + const tagsMarkup = hasSelectedOptions + ? selectedOptions.map((option) => { + let tagLabel = ''; + tagLabel = option.replace('_', ' '); + tagLabel = titleCase(tagLabel); + return ( + + {tagLabel} + + ); + }) + : null; + const optionList = options.slice(0, visibleOptionIndex); + const selectedTagMarkup = hasSelectedOptions ? ( + {tagsMarkup} + ) : null; + + return ( + + {selectedTagMarkup} + + + ); + + function titleCase(string) { + return string + .toLowerCase() + .split(' ') + .map((word) => { + return word.replace(word[0], word[0].toUpperCase()); + }) + .join(' '); + } + }, +}; + +export const WithEmptyState = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + const [loading, setLoading] = useState(false); + + const updateText = useCallback( + (value) => { + setInputValue(value); + + if (!loading) { + setLoading(true); + } + + setTimeout(() => { + if (value === '') { + setOptions(deselectedOptions); + setLoading(false); + return; + } + const filterRegex = new RegExp(value, 'i'); + const resultOptions = deselectedOptions.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); + setLoading(false); + }, 300); + }, + [deselectedOptions, loading], + ); + + const updateSelection = useCallback( + (selected) => { + const selectedText = selected.map((selectedItem) => { + const matchedOption = options.find((option) => { + return option.value.match(selectedItem); + }); + return matchedOption && matchedOption.label; }); - return matchedOption && matchedOption.label; - }); - setSelectedOptions(selected); - setInputValue(selectedText[0]); - }, - [options], - ); - - const textField = ( - } - placeholder="Search" - /> - ); - - return ( -
- { - console.log('actionBefore clicked!'); - }, - }} - options={options} - selected={selectedOptions} - onSelect={updateSelection} - listTitle="Suggested tags" - loading={loading} - textField={textField} + setSelectedOptions(selected); + setInputValue(selectedText[0]); + }, + [options], + ); + + const textField = ( + } + placeholder="Search" /> -
- ); -} - -export function WithDestructiveAction() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - const [loading, setLoading] = useState(false); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (!loading) { - setLoading(true); - } + ); + + const emptyState = ( + <> + +
+ Could not find any results +
+ + ); + + return ( +
+ +
+ ); + }, +}; + +export const WithAction = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + const [loading, setLoading] = useState(false); + + const updateText = useCallback( + (value) => { + setInputValue(value); + + if (!loading) { + setLoading(true); + } - setTimeout(() => { - if (value === '') { - setOptions(deselectedOptions); + setTimeout(() => { + if (value === '') { + setOptions(deselectedOptions); + setLoading(false); + return; + } + const filterRegex = new RegExp(value, 'i'); + const resultOptions = options.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); setLoading(false); - return; + }, 300); + }, + [deselectedOptions, loading, options], + ); + + const updateSelection = useCallback( + (selected) => { + const selectedText = selected.map((selectedItem) => { + const matchedOption = options.find((option) => { + return option.value.match(selectedItem); + }); + return matchedOption && matchedOption.label; + }); + setSelectedOptions(selected); + setInputValue(selectedText[0]); + }, + [options], + ); + + const textField = ( + } + placeholder="Search" + /> + ); + + return ( +
+ { + console.log('actionBefore clicked!'); + }, + }} + options={options} + selected={selectedOptions} + onSelect={updateSelection} + listTitle="Suggested tags" + loading={loading} + textField={textField} + /> +
+ ); + }, +}; + +export const WithWrappingAction = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + const [loading, setLoading] = useState(false); + + const updateText = useCallback( + (value) => { + setInputValue(value); + + if (!loading) { + setLoading(true); } - const filterRegex = new RegExp(value, 'i'); - const resultOptions = options.filter((option) => - option.label.match(filterRegex), - ); - setOptions(resultOptions); - setLoading(false); - }, 300); - }, - [deselectedOptions, loading, options], - ); - - const updateSelection = useCallback( - (selected) => { - const selectedText = selected.map((selectedItem) => { - const matchedOption = options.find((option) => { - return option.value.match(selectedItem); + + setTimeout(() => { + if (value === '') { + setOptions(deselectedOptions); + setLoading(false); + return; + } + const filterRegex = new RegExp(value, 'i'); + const resultOptions = options.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); + setLoading(false); + }, 300); + }, + [deselectedOptions, loading, options], + ); + + const updateSelection = useCallback( + (selected) => { + const selectedText = selected.map((selectedItem) => { + const matchedOption = options.find((option) => { + return option.value.match(selectedItem); + }); + return matchedOption && matchedOption.label; }); - return matchedOption && matchedOption.label; - }); - setSelectedOptions(selected); - setInputValue(selectedText[0]); - }, - [options], - ); - - const textField = ( - } - placeholder="Search" - /> - ); - - return ( -
- { - console.log('actionBefore clicked!'); - }, - }} - options={options} - selected={selectedOptions} - onSelect={updateSelection} - listTitle="Suggested tags" - loading={loading} - textField={textField} + setSelectedOptions(selected); + setInputValue(selectedText[0]); + }, + [options], + ); + + const textField = ( + } + placeholder="Search" /> -
- ); -} + ); + + return ( +
+ { + console.log('actionBefore clicked!'); + }, + }} + options={options} + selected={selectedOptions} + onSelect={updateSelection} + listTitle="Suggested tags" + loading={loading} + textField={textField} + /> +
+ ); + }, +}; + +export const WithDestructiveAction = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + const [loading, setLoading] = useState(false); + + const updateText = useCallback( + (value) => { + setInputValue(value); + + if (!loading) { + setLoading(true); + } + + setTimeout(() => { + if (value === '') { + setOptions(deselectedOptions); + setLoading(false); + return; + } + const filterRegex = new RegExp(value, 'i'); + const resultOptions = options.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); + setLoading(false); + }, 300); + }, + [deselectedOptions, loading, options], + ); + + const updateSelection = useCallback( + (selected) => { + const selectedText = selected.map((selectedItem) => { + const matchedOption = options.find((option) => { + return option.value.match(selectedItem); + }); + return matchedOption && matchedOption.label; + }); + setSelectedOptions(selected); + setInputValue(selectedText[0]); + }, + [options], + ); + + const textField = ( + } + placeholder="Search" + /> + ); + + return ( +
+ { + console.log('actionBefore clicked!'); + }, + }} + options={options} + selected={selectedOptions} + onSelect={updateSelection} + listTitle="Suggested tags" + loading={loading} + textField={textField} + /> +
+ ); + }, +}; diff --git a/polaris-react/src/components/Avatar/Avatar.stories.tsx b/polaris-react/src/components/Avatar/Avatar.stories.tsx index d2d3b255fcc..33e617d754f 100644 --- a/polaris-react/src/components/Avatar/Avatar.stories.tsx +++ b/polaris-react/src/components/Avatar/Avatar.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import type {AvatarProps} from '@shopify/polaris'; import { ActionList, @@ -18,7 +18,7 @@ import type {STYLE_CLASSES} from './Avatar'; export default { component: Avatar, -} as ComponentMeta; +} as Meta; const sizes: NonNullable[] = [ 'xl', @@ -62,162 +62,178 @@ const styleInitialsLongEntries = Object.entries(styleInitialsLong) as Entries< typeof styleInitialsLong >; -export function All() { - return ( - - - - - - Default - - - {sizes.map((size) => ( - - ))} - - - - - With customer - - - {sizes.map((size) => ( - - ))} - - - - - With image - - - - - - - - With icon (all styles) - - - - - - With default initials (all styles) - - - - - - With long initials (all styles) - - - - - - With long and wide initials - +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + Default + {sizes.map((size) => ( - + ))} + + + With customer + + + {sizes.map((size) => ( + + ))} + + + + + With image + + + + + + + + With icon (all styles) + + + + + + With default initials (all styles) + + + + + + With long initials (all styles) + + + + + + With long and wide initials + + + + {sizes.map((size) => ( + + ))} + + + - - - - ); -} - -export function Default() { - return ; -} - -export function IconColorsSizes() { - return ( - - {styleInitialsDefaultEntries.map(([style, initials]) => ( - - {sizes.map((size) => ( - - ))} - - ))} - - ); -} - -export function InitialsColorsSizes() { - return ( - - {styleInitialsDefaultEntries.map(([style, initials]) => ( - - {sizes.map((size) => ( - - ))} - - ))} - - ); -} - -export function InitialsLong() { - return ( - - {styleInitialsLongEntries.map(([style, initialsLong]) => ( - - {sizes.map((size) => ( - - ))} - - ))} - - ); -} - -export function ExtraSmallInContext() { - const [active, setActive] = useState(true); - const toggleActive = useCallback(() => setActive((active) => !active), []); - const activator = ( - - ); - - return ( -
- - , - }, - { - content: 'Farrah Fawcett', - prefix: , - }, - ]} - /> - -
- ); -} - -export function Image() { - return ( - - {sizes.map((size) => ( - - ))} - - ); -} + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; + +export const Default = { + render() { + return ; + }, +}; + +export const IconColorsSizes = { + render() { + return ( + + {styleInitialsDefaultEntries.map(([style, initials]) => ( + + {sizes.map((size) => ( + + ))} + + ))} + + ); + }, +}; + +export const InitialsColorsSizes = { + render() { + return ( + + {styleInitialsDefaultEntries.map(([style, initials]) => ( + + {sizes.map((size) => ( + + ))} + + ))} + + ); + }, +}; + +export const InitialsLong = { + render() { + return ( + + {styleInitialsLongEntries.map(([style, initialsLong]) => ( + + {sizes.map((size) => ( + + ))} + + ))} + + ); + }, +}; + +export const ExtraSmallInContext = { + render() { + const [active, setActive] = useState(true); + const toggleActive = useCallback(() => setActive((active) => !active), []); + const activator = ( + + ); + + return ( +
+ + , + }, + { + content: 'Farrah Fawcett', + prefix: , + }, + ]} + /> + +
+ ); + }, +}; + +export const Image = { + render() { + return ( + + {sizes.map((size) => ( + + ))} + + ); + }, +}; diff --git a/polaris-react/src/components/Badge/Badge.stories.tsx b/polaris-react/src/components/Badge/Badge.stories.tsx index 902f2829d61..bdf08477d06 100644 --- a/polaris-react/src/components/Badge/Badge.stories.tsx +++ b/polaris-react/src/components/Badge/Badge.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import type {BadgeProps} from '@shopify/polaris'; import { Badge, @@ -14,71 +14,95 @@ import type {Entries} from '../../types'; export default { component: Badge, -} as ComponentMeta; - -export function Default() { - return Fulfilled; -} - -export function Informational() { - return Draft; -} - -export function Success() { - return Active; -} - -export function Attention() { - return Open; -} - -export function Warning() { - return On hold; -} - -export function Critical() { - return Action required; -} - -export function New() { - return Fulfilled; -} - -export function Magic() { - return Magic; -} - -export function Incomplete() { - return ( - - Unfulfilled - - ); -} - -export function PartiallyComplete() { - return ( - - Partially fulfilled - - ); -} - -export function Complete() { - return Fulfilled; -} - -export function WithToneAndProgressLabelOverride() { - return ( - - Published - - ); -} +} as Meta; + +export const Default = { + render() { + return Fulfilled; + }, +}; + +export const Informational = { + render() { + return Draft; + }, +}; + +export const Success = { + render() { + return Active; + }, +}; + +export const Attention = { + render() { + return Open; + }, +}; + +export const Warning = { + render() { + return On hold; + }, +}; + +export const Critical = { + render() { + return Action required; + }, +}; + +export const New = { + render() { + return Fulfilled; + }, +}; + +export const Magic = { + render() { + return Magic; + }, +}; + +export const Incomplete = { + render() { + return ( + + Unfulfilled + + ); + }, +}; + +export const PartiallyComplete = { + render() { + return ( + + Partially fulfilled + + ); + }, +}; + +export const Complete = { + render() { + return Fulfilled; + }, +}; + +export const WithToneAndProgressLabelOverride = { + render() { + return ( + + Published + + ); + }, +}; const TempIcon = () => ( @@ -134,89 +158,91 @@ const sizes: { const sizeEntries = Object.entries(sizes) as Entries; -export function All() { - return ( - - {sizeEntries.map(([size, sizeLabel]) => ( - - - - Size: {sizeLabel} - - - - Tone only - - - {toneEntries.map(([tone, toneLabel]) => ( - - {toneLabel} - - ))} - - - - - Tone with progress +export const All = { + render() { + return ( + + {sizeEntries.map(([size, sizeLabel]) => ( + + + + Size: {sizeLabel} - {progressEntries.map(([progress]) => ( - + + + Tone only + + {toneEntries.map(([tone, toneLabel]) => ( {toneLabel} ))} - ))} - - {/* Remove `size` condition when micro icons are available */} - {size === 'large' && ( + - Tone with icon + Tone with progress + + {progressEntries.map(([progress]) => ( + + {toneEntries.map(([tone, toneLabel]) => ( + + {toneLabel} + + ))} + + ))} + + {/* Remove `size` condition when micro icons are available */} + {size === 'large' && ( + + + Tone with icon + + + {toneEntries.map(([tone, toneLabel]) => ( + + {toneLabel} + + ))} + + + )} + {/* TODO: Re-enable the following examples when designs are available (see https://github.com/Shopify/polaris-internal/issues/1411) */} + {/* + + Tone with icon only - {toneEntries.map(([tone, toneLabel]) => ( + {toneEntries.map(([tone]) => ( - {toneLabel} - + /> ))} - - )} - {/* TODO: Re-enable the following examples when designs are available (see https://github.com/Shopify/polaris-internal/issues/1411) */} - {/* - - Tone with icon only - - - {toneEntries.map(([tone]) => ( - - ))} - - */} - - - ))} - - ); -} + */} + + + ))} + + ); + }, +}; diff --git a/polaris-react/src/components/Banner/Banner.stories.tsx b/polaris-react/src/components/Banner/Banner.stories.tsx index 1c9aebb9355..dea590a5535 100644 --- a/polaris-react/src/components/Banner/Banner.stories.tsx +++ b/polaris-react/src/components/Banner/Banner.stories.tsx @@ -1,6 +1,6 @@ /* eslint-disable react/no-children-prop */ import React, {useCallback, useEffect, useRef, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { BlockStack, Banner, @@ -18,383 +18,327 @@ import {DiscountIcon} from '@shopify/polaris-icons'; export default { component: Banner, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - {}}> - - This order was archived on March 7, 2017 at 3:12pm EDT. - - - ); -} +export const Default = { + render() { + return ( + {}}> + + This order was archived on March 7, 2017 at 3:12pm EDT. + + + ); + }, +}; -export function Dismissible() { - return ( - {}}> - - Use your finance report to get detailed information about your business.{' '} - Let us know what you think - - - ); -} +export const Dismissible = { + render() { + return ( + {}}> + + Use your finance report to get detailed information about your + business. Let us know what you think + + + ); + }, +}; -export function WithFooterCallToAction() { - return ( - {}} - > - - Add weights to show accurate rates at checkout and when buying shipping - labels in Shopify. - - - ); -} +export const WithFooterCallToAction = { + render() { + return ( + {}} + > + + Add weights to show accurate rates at checkout and when buying + shipping labels in Shopify. + + + ); + }, +}; -export function Informational() { - return ( - {}} - > - - Make sure you know how these changes affect your store. - - - ); -} +export const Informational = { + render() { + return ( + {}} + > + + Make sure you know how these changes affect your store. + + + ); + }, +}; -export function Success() { - return ( - {}} - /> - ); -} +export const Success = { + render() { + return ( + {}} + /> + ); + }, +}; -export function Warning() { - return ( - - - - The name of the city you’re shipping to has characters that aren’t - allowed. City name can only include spaces and hyphens. - - - - ); -} +export const Warning = { + render() { + return ( + + + + The name of the city you’re shipping to has characters that aren’t + allowed. City name can only include spaces and hyphens. + + + + ); + }, +}; -export function Critical() { - return ( - - - Before fulfilling this order or capturing payment, please{' '} - review the Risk Analysis and determine if this order - is fraudulent. - - - ); -} +export const Critical = { + render() { + return ( + + + Before fulfilling this order or capturing payment, please{' '} + review the Risk Analysis and determine if this + order is fraudulent. + + + ); + }, +}; -export function InAModal() { - const [active, setActive] = useState(false); +export const InAModal = { + render() { + const [active, setActive] = useState(false); - const handleChange = useCallback(() => setActive(!active), [active]); + const handleChange = useCallback(() => setActive(!active), [active]); - return ( -
- - + + - - - + }} + secondaryActions={[ + { + content: 'Learn more', + onAction: handleChange, + }, + ]} + > + + + + + Connect your instagram account to your shop before proceeding. + + - Connect your instagram account to your shop before proceeding. + Use Instagram posts to share your products with millions of + people. Let shoppers buy from your store without leaving + Instagram. - - - Use Instagram posts to share your products with millions of - people. Let shoppers buy from your store without leaving - Instagram. - - - - -
- ); -} + + + + + ); + }, +}; -export function WithFocus() { - const banner = useRef(); +export const WithFocus = { + render() { + const banner = useRef(); - useEffect(() => banner.current.focus(), []); + useEffect(() => banner.current.focus(), []); - return ( - {}} - tone="critical" - ref={banner} - > - - Before fulfilling this order or capturing payment, please review the - fraud analysis and determine if this order is fraudulent - - - ); -} - -export function InACard() { - return ( - - - - Online store dashboard + return ( + {}} + tone="critical" + ref={banner} + > + + Before fulfilling this order or capturing payment, please review the + fraud analysis and determine if this order is fraudulent - {}}> - - Use your finance report to get detailed information about your - business. Let us know what you think - - - View a summary of your online store’s performance. - - - ); -} + + ); + }, +}; -export function InALegacyCard() { - return ( - - - {}}> - - Use your finance report to get detailed information about your - business. Let us know what you think +export const InACard = { + render() { + return ( + + + + Online store dashboard - + {}}> + + Use your finance report to get detailed information about your + business. Let us know what you think + + + View a summary of your online store’s performance. + + + ); + }, +}; - - View a summary of your online store’s performance. - - - - ); -} +export const InALegacyCard = { + render() { + return ( + + + {}}> + + Use your finance report to get detailed information about your + business. Let us know what you think + + -export function WithEndJustifiedContent() { - return ( - - - - - Deployment failed in 5min + + View a summary of your online store’s performance. - - Logs - - - - This order was archived on March 7, 2017 at 3:12pm EDT. - - - - ); -} + + + ); + }, +}; -export function HideIcon() { - return ( - - - - Changing the phone number for this customer will unsubscribe them from - SMS marketing text messages until they provide consent. - +export const WithEndJustifiedContent = { + render() { + return ( + + + + + Deployment failed in 5min + + + Logs + + + + This order was archived on March 7, 2017 at 3:12pm EDT. + + - - ); -} + ); + }, +}; -export function CustomIcon() { - return ( - - ); -} - -export function All() { - return ( - - - With dismiss and actions - - {}} - action={{content: 'Primary action'}} - secondaryAction={{content: 'Secondary action'}} - /> - - Default by status - - - - No title - - {}} - children={ - - Changing the phone number for this customer will unsubscribe them - from SMS marketing text messages until they provide consent. - - } - /> - - No title with actions - - +export const HideIcon = { + render() { + return ( + + + Changing the phone number for this customer will unsubscribe them from SMS marketing text messages until they provide consent. - } - /> - - No title with hidden icon - - {}} - children={ - <> - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim - ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut - aliquip ex ea commodo consequat. Duis aute irure dolor in - reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in - culpa qui officia deserunt mollit anim id est laborum. - - } - /> - - Only title - - {}} /> - - Hide icon - - {}} /> - - Custom icon - - {}} /> - - With links - - {}} - children={ - <> - Text with monochrome link. - - } + + + ); + }, +}; + +export const CustomIcon = { + render() { + return ( + - - In card - - + ); + }, +}; + +export const All = { + render() { + return ( + + + With dismiss and actions + + {}} + action={{content: 'Primary action'}} + secondaryAction={{content: 'Secondary action'}} + /> + + Default by status + - - - In card with dismiss - - - {}} /> - - - In card no title - - - {}} /> - - - In card no icon - - - {}} /> - - - In card custom icon - - - {}} /> - - - In card with links - - + + No title + {}} children={ - <> - Text with monochrome link. - + + Changing the phone number for this customer will unsubscribe them + from SMS marketing text messages until they provide consent. + } /> - - - In card with long text - - + + No title with actions + {}} title={undefined} + action={{content: 'Primary action'}} + secondaryAction={{content: 'Secondary action'}} + children={ + + Changing the phone number for this customer will unsubscribe them + from SMS marketing text messages until they provide consent. + + } + /> + + No title with hidden icon + + {}} children={ <> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do @@ -407,10 +351,96 @@ export function All() { } /> - - - ); -} + + Only title + + {}} /> + + Hide icon + + {}} /> + + Custom icon + + {}} /> + + With links + + {}} + children={ + <> + Text with monochrome link. + + } + /> + + In card + + + + + + In card with dismiss + + + {}} /> + + + In card no title + + + {}} /> + + + In card no icon + + + {}} /> + + + In card custom icon + + + {}} /> + + + In card with links + + + {}} + children={ + <> + Text with monochrome link. + + } + /> + + + In card with long text + + + {}} + title={undefined} + children={ + <> + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do + eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut + enim ad minim veniam, quis nostrud exercitation ullamco laboris + nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor + in reprehenderit in voluptate velit esse cillum dolore eu fugiat + nulla pariatur. Excepteur sint occaecat cupidatat non proident, + sunt in culpa qui officia deserunt mollit anim id est laborum. + + } + /> + + + ); + }, +}; function AllBanners(props) { return ( diff --git a/polaris-react/src/components/Bleed/Bleed.stories.tsx b/polaris-react/src/components/Bleed/Bleed.stories.tsx index 2611ee818cf..46b1be8c917 100644 --- a/polaris-react/src/components/Bleed/Bleed.stories.tsx +++ b/polaris-react/src/components/Bleed/Bleed.stories.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Card, Bleed, Box, Divider, LegacyStack, Text} from '@shopify/polaris'; export default { component: Bleed, -} as ComponentMeta; +} as Meta; const styles = { background: 'var(--p-color-bg-inverse)', @@ -13,143 +13,155 @@ const styles = { height: 'var(--p-space-1200)', }; -export function Default() { - return ( - - - - Section 01 - - - - - - - - Section 02 - - - - ); -} - -export function WithVerticalDirection() { - return ( - - -
- - - ); -} - -export function WithHorizontalDirection() { - return ( - - -
- - - ); -} +export const Default = { + render() { + return ( + + + + Section 01 + + + + + + + + Section 02 + + + + ); + }, +}; -export function WithSpecificDirection() { - return ( - - - Block Start - +export const WithVerticalDirection = { + render() { + return ( - +
- - Block End - + ); + }, +}; + +export const WithHorizontalDirection = { + render() { + return ( - +
- - Inline Start - + ); + }, +}; + +export const WithSpecificDirection = { + render() { + return ( + + + Block Start + + + +
+ + + + Block End + + + +
+ + + + Inline Start + + + +
+ + + + Inline End + + + +
+ + + + ); + }, +}; + +export const WithAllDirection = { + render() { + return ( - +
- - Inline End - + ); + }, +}; + +export const WithResponsiveHorizontalDirection = { + render() { + return ( - +
- - ); -} - -export function WithAllDirection() { - return ( - - -
- - - ); -} - -export function WithResponsiveHorizontalDirection() { - return ( - - -
- - - ); -} + ); + }, +}; diff --git a/polaris-react/src/components/BlockStack/BlockStack.stories.tsx b/polaris-react/src/components/BlockStack/BlockStack.stories.tsx index a522da09865..cfdcecb2d50 100644 --- a/polaris-react/src/components/BlockStack/BlockStack.stories.tsx +++ b/polaris-react/src/components/BlockStack/BlockStack.stories.tsx @@ -1,63 +1,15 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Box, BlockStack} from '@shopify/polaris'; export default { component: BlockStack, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - - 01 - - - 02 - - - 03 - - - ); -} - -export function WithGap() { - return ( - - - 01 - - - 02 - - - 03 - - - ); -} - -export function WithResponsiveGap() { - return ( - - - 01 - - - 02 - - - 03 - - - ); -} - -export function WithAlignStart() { - return ( -
- +export const Default = { + render() { + return ( + 01 @@ -68,14 +20,14 @@ export function WithAlignStart() { 03 -
- ); -} + ); + }, +}; -export function WithAlignCenter() { - return ( -
- +export const WithGap = { + render() { + return ( + 01 @@ -86,14 +38,14 @@ export function WithAlignCenter() { 03 -
- ); -} + ); + }, +}; -export function WithAlignEnd() { - return ( -
- +export const WithResponsiveGap = { + render() { + return ( + 01 @@ -104,14 +56,134 @@ export function WithAlignEnd() { 03 -
- ); -} + ); + }, +}; + +export const WithAlignStart = { + render() { + return ( +
+ + + 01 + + + 02 + + + 03 + + +
+ ); + }, +}; + +export const WithAlignCenter = { + render() { + return ( +
+ + + 01 + + + 02 + + + 03 + + +
+ ); + }, +}; + +export const WithAlignEnd = { + render() { + return ( +
+ + + 01 + + + 02 + + + 03 + + +
+ ); + }, +}; -export function WithAlignSpaceAround() { - return ( -
- +export const WithAlignSpaceAround = { + render() { + return ( +
+ + + 01 + + + 02 + + + 03 + + +
+ ); + }, +}; + +export const WithAlignSpaceBetween = { + render() { + return ( +
+ + + 01 + + + 02 + + + 03 + + +
+ ); + }, +}; + +export const WithAlignSpaceEvenly = { + render() { + return ( +
+ + + 01 + + + 02 + + + 03 + + +
+ ); + }, +}; + +export const WithInlineAlignStart = { + render() { + return ( + 01 @@ -122,14 +194,14 @@ export function WithAlignSpaceAround() { 03 -
- ); -} + ); + }, +}; -export function WithAlignSpaceBetween() { - return ( -
- +export const WithInlineAlignCenter = { + render() { + return ( + 01 @@ -140,14 +212,14 @@ export function WithAlignSpaceBetween() { 03 -
- ); -} + ); + }, +}; -export function WithAlignSpaceEvenly() { - return ( -
- +export const WithInlineAlignEnd = { + render() { + return ( + 01 @@ -158,54 +230,6 @@ export function WithAlignSpaceEvenly() { 03 -
- ); -} - -export function WithInlineAlignStart() { - return ( - - - 01 - - - 02 - - - 03 - - - ); -} - -export function WithInlineAlignCenter() { - return ( - - - 01 - - - 02 - - - 03 - - - ); -} - -export function WithInlineAlignEnd() { - return ( - - - 01 - - - 02 - - - 03 - - - ); -} + ); + }, +}; diff --git a/polaris-react/src/components/Box/Box.stories.tsx b/polaris-react/src/components/Box/Box.stories.tsx index b26f88c7323..a224170f428 100644 --- a/polaris-react/src/components/Box/Box.stories.tsx +++ b/polaris-react/src/components/Box/Box.stories.tsx @@ -1,255 +1,267 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {BlockStack, Text, Box, Icon} from '@shopify/polaris'; import {PaintBrushFlatIcon} from '@shopify/polaris-icons'; export default { component: Box, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - - - ); -} - -export function WithBorders() { - return ( - - - 1px solid border - - - 1px dashed border - - - 2px solid blue - - - 4px solid yellow - - - border-block-start: 4px solid red +export const Default = { + render() { + return ( + + - - border-width: 4px solid red - border-block-start: 1px solid red + ); + }, +}; + +export const WithBorders = { + render() { + return ( + + + 1px solid border + + + 1px dashed border + + + 2px solid blue + - border-width: 4px solid yellow - - Note: border-block-start will not inherit from the parent Box - component - + 4px solid yellow - - - 4px solid transparent - - - ); -} - -export function WithOutline() { - return ( - - - - - - - - - - - - - - - ); -} + + border-block-start: 4px solid red + + + border-width: 4px solid red + border-block-start: 1px solid red + + border-width: 4px solid yellow + + Note: border-block-start will not inherit from the parent Box + component + + + + + 4px solid transparent + + + ); + }, +}; -export function WithBorderRadius() { - return ( - - - - ); -} +export const WithOutline = { + render() { + return ( + + + + + + + + + + + + + + + ); + }, +}; -export function WithPadding() { - return ( - - - +export const WithBorderRadius = { + render() { + return ( + + - - - - - - - - - - - - - - - - - - - - ); -} + ); + }, +}; -export function WithResponsivePadding() { - return ( - - - - - - - - - - - - - - - - - - ); -} +export const WithPadding = { + render() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + ); + }, +}; + +export const WithResponsivePadding = { + render() { + return ( + + + + + + + + + + + + + + + + + + ); + }, +}; diff --git a/polaris-react/src/components/BulkActions/BulkActions.stories.tsx b/polaris-react/src/components/BulkActions/BulkActions.stories.tsx index 39e72293960..685da4c09ac 100644 --- a/polaris-react/src/components/BulkActions/BulkActions.stories.tsx +++ b/polaris-react/src/components/BulkActions/BulkActions.stories.tsx @@ -1,137 +1,141 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {DeleteIcon} from '@shopify/polaris-icons'; import {BulkActions} from './BulkActions'; export default { component: BulkActions, -} as ComponentMeta; +} as Meta; -export function Default() { - const promotedActions = [ - { - content: 'Capture payments', - onAction: () => console.log('Todo: implement payment capture'), - }, - { - title: 'Edit customers', - actions: [ - { - content: 'Add customers', - onAction: () => console.log('Todo: implement adding customers'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement deleting customers'), - }, - ], - }, - { - title: 'Export', - actions: [ - { - content: 'Export as PDF', - onAction: () => console.log('Todo: implement PDF exporting'), - }, - { - content: 'Export as CSV', - onAction: () => console.log('Todo: implement CSV exporting'), - }, - ], - }, - ]; - const actions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - return ( - console.log('toggling all')} - accessibilityLabel="Select all items" - selected={false} - promotedActions={promotedActions} - actions={actions} - /> - ); -} +export const Default = { + render() { + const promotedActions = [ + { + content: 'Capture payments', + onAction: () => console.log('Todo: implement payment capture'), + }, + { + title: 'Edit customers', + actions: [ + { + content: 'Add customers', + onAction: () => console.log('Todo: implement adding customers'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement deleting customers'), + }, + ], + }, + { + title: 'Export', + actions: [ + { + content: 'Export as PDF', + onAction: () => console.log('Todo: implement PDF exporting'), + }, + { + content: 'Export as CSV', + onAction: () => console.log('Todo: implement CSV exporting'), + }, + ], + }, + ]; + const actions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + return ( + console.log('toggling all')} + accessibilityLabel="Select all items" + selected={false} + promotedActions={promotedActions} + actions={actions} + /> + ); + }, +}; -export function WithDeprecatedProps() { - const promotedActions = [ - { - content: 'Capture payments', - onAction: () => console.log('Todo: implement payment capture'), - }, - { - title: 'Edit customers', - actions: [ - { - content: 'Add customers', - onAction: () => console.log('Todo: implement adding customers'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement deleting customers'), - }, - ], - }, - { - title: 'Export', - actions: [ - { - content: 'Export as PDF', - onAction: () => console.log('Todo: implement PDF exporting'), - }, - { - content: 'Export as CSV', - onAction: () => console.log('Todo: implement CSV exporting'), - }, - ], - }, - ]; - const actions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - return ( - console.log('toggling all')} - accessibilityLabel="Select all items" - selected={false} - promotedActions={promotedActions} - actions={actions} - isSticky - width={500} - /> - ); -} +export const WithDeprecatedProps = { + render() { + const promotedActions = [ + { + content: 'Capture payments', + onAction: () => console.log('Todo: implement payment capture'), + }, + { + title: 'Edit customers', + actions: [ + { + content: 'Add customers', + onAction: () => console.log('Todo: implement adding customers'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement deleting customers'), + }, + ], + }, + { + title: 'Export', + actions: [ + { + content: 'Export as PDF', + onAction: () => console.log('Todo: implement PDF exporting'), + }, + { + content: 'Export as CSV', + onAction: () => console.log('Todo: implement CSV exporting'), + }, + ], + }, + ]; + const actions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + return ( + console.log('toggling all')} + accessibilityLabel="Select all items" + selected={false} + promotedActions={promotedActions} + actions={actions} + isSticky + width={500} + /> + ); + }, +}; diff --git a/polaris-react/src/components/Button/Button.stories.tsx b/polaris-react/src/components/Button/Button.stories.tsx index bb34b309899..87964863a20 100644 --- a/polaris-react/src/components/Button/Button.stories.tsx +++ b/polaris-react/src/components/Button/Button.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useRef, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import type {TextProps} from '@shopify/polaris'; import { useCopyToClipboard, @@ -32,373 +32,592 @@ import { export default { component: Button, -} as ComponentMeta; - -export function All() { - const textProps: Pick = { - as: 'span', - fontWeight: 'bold', - }; - return ( - - Default - - Critical - - Primary - - Primary success - - Primary critical - - Tertiary - - Tertiary critical - - Plain - - Plain Critical - - Monochrome Plain - - Micro - - Slim - - Large - - Full width - - Text aligned - - Pressed - - Disclosure - - Right aligned disclosure - - Select disclosure - - Split - - Disabled state - - Loading state - - - ); -} - -export function Default() { - return ( - <> +} as Meta; + +export const All = { + render() { + const textProps: Pick = { + as: 'span', + fontWeight: 'bold', + }; + return ( + /* eslint-disable react/jsx-pascal-case */ + + Default + + Critical + + Primary + + Primary success + + Primary critical + + Tertiary + + Tertiary critical + + Plain + + Plain Critical + + Monochrome Plain + + Micro + + Slim + + Large + + Full width + + Text aligned + + Pressed + + Disclosure + + Right aligned disclosure + + Select disclosure + + Split + + Disabled state + + Loading state + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; + +export const Default = { + render() { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + - - - - - - - - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + - - + + - - - ; + }, +}; + +export const TextAligned = { + render() { + return ( + + - - - - - - - - - - - - - ; -} - -export function TextAligned() { - return ( - - - - ); -} - -export function Pressed() { - const [isFirstButtonActive, setIsFirstButtonActive] = useState(true); - - const handleFirstButtonClick = useCallback(() => { - if (isFirstButtonActive) return; - setIsFirstButtonActive(true); - }, [isFirstButtonActive]); - - const handleSecondButtonClick = useCallback(() => { - if (!isFirstButtonActive) return; - setIsFirstButtonActive(false); - }, [isFirstButtonActive]); - - return ( - - - - - ); -} - -export function PlainDisclosure() { - const [expanded, setExpanded] = useState(false); - - return ( - - ); -} - -export function RightAlignedDisclosure() { - const [expanded, setExpanded] = useState(false); - - return ( -
+ pressed={!isFirstButtonActive} + onClick={handleSecondButtonClick} + > + Second button + + + ); + }, +}; + +export const PlainDisclosure = { + render() { + const [expanded, setExpanded] = useState(false); + + return ( -
- ); -} - -export function SelectDisclosure() { - return ( -
- -
- ); -} - -export function Split() { - const [active, setActive] = React.useState(null); - - const toggleActive = (id: string) => () => { - setActive((activeId) => (activeId !== id ? id : null)); - }; - return ( -
- - - - - + +
+ ); + }, +}; + +export const SelectDisclosure = { + render() { + return ( +
+ +
+ ); + }, +}; + +export const Split = { + render() { + const [active, setActive] = React.useState(null); + + const toggleActive = (id: string) => () => { + setActive((activeId) => (activeId !== id ? id : null)); + }; + return ( +
+ + + + + + } + autofocusTarget="first-node" + onClose={toggleActive('popover1')} + > + - } - autofocusTarget="first-node" - onClose={toggleActive('popover1')} - > - - - - - - - - + + + + + + + } + autofocusTarget="first-node" + onClose={toggleActive('popover2')} + > + - } - autofocusTarget="first-node" - onClose={toggleActive('popover2')} - > - - - - -
- ); -} - -export function DisabledState() { - return ( - - - - - + + +
+
+ ); + }, +}; + +export const DisabledState = { + render() { + return ( + - - - - {/* Visual check to ensure the button color is not inherited from the parent */} - - - - - ); -} - -export function LoadingState() { - return ( - - - - - - ); -} - -export function CopyToClipboard() { - const [copy, status] = useCopyToClipboard({ - defaultValue: 'hello@example.com', - }); - - const ref = useRef(null); - const isFocusedIn = useFocusIn(ref); - const isHovered = useHover(ref); - const isMouseDevice = useMediaQuery('mouse'); - const isMouseHovered = isMouseDevice ? isHovered : true; - - return ( -
- -
- - hello@example.com -
- + Buy shipping label + + + + + + + {/* Visual check to ensure the button color is not inherited from the parent */} + + + + + ); + }, +}; + +export const LoadingState = { + render() { + return ( + + + + + + ); + }, +}; + +export const CopyToClipboard = { + render() { + const [copy, status] = useCopyToClipboard({ + defaultValue: 'hello@example.com', + }); + + const ref = useRef(null); + const isFocusedIn = useFocusIn(ref); + const isHovered = useHover(ref); + const isMouseDevice = useMediaQuery('mouse'); + const isMouseHovered = isMouseDevice ? isHovered : true; + + return ( +
+ +
+ + hello@example.com +
-
-
-
-
-
- ); -} + +
+
+
+
+
+ ); + }, +}; diff --git a/polaris-react/src/components/ButtonGroup/ButtonGroup.stories.tsx b/polaris-react/src/components/ButtonGroup/ButtonGroup.stories.tsx index daeb0965fb0..1e8f02ba9f8 100644 --- a/polaris-react/src/components/ButtonGroup/ButtonGroup.stories.tsx +++ b/polaris-react/src/components/ButtonGroup/ButtonGroup.stories.tsx @@ -1,196 +1,206 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Button, ButtonGroup, Icon, BlockStack, Text} from '@shopify/polaris'; import {DeleteIcon} from '@shopify/polaris-icons'; export default { component: ButtonGroup, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - - - - ); -} - -export function WithSegmentedButtons() { - const [activeButtonIndex, setActiveButtonIndex] = useState(0); - - const handleButtonClick = useCallback( - (index: number) => { - if (activeButtonIndex === index) return; - setActiveButtonIndex(index); - }, - [activeButtonIndex], - ); - return ( -
- - - - - + -
- - - - - - - - - - -
- - - - - -
- ); -} + ); + }, +}; -export function OutlineWithSegmentedButtons() { - return ( - - - - - - ); -} +export const WithSegmentedButtons = { + render() { + const [activeButtonIndex, setActiveButtonIndex] = useState(0); -export function WithAllGaps() { - return ( - - - - - - - - - - - - + const handleButtonClick = useCallback( + (index: number) => { + if (activeButtonIndex === index) return; + setActiveButtonIndex(index); + }, + [activeButtonIndex], + ); + return ( +
+ + + + + + + + + + + + + +
+ + + + + +
+ ); + }, +}; + +export const OutlineWithSegmentedButtons = { + render() { + return ( + -
- ); -} + ); + }, +}; -export function NoWrapButtons() { - return ( - <> - - Default - -
- - - - - - +export const WithAllGaps = { + render() { + return ( + + + + + -
-
- - With noWrap - -
- - - - - - + + + + -
- - ); -} + + + + + + + ); + }, +}; + +export const NoWrapButtons = { + render() { + return ( + <> + + Default + +
+ + + + + + + +
+
+ + With noWrap + +
+ + + + + + + +
+ + ); + }, +}; diff --git a/polaris-react/src/components/CalloutCard/CalloutCard.stories.tsx b/polaris-react/src/components/CalloutCard/CalloutCard.stories.tsx index e2e37450fd8..d9e05e83dc1 100644 --- a/polaris-react/src/components/CalloutCard/CalloutCard.stories.tsx +++ b/polaris-react/src/components/CalloutCard/CalloutCard.stories.tsx @@ -7,92 +7,102 @@ export default { component: CalloutCard, } as Meta; -export function Default() { - return ( - - - Upload your store’s logo, change colors and fonts, and more. - - - ); -} +export const Default = { + render() { + return ( + + + Upload your store’s logo, change colors and fonts, and more. + + + ); + }, +}; -export function WithSecondaryAction() { - return ( - - - Upload your store’s logo, change colors and fonts, and more. - - - ); -} +export const WithSecondaryAction = { + render() { + return ( + + + Upload your store’s logo, change colors and fonts, and more. + + + ); + }, +}; -export function Dismissable() { - return ( - {}} - > - - Upload your store’s logo, change colors and fonts, and more. - - - ); -} +export const Dismissable = { + render() { + return ( + {}} + > + + Upload your store’s logo, change colors and fonts, and more. + + + ); + }, +}; -export function WithCustomTitle() { - const customTitle = ( - <> - Customize the style of your checkout - New - - ); +export const WithCustomTitle = { + render() { + const customTitle = ( + <> + Customize the style of your checkout + New + + ); - return ( - - - Upload your store’s logo, change colors and fonts, and more. - - - ); -} + return ( + + + Upload your store’s logo, change colors and fonts, and more. + + + ); + }, +}; -export function WithIconableActions() { - return ( - - - How do you like our app? - - - ); -} +export const WithIconableActions = { + render() { + return ( + + + How do you like our app? + + + ); + }, +}; diff --git a/polaris-react/src/components/Card/Card.stories.tsx b/polaris-react/src/components/Card/Card.stories.tsx index 0afb1491a09..a003616a368 100644 --- a/polaris-react/src/components/Card/Card.stories.tsx +++ b/polaris-react/src/components/Card/Card.stories.tsx @@ -1,5 +1,5 @@ import React, {useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { ActionList, BlockStack, @@ -26,739 +26,783 @@ import { export default { component: Card, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - - - Online store dashboard - - - View a summary of your online store’s performance. - - - - ); -} - -export function WithResponsiveBorderRadius() { - return ( - - - - Online store dashboard - - - View a summary of your online store’s performance. - - - - ); -} - -export function WithResponsivePadding() { - return ( - - - - Online store dashboard - - - View a summary of your online store’s performance. - - - - ); -} - -export function WithSubdued() { - return ( - - - - Online store dashboard - - - View a summary of your online store’s performance. - - - - ); -} - -export function WithSubduedForSecondaryContent() { - return ( - - - - Deactivated staff accounts - - - Felix Crafford - Ezequiel Manno - - - - ); -} - -export function WithSection() { - return ( - - - Online store dashboard - - - - View a summary of your online store’s performance. - - - - ); -} - -export function WithSubduedSection() { - return ( - - - - Staff accounts - - - - Felix Crafford - Ezequiel Manno - - - - - - - - Deactivated staff accounts - - - Felix Crafford - Ezequiel Manno - - - - - - ); -} - -export function WithMultipleSections() { - return ( - - - Online store dashboard - - - - View a summary of your online store’s performance. - - - - - View a summary of your online store’s performance, including sales, - visitors, top products, and referrals. - - - - ); -} - -export function WithMultipleTitledSections() { - return ( - - - Online store dashboard - - +export const Default = { + render() { + return ( + - - Reports + + Online store dashboard View a summary of your online store’s performance. - - + + ); + }, +}; + +export const WithResponsiveBorderRadius = { + render() { + return ( + - - Summary + + Online store dashboard - View a summary of your online store’s performance, including sales, - visitors, top products, and referrals. + View a summary of your online store’s performance. -
- - ); -} - -export function WithSubsection() { - return ( - - - + + ); + }, +}; + +export const WithResponsivePadding = { + render() { + return ( + + - Customer + Online store dashboard - John Smith + View a summary of your online store’s performance. -
- - - Addresses - -
- - 123 First St - - - Somewhere - - - The Universe - -
-
- - 123 Second St - - - Somewhere - - - The Universe - -
-
-
-
+ + ); + }, +}; + +export const WithSubdued = { + render() { + return ( + + + + Online store dashboard + - A single subsection without a sibling has no visual appearance + View a summary of your online store’s performance. -
- -
- ); -} - -export function WithFlushedSection() { - return ( - - - a sheet with purple and orange stripes - - - - You can use sales reports to see information about your customers’ - orders based on criteria such as sales over time, by channel, or by - staff. + + + ); + }, +}; + +export const WithSubduedForSecondaryContent = { + render() { + return ( + + + + Deactivated staff accounts + + + Felix Crafford + Ezequiel Manno + + + + ); + }, +}; + +export const WithSection = { + render() { + return ( + + + Online store dashboard - - - ); -} - -export function WithFlushedSectionAndSubduedSection() { - return ( - - - a sheet with purple and orange stripes - + - You can use sales reports to see information about your customers’ - orders based on criteria such as sales over time, by channel, or by - staff. + View a summary of your online store’s performance. - - - ); -} - -export function WithSectionsAndActions() { - return ( - - + + ); + }, +}; + +export const WithSubduedSection = { + render() { + return ( + - Customer + Staff accounts + + + + Felix Crafford + Ezequiel Manno + + + + + + + + Deactivated staff accounts + + + Felix Crafford + Ezequiel Manno + + + + + + ); + }, +}; + +export const WithMultipleSections = { + render() { + return ( + + + Online store dashboard + + + + View a summary of your online store’s performance. + + - John Smith + View a summary of your online store’s performance, including sales, + visitors, top products, and referrals. - - - + + + ); + }, +}; + +export const WithMultipleTitledSections = { + render() { + return ( + + + Online store dashboard + + + - Contact Information + Reports - - ); - - const disclosureButton = ( - - - - ); - - return ( - - - - - Staff accounts - - - - {disclosureButton} - - - - Felix Crafford - Ezequiel Manno - - - - ); -} - -export function WithHeaderActions() { - return ( - - - - - Variants - - - - - Add variants if this product comes in multiple versions, like - different sizes or colors. - - - - ); -} - -export function WithFooterActions() { - return ( - - - - Shipment 1234 - + + ); + }, +}; + +export const WithSectionsAndCriticalAction = { + render() { + return ( + + + + + Customer + + + John Smith + + + + + + Contact Information + + + + ); + + const disclosureButton = ( + + + + ); + + return ( + - - Items - + + + Staff accounts + + + + {disclosureButton} + + - 1 × Oasis Glass, 4-Pack - 1 × Anubis Cup, 2-Pack + Felix Crafford + Ezequiel Manno - - - + + ); + }, +}; + +export const WithHeaderActions = { + render() { + return ( + + + + + Variants + - - - - - ); -} - -export function WithMultipleFooterActions() { - const [actionActive, toggleAction] = useState(false); - - const handleToggleAction = () => { - toggleAction(!actionActive); - }; - - const items = [ - {content: 'Cancel shipment', destructive: true}, - {content: 'Add another shipment', disabled: true}, - ]; - - const disclosureButtonActivator = ( - - ); - - const disclosureButton = ( - - - - ); - - return ( - - - - Shipment 1234 - - - - Items + + + Add variants if this product comes in multiple versions, like + different sizes or colors. - - 1 × Oasis Glass, 4-Pack - 1 × Anubis Cup, 2-Pack - - - - {disclosureButton} - - - - - - ); -} - -export function WithCustomFooterActions() { - return ( - - + + ); + }, +}; + +export const WithFooterActions = { + render() { + return ( + - Secure your account with 2-step authentication - - - Two-step authentication adds an extra layer of security when logging - in to your account. A special code will be required each time you - log in, ensuring only you can access your account. + Shipment 1234 + + + Items + + + 1 × Oasis Glass, 4-Pack + 1 × Anubis Cup, 2-Pack + + + + + + + + - - - - - - - - - ); -} - -export function WithCriticalFooterActions() { - return ( - - - - Shipment 1234 - + + ); + }, +}; + +export const WithMultipleFooterActions = { + render() { + const [actionActive, toggleAction] = useState(false); + + const handleToggleAction = () => { + toggleAction(!actionActive); + }; + + const items = [ + {content: 'Cancel shipment', destructive: true}, + {content: 'Add another shipment', disabled: true}, + ]; + + const disclosureButtonActivator = ( + + ); + + const disclosureButton = ( + + + + ); + + return ( + - - Items + + Shipment 1234 - - 1 × Oasis Glass, 4-Pack - 1 × Anubis Cup, 2-Pack - - - - - - - - - - - ); -} - -export function WithCustomReactNodeTitle() { - return ( - - - - Products - - - - - - New Products + + + Items + + 1 × Oasis Glass, 4-Pack + 1 × Anubis Cup, 2-Pack + + + + + {disclosureButton} + + - - Socks - Super Shoes - - - - ); -} - -export function WithAllElements() { - const [actionActive, toggleAction] = useState(false); - - const handleToggleAction = () => { - toggleAction(!actionActive); - }; - - const items = [{content: 'Gross Sales'}, {content: 'Net Sales'}]; - - const disclosureButtonActivator = ( - - ); - - const disclosureButton = ( - - - - ); - - const salesMarkup = ( -
- { - const {sales, amount, url} = item; - return ( - - -
{sales}
-
{amount}
-
-
- ); - }} - /> -
- ); - - return ( - - - - - Sales - - - - {disclosureButton} - - - - - You can use sales reports to see information about your customers’ - orders based on criteria such as sales over time, by channel, or by - staff. - - - Total Sales Breakdown - + + ); + }, +}; + +export const WithCustomFooterActions = { + render() { + return ( + + + + + Secure your account with 2-step authentication + + + Two-step authentication adds an extra layer of security when + logging in to your account. A special code will be required each + time you log in, ensuring only you can access your account. + + + + + + + + - {salesMarkup} - - - - - Deactivated reports - - - Payouts - Total Sales By Channel - - - - + + ); + }, +}; + +export const WithCriticalFooterActions = { + render() { + return ( + - - Note - - - The sales reports are available only if your store is on the Shopify - plan or higher. + + Shipment 1234 + + + Items + + + 1 × Oasis Glass, 4-Pack + 1 × Anubis Cup, 2-Pack + + - - - - ); -} + + ); + }, +}; + +export const WithCustomReactNodeTitle = { + render() { + return ( + + + + Products + + + + + + New Products + + + + + Socks + Super Shoes + + + + ); + }, +}; + +export const WithAllElements = { + render() { + const [actionActive, toggleAction] = useState(false); + + const handleToggleAction = () => { + toggleAction(!actionActive); + }; + + const items = [{content: 'Gross Sales'}, {content: 'Net Sales'}]; + + const disclosureButtonActivator = ( + + ); + + const disclosureButton = ( + + + + ); + + const salesMarkup = ( +
+ { + const {sales, amount, url} = item; + return ( + + +
{sales}
+
{amount}
+
+
+ ); + }} + /> +
+ ); + + return ( + + + + + Sales + + + + {disclosureButton} + + + + + You can use sales reports to see information about your customers’ + orders based on criteria such as sales over time, by channel, or + by staff. + + + Total Sales Breakdown + + + {salesMarkup} + + + + + Deactivated reports + + + Payouts + Total Sales By Channel + + + + + + + Note + + + The sales reports are available only if your store is on the + Shopify plan or higher. + + + + + + + + + + + ); + }, +}; diff --git a/polaris-react/src/components/Checkbox/Checkbox.stories.tsx b/polaris-react/src/components/Checkbox/Checkbox.stories.tsx index 522e71da3d6..547c9523727 100644 --- a/polaris-react/src/components/Checkbox/Checkbox.stories.tsx +++ b/polaris-react/src/components/Checkbox/Checkbox.stories.tsx @@ -1,153 +1,177 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Checkbox, InlineStack, BlockStack, Card} from '@shopify/polaris'; export default { component: Checkbox, -} as ComponentMeta; +} as Meta; type CheckboxState = boolean | 'indeterminate'; -export function Default() { - const [checked, setChecked] = useState(false); - const handleChange = useCallback((newChecked) => setChecked(newChecked), []); +export const Default = { + render() { + const [checked, setChecked] = useState(false); + const handleChange = useCallback( + (newChecked) => setChecked(newChecked), + [], + ); - return ( - - ); -} - -export function Indeterminate() { - const [checked, setChecked] = useState('indeterminate'); - const handleChange = useCallback((newChecked) => setChecked(newChecked), []); - - return ( - - ); -} - -export function DisabledStates() { - const handleChange = () => { - console.error('This should never be fired'); - }; - - return ( - + return ( - + ); + }, +}; + +export const Indeterminate = { + render() { + const [checked, setChecked] = useState('indeterminate'); + const handleChange = useCallback( + (newChecked) => setChecked(newChecked), + [], + ); + + return ( - - ); -} - -export function Error() { - const [checked, setChecked] = useState('indeterminate'); - const handleChange = useCallback((newChecked) => setChecked(newChecked), []); - - return ( - - ); -} - -export function Magic() { - const [checked, setChecked] = useState(); - const handleChange = useCallback((newChecked) => setChecked(newChecked), []); + ); + }, +}; - return ( - - ); -} +export const DisabledStates = { + render() { + const handleChange = () => { + console.error('This should never be fired'); + }; -export function WithBleedAndFill() { - const [checked1, setChecked1] = useState(false); - const [checked2, setChecked2] = useState(false); - const [checked3, setChecked3] = useState(false); - const [checked4, setChecked4] = useState(false); - const handleChange1 = useCallback( - (newChecked) => setChecked1(newChecked), - [], - ); - const handleChange2 = useCallback( - (newChecked) => setChecked2(newChecked), - [], - ); - const handleChange3 = useCallback( - (newChecked) => setChecked3(newChecked), - [], - ); - const handleChange4 = useCallback( - (newChecked) => setChecked4(newChecked), - [], - ); - return ( - - + return ( + - - - - -
+ + + ); + }, +}; + +export const Error = { + render() { + const [checked, setChecked] = useState('indeterminate'); + const handleChange = useCallback( + (newChecked) => setChecked(newChecked), + [], + ); + + return ( + + ); + }, +}; + +export const Magic = { + render() { + const [checked, setChecked] = useState(); + const handleChange = useCallback( + (newChecked) => setChecked(newChecked), + [], + ); + + return ( + + ); + }, +}; + +export const WithBleedAndFill = { + render() { + const [checked1, setChecked1] = useState(false); + const [checked2, setChecked2] = useState(false); + const [checked3, setChecked3] = useState(false); + const [checked4, setChecked4] = useState(false); + const handleChange1 = useCallback( + (newChecked) => setChecked1(newChecked), + [], + ); + const handleChange2 = useCallback( + (newChecked) => setChecked2(newChecked), + [], + ); + const handleChange3 = useCallback( + (newChecked) => setChecked3(newChecked), + [], + ); + const handleChange4 = useCallback( + (newChecked) => setChecked4(newChecked), + [], + ); + return ( + + + + + -
-
- - - -
- ); -} + + +
+ +
+
+ + + + + ); + }, +}; diff --git a/polaris-react/src/components/ChoiceList/ChoiceList.stories.tsx b/polaris-react/src/components/ChoiceList/ChoiceList.stories.tsx index e3c6424478b..3abd0099b73 100644 --- a/polaris-react/src/components/ChoiceList/ChoiceList.stories.tsx +++ b/polaris-react/src/components/ChoiceList/ChoiceList.stories.tsx @@ -1,188 +1,156 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {ChoiceList, TextField} from '@shopify/polaris'; export default { component: ChoiceList, -} as ComponentMeta; - -export function Default() { - const [selected, setSelected] = useState(['hidden']); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - ); -} - -export function WithError() { - const [selected, setSelected] = useState(['hidden']); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - ); -} - -export function Magic() { - const [selected, setSelected] = useState(['hidden']); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - ); -} - -export function WithMultiChoice() { - const [selected, setSelected] = useState(['hidden']); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - ); -} - -export function MagicWithMultiChoice() { - const [selected, setSelected] = useState(['hidden']); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - ); -} - -export function WithChildrenContent() { - const [selected, setSelected] = useState(['none']); - const [textFieldValue, setTextFieldValue] = useState(''); - - const handleChoiceListChange = useCallback((value) => setSelected(value), []); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - const renderChildren = useCallback( - () => ( - ; + +export const Default = { + render() { + const [selected, setSelected] = useState(['hidden']); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + - ), - [handleTextFieldChange, textFieldValue], - ); - - return ( - - ); -} - -export function WithDynamicChildrenContent() { - const [selected, setSelected] = useState(['none']); - const [textFieldValue, setTextFieldValue] = useState(''); - - const handleChoiceListChange = useCallback((value) => setSelected(value), []); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - const renderChildren = useCallback( - (isSelected) => - isSelected && ( + ); + }, +}; + +export const WithError = { + render() { + const [selected, setSelected] = useState(['hidden']); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + + ); + }, +}; + +export const Magic = { + render() { + const [selected, setSelected] = useState(['hidden']); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + + ); + }, +}; + +export const WithMultiChoice = { + render() { + const [selected, setSelected] = useState(['hidden']); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + + ); + }, +}; + +export const MagicWithMultiChoice = { + render() { + const [selected, setSelected] = useState(['hidden']); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + + ); + }, +}; + +export const WithChildrenContent = { + render() { + const [selected, setSelected] = useState(['none']); + const [textFieldValue, setTextFieldValue] = useState(''); + + const handleChoiceListChange = useCallback( + (value) => setSelected(value), + [], + ); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + const renderChildren = useCallback( + () => ( ), - [handleTextFieldChange, textFieldValue], - ); + [handleTextFieldChange, textFieldValue], + ); - return ( -
+ return ( -
- ); -} + ); + }, +}; + +export const WithDynamicChildrenContent = { + render() { + const [selected, setSelected] = useState(['none']); + const [textFieldValue, setTextFieldValue] = useState(''); + + const handleChoiceListChange = useCallback( + (value) => setSelected(value), + [], + ); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + const renderChildren = useCallback( + (isSelected) => + isSelected && ( + + ), + [handleTextFieldChange, textFieldValue], + ); + + return ( +
+ +
+ ); + }, +}; diff --git a/polaris-react/src/components/Collapsible/Collapsible.stories.tsx b/polaris-react/src/components/Collapsible/Collapsible.stories.tsx index d6785fe2cd6..cfa20808adc 100644 --- a/polaris-react/src/components/Collapsible/Collapsible.stories.tsx +++ b/polaris-react/src/components/Collapsible/Collapsible.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Button, LegacyCard, @@ -12,44 +12,46 @@ import { export default { component: Collapsible, -} as ComponentMeta; +} as Meta; -export function Default() { - const [open, setOpen] = useState(true); +export const Default = { + render() { + const [open, setOpen] = useState(true); - const handleToggle = useCallback(() => setOpen((open) => !open), []); + const handleToggle = useCallback(() => setOpen((open) => !open), []); - return ( -
- - - - - - - Your mailing list lets you contact customers or visitors who - have shown an interest in your store. Reach out to them with - exclusive offers or updates about your products. - - Test link - - - - -
- ); -} + return ( +
+ + + + + + + Your mailing list lets you contact customers or visitors who + have shown an interest in your store. Reach out to them with + exclusive offers or updates about your products. + + Test link + + + + +
+ ); + }, +}; diff --git a/polaris-react/src/components/ColorPicker/ColorPicker.stories.tsx b/polaris-react/src/components/ColorPicker/ColorPicker.stories.tsx index 59111383b67..19841f5499c 100644 --- a/polaris-react/src/components/ColorPicker/ColorPicker.stories.tsx +++ b/polaris-react/src/components/ColorPicker/ColorPicker.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useEffect, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { ColorPicker, TextField, @@ -10,97 +10,108 @@ import { export default { component: ColorPicker, -} as ComponentMeta; +} as Meta; -export function Default() { - const [color, setColor] = useState({ - hue: 120, - brightness: 1, - saturation: 1, - }); +export const Default = { + render() { + const [color, setColor] = useState({ + hue: 120, + brightness: 1, + saturation: 1, + }); - return ; -} + return ; + }, +}; -export function WithTransparentValue() { - const [color, setColor] = useState({ - hue: 300, - brightness: 1, - saturation: 0.7, - alpha: 0.7, - }); +export const WithTransparentValue = { + render() { + const [color, setColor] = useState({ + hue: 300, + brightness: 1, + saturation: 0.7, + alpha: 0.7, + }); - return ; -} + return ; + }, +}; -export function WithTransparentValueFullWidth() { - const [color, setColor] = useState({ - hue: 300, - brightness: 1, - saturation: 0.7, - alpha: 0.7, - }); +export const WithTransparentValueFullWidth = { + render() { + const [color, setColor] = useState({ + hue: 300, + brightness: 1, + saturation: 0.7, + alpha: 0.7, + }); - return ; -} + return ( + + ); + }, +}; -export function WithHexTextField() { - const [color, setColor] = useState({ - hue: 300, - saturation: 0.7, - brightness: 1, - }); +export const WithHexTextField = { + render() { + const [color, setColor] = useState({ + hue: 300, + saturation: 0.7, + brightness: 1, + }); - const [hex, setHex] = useState(hsbToHex(color)); + const [hex, setHex] = useState(hsbToHex(color)); - const handleBlur = useCallback(() => { - setColor(rgbToHsb(hexToRgb(hex))); - }, [hex]); + const handleBlur = useCallback(() => { + setColor(rgbToHsb(hexToRgb(hex))); + }, [hex]); - useEffect(() => { - setHex(hsbToHex(color)); - }, [color]); + useEffect(() => { + setHex(hsbToHex(color)); + }, [color]); - const styles = { - Wrapper: { - display: 'grid', - gap: 'var(--p-space-200)', - gridTemplateColumns: 'auto 1fr', - maxWidth: 'fit-content', - }, - Picker: { - gridColumn: '1 / 3', - }, - Tile: { - minHeight: 'calc(100% - 0.125rem)', - aspectRatio: '1 / 1', - borderRadius: 'var(--p-border-radius-100)', - border: 'var(--p-border-width-025) solid var(--p-color-border-secondary)', - backgroundColor: hsbToHex(color), - }, - TextField: { - maxWidth: 'fit-content', - }, - }; + const styles = { + Wrapper: { + display: 'grid', + gap: 'var(--p-space-200)', + gridTemplateColumns: 'auto 1fr', + maxWidth: 'fit-content', + }, + Picker: { + gridColumn: '1 / 3', + }, + Tile: { + minHeight: 'calc(100% - 0.125rem)', + aspectRatio: '1 / 1', + borderRadius: 'var(--p-border-radius-100)', + border: + 'var(--p-border-width-025) solid var(--p-color-border-secondary)', + backgroundColor: hsbToHex(color), + }, + TextField: { + maxWidth: 'fit-content', + }, + }; - return ( -
-
- -
+ return ( +
+
+ +
-
+
-
- +
+ +
-
- ); -} + ); + }, +}; diff --git a/polaris-react/src/components/Combobox/Combobox.stories.tsx b/polaris-react/src/components/Combobox/Combobox.stories.tsx index b885f50dab0..a1a50c43727 100644 --- a/polaris-react/src/components/Combobox/Combobox.stories.tsx +++ b/polaris-react/src/components/Combobox/Combobox.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useMemo, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Combobox, EmptySearchResult, @@ -14,770 +14,790 @@ import {SearchIcon} from '@shopify/polaris-icons'; export default { component: Combobox, -} as ComponentMeta; - -export function Default() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - - const [selectedOption, setSelectedOption] = useState(); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } +} as Meta; + +export const Default = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + + const [selectedOption, setSelectedOption] = useState(); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const updateSelection = useCallback( - (selected) => { - const matchedOption = options.find((option) => { - return option.value.match(selected); - }); - - setSelectedOption(selected); - setInputValue((matchedOption && matchedOption.label) || ''); - }, - [options], - ); - - const optionsMarkup = - options.length > 0 - ? options.map((option) => { - const {label, value} = option; - - return ( - - {label} - - ); - }) - : null; - - return ( -
- } - onChange={updateText} - label="Search tags" - labelHidden - value={inputValue} - placeholder="Search tags" - /> + if (value === '') { + setOptions(deselectedOptions); + return; } - > - {options.length > 0 ? ( - {optionsMarkup} - ) : null} - -
- ); -} - -export function WithChildrenBasedOnInput() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - - const [selectedOption, setSelectedOption] = useState(); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const updateSelection = useCallback( - (selected) => { - const matchedOption = options.find((option) => { - return option.value.match(selected); - }); - - setSelectedOption(selected); - setInputValue((matchedOption && matchedOption.label) || ''); - }, - [options], - ); - - const optionsMarkup = - options.length > 0 - ? options.map((option) => { - const {label, value} = option; - - return ( - - {label} - - ); - }) - : null; - - return ( -
- } - onChange={updateText} - label="Search tags" - labelHidden - value={inputValue} - placeholder="Search tags" - /> - } - > - {inputValue.length > 0 && options.length > 0 ? ( - {optionsMarkup} - ) : null} - -
- ); -} - -export function WithManualSelection() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - - const [selectedOption, setSelectedOption] = useState(); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } + const filterRegex = new RegExp(value, 'i'); + const resultOptions = deselectedOptions.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); + }, + [deselectedOptions], + ); + + const updateSelection = useCallback( + (selected) => { + const matchedOption = options.find((option) => { + return option.value.match(selected); + }); + + setSelectedOption(selected); + setInputValue((matchedOption && matchedOption.label) || ''); + }, + [options], + ); + + const optionsMarkup = + options.length > 0 + ? options.map((option) => { + const {label, value} = option; + + return ( + + {label} + + ); + }) + : null; + + return ( +
+ } + onChange={updateText} + label="Search tags" + labelHidden + value={inputValue} + placeholder="Search tags" + /> + } + > + {options.length > 0 ? ( + {optionsMarkup} + ) : null} + +
+ ); + }, +}; + +export const WithChildrenBasedOnInput = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + + const [selectedOption, setSelectedOption] = useState(); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const updateSelection = useCallback( - (selected) => { - const matchedOption = options.find((option) => { - return option.value.match(selected); - }); - - setSelectedOption(selected); - setInputValue((matchedOption && matchedOption.label) || ''); - }, - [options], - ); - - const optionsMarkup = - options.length > 0 - ? options.map((option) => { - const {label, value} = option; - - return ( - - {label} - - ); - }) - : null; - - return ( -
- } - onChange={updateText} - label="Search tags" - labelHidden - value={inputValue} - placeholder="Search tags" - /> + if (value === '') { + setOptions(deselectedOptions); + return; } - > - {options.length > 0 ? ( - - {optionsMarkup} - - ) : null} - -
- ); -} - -export function WithMultiSelect() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const updateSelection = useCallback( - (selected) => { - if (selectedOptions.includes(selected)) { - setSelectedOptions( - selectedOptions.filter((option) => option !== selected), + const filterRegex = new RegExp(value, 'i'); + const resultOptions = deselectedOptions.filter((option) => + option.label.match(filterRegex), ); - } else { - setSelectedOptions([...selectedOptions, selected]); - } + setOptions(resultOptions); + }, + [deselectedOptions], + ); + + const updateSelection = useCallback( + (selected) => { + const matchedOption = options.find((option) => { + return option.value.match(selected); + }); + + setSelectedOption(selected); + setInputValue((matchedOption && matchedOption.label) || ''); + }, + [options], + ); + + const optionsMarkup = + options.length > 0 + ? options.map((option) => { + const {label, value} = option; + + return ( + + {label} + + ); + }) + : null; + + return ( +
+ } + onChange={updateText} + label="Search tags" + labelHidden + value={inputValue} + placeholder="Search tags" + /> + } + > + {inputValue.length > 0 && options.length > 0 ? ( + {optionsMarkup} + ) : null} + +
+ ); + }, +}; + +export const WithManualSelection = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + + const [selectedOption, setSelectedOption] = useState(); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); - const matchedOption = options.find((option) => { - return option.value.match(selected); - }); - - updateText(''); - }, - [options, selectedOptions, updateText], - ); - - const removeTag = useCallback( - (tag) => () => { - const options = [...selectedOptions]; - options.splice(options.indexOf(tag), 1); - setSelectedOptions(options); - }, - [selectedOptions], - ); - - const tagsMarkup = selectedOptions.map((option) => ( - - {option} - - )); - - const optionsMarkup = - options.length > 0 - ? options.map((option) => { - const {label, value} = option; - - return ( - - {label} - - ); - }) - : null; - - return ( -
- } - onChange={updateText} - label="Search tags" - labelHidden - value={inputValue} - placeholder="Search tags" - /> + if (value === '') { + setOptions(deselectedOptions); + return; } - > - {optionsMarkup ? ( - {optionsMarkup} - ) : null} - - - {tagsMarkup} - -
- ); -} - -export function WithMultiSelectAndManualSelection() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - - const [selectedOptions, setSelectedOptions] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (value === '') { - setOptions(deselectedOptions); - return; - } - const filterRegex = new RegExp(value, 'i'); - const resultOptions = deselectedOptions.filter((option) => - option.label.match(filterRegex), - ); - setOptions(resultOptions); - }, - [deselectedOptions], - ); - - const updateSelection = useCallback( - (selected) => { - if (selectedOptions.includes(selected)) { - setSelectedOptions( - selectedOptions.filter((option) => option !== selected), + const filterRegex = new RegExp(value, 'i'); + const resultOptions = deselectedOptions.filter((option) => + option.label.match(filterRegex), ); - } else { - setSelectedOptions([...selectedOptions, selected]); - } + setOptions(resultOptions); + }, + [deselectedOptions], + ); + + const updateSelection = useCallback( + (selected) => { + const matchedOption = options.find((option) => { + return option.value.match(selected); + }); + + setSelectedOption(selected); + setInputValue((matchedOption && matchedOption.label) || ''); + }, + [options], + ); + + const optionsMarkup = + options.length > 0 + ? options.map((option) => { + const {label, value} = option; + + return ( + + {label} + + ); + }) + : null; + + return ( +
+ } + onChange={updateText} + label="Search tags" + labelHidden + value={inputValue} + placeholder="Search tags" + /> + } + > + {options.length > 0 ? ( + + {optionsMarkup} + + ) : null} + +
+ ); + }, +}; + +export const WithMultiSelect = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); - const matchedOption = options.find((option) => { - return option.value.match(selected); - }); - - updateText(''); - }, - [options, selectedOptions, updateText], - ); - - const removeTag = useCallback( - (tag) => () => { - const options = [...selectedOptions]; - options.splice(options.indexOf(tag), 1); - setSelectedOptions(options); - }, - [selectedOptions], - ); - - const tagsMarkup = selectedOptions.map((option) => ( - - {option} - - )); - - const optionsMarkup = - options.length > 0 - ? options.map((option) => { - const {label, value} = option; - - return ( - - {label} - - ); - }) - : null; - - return ( -
- } - onChange={updateText} - label="Search tags" - labelHidden - value={inputValue} - placeholder="Search tags" - /> + if (value === '') { + setOptions(deselectedOptions); + return; } - > - {optionsMarkup ? ( - - {optionsMarkup} - - ) : null} - - - {tagsMarkup} - -
- ); -} - -export function WithMultiSelectAndVerticalContent() { - const [selectedTags, setSelectedTags] = useState(['Rustic']); - const [value, setValue] = useState(''); - const [suggestion, setSuggestion] = useState(''); - - const handleActiveOptionChange = useCallback( - (activeOption) => { - const activeOptionIsAction = activeOption === value; - - if (!activeOptionIsAction && !selectedTags.includes(activeOption)) { - setSuggestion(activeOption); - } else { - setSuggestion(''); - } - }, - [value, selectedTags], - ); - const updateSelection = useCallback( - (selected) => { - const nextSelectedTags = new Set([...selectedTags]); - - if (nextSelectedTags.has(selected)) { - nextSelectedTags.delete(selected); - } else { - nextSelectedTags.add(selected); - } - setSelectedTags([...nextSelectedTags]); - setValue(''); - setSuggestion(''); - }, - [selectedTags], - ); - - const removeTag = useCallback( - (tag) => () => { - updateSelection(tag); - }, - [updateSelection], - ); - - const getAllTags = useCallback(() => { - const savedTags = ['Rustic', 'Antique', 'Vinyl', 'Vintage', 'Refurbished']; - return [...new Set([...savedTags, ...selectedTags].sort())]; - }, [selectedTags]); - - const formatOptionText = useCallback( - (option) => { - const trimValue = value.trim().toLocaleLowerCase(); - const matchIndex = option.toLocaleLowerCase().indexOf(trimValue); - - if (!value || matchIndex === -1) return option; - - const start = option.slice(0, matchIndex); - const highlight = option.slice( - matchIndex, - `${matchIndex}${trimValue.length}`, - ); - const end = option.slice( - `${matchIndex}${trimValue.length}`, - option.length, - ); - - return ( - - {start} - - {highlight} - - {end} - - ); - }, - [value], - ); - - const options = useMemo(() => { - let list; - const allTags = getAllTags(); - const filterRegex = new RegExp(value, 'i'); - - if (value) { - list = allTags.filter((tag) => tag.match(filterRegex)); - } else { - list = allTags; - } - - return [...list]; - }, [value, getAllTags]); - - const verticalContentMarkup = - selectedTags.length > 0 ? ( - - {selectedTags.map((tag) => ( - - {tag} - - ))} - - ) : null; - const optionMarkup = - options.length > 0 - ? options.map((option) => { - return ( - - - {formatOptionText(option)} - - + const filterRegex = new RegExp(value, 'i'); + const resultOptions = deselectedOptions.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); + }, + [deselectedOptions], + ); + + const updateSelection = useCallback( + (selected) => { + if (selectedOptions.includes(selected)) { + setSelectedOptions( + selectedOptions.filter((option) => option !== selected), ); - }) - : null; - - const noResults = value && !getAllTags().includes(value); - - const actionMarkup = noResults ? ( - {`Add "${value}"`} - ) : null; - - const emptyStateMarkup = optionMarkup ? null : ( - - ); - - const listboxMarkup = - optionMarkup || actionMarkup || emptyStateMarkup ? ( - - {actionMarkup} - {optionMarkup} - - ) : null; - - return ( -
- + } else { + setSelectedOptions([...selectedOptions, selected]); } - > - {listboxMarkup} - -
- ); -} - -export function WithLoading() { - const deselectedOptions = useMemo( - () => [ - {value: 'rustic', label: 'Rustic'}, - {value: 'antique', label: 'Antique'}, - {value: 'vinyl', label: 'Vinyl'}, - {value: 'vintage', label: 'Vintage'}, - {value: 'refurbished', label: 'Refurbished'}, - ], - [], - ); - - const [selectedOption, setSelectedOption] = useState(); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState(deselectedOptions); - const [loading, setLoading] = useState(false); - - const updateText = useCallback( - (value) => { - setInputValue(value); - - if (!loading) { - setLoading(true); - } - setTimeout(() => { + const matchedOption = options.find((option) => { + return option.value.match(selected); + }); + + updateText(''); + }, + [options, selectedOptions, updateText], + ); + + const removeTag = useCallback( + (tag) => () => { + const options = [...selectedOptions]; + options.splice(options.indexOf(tag), 1); + setSelectedOptions(options); + }, + [selectedOptions], + ); + + const tagsMarkup = selectedOptions.map((option) => ( + + {option} + + )); + + const optionsMarkup = + options.length > 0 + ? options.map((option) => { + const {label, value} = option; + + return ( + + {label} + + ); + }) + : null; + + return ( +
+ } + onChange={updateText} + label="Search tags" + labelHidden + value={inputValue} + placeholder="Search tags" + /> + } + > + {optionsMarkup ? ( + {optionsMarkup} + ) : null} + + + {tagsMarkup} + +
+ ); + }, +}; + +export const WithMultiSelectAndManualSelection = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + + const [selectedOptions, setSelectedOptions] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + + const updateText = useCallback( + (value) => { + setInputValue(value); + if (value === '') { setOptions(deselectedOptions); - setLoading(false); return; } + const filterRegex = new RegExp(value, 'i'); - const resultOptions = options.filter((option) => + const resultOptions = deselectedOptions.filter((option) => option.label.match(filterRegex), ); setOptions(resultOptions); - setLoading(false); - }, 400); - }, - [deselectedOptions, loading, options], - ); - - const updateSelection = useCallback( - (selected) => { - const matchedOption = options.find((option) => { - return option.value.match(selected); - }); - - setSelectedOption(selected); - setInputValue((matchedOption && matchedOption.label) || ''); - }, - [options], - ); - - const optionsMarkup = - options.length > 0 && !loading - ? options.map((option) => { - const {label, value} = option; - - return ( - - {label} - + }, + [deselectedOptions], + ); + + const updateSelection = useCallback( + (selected) => { + if (selectedOptions.includes(selected)) { + setSelectedOptions( + selectedOptions.filter((option) => option !== selected), ); - }) - : null; - - const loadingMarkup = loading ? ( -
- -
- ) : null; - - const listboxMarkup = - optionsMarkup || loadingMarkup ? ( - - {optionsMarkup} - {loadingMarkup} - + } else { + setSelectedOptions([...selectedOptions, selected]); + } + + const matchedOption = options.find((option) => { + return option.value.match(selected); + }); + + updateText(''); + }, + [options, selectedOptions, updateText], + ); + + const removeTag = useCallback( + (tag) => () => { + const options = [...selectedOptions]; + options.splice(options.indexOf(tag), 1); + setSelectedOptions(options); + }, + [selectedOptions], + ); + + const tagsMarkup = selectedOptions.map((option) => ( + + {option} + + )); + + const optionsMarkup = + options.length > 0 + ? options.map((option) => { + const {label, value} = option; + + return ( + + {label} + + ); + }) + : null; + + return ( +
+ } + onChange={updateText} + label="Search tags" + labelHidden + value={inputValue} + placeholder="Search tags" + /> + } + > + {optionsMarkup ? ( + + {optionsMarkup} + + ) : null} + + + {tagsMarkup} + +
+ ); + }, +}; + +export const WithMultiSelectAndVerticalContent = { + render() { + const [selectedTags, setSelectedTags] = useState(['Rustic']); + const [value, setValue] = useState(''); + const [suggestion, setSuggestion] = useState(''); + + const handleActiveOptionChange = useCallback( + (activeOption) => { + const activeOptionIsAction = activeOption === value; + + if (!activeOptionIsAction && !selectedTags.includes(activeOption)) { + setSuggestion(activeOption); + } else { + setSuggestion(''); + } + }, + [value, selectedTags], + ); + const updateSelection = useCallback( + (selected) => { + const nextSelectedTags = new Set([...selectedTags]); + + if (nextSelectedTags.has(selected)) { + nextSelectedTags.delete(selected); + } else { + nextSelectedTags.add(selected); + } + setSelectedTags([...nextSelectedTags]); + setValue(''); + setSuggestion(''); + }, + [selectedTags], + ); + + const removeTag = useCallback( + (tag) => () => { + updateSelection(tag); + }, + [updateSelection], + ); + + const getAllTags = useCallback(() => { + const savedTags = [ + 'Rustic', + 'Antique', + 'Vinyl', + 'Vintage', + 'Refurbished', + ]; + return [...new Set([...savedTags, ...selectedTags].sort())]; + }, [selectedTags]); + + const formatOptionText = useCallback( + (option) => { + const trimValue = value.trim().toLocaleLowerCase(); + const matchIndex = option.toLocaleLowerCase().indexOf(trimValue); + + if (!value || matchIndex === -1) return option; + + const start = option.slice(0, matchIndex); + const highlight = option.slice( + matchIndex, + `${matchIndex}${trimValue.length}`, + ); + const end = option.slice( + `${matchIndex}${trimValue.length}`, + option.length, + ); + + return ( + + {start} + + {highlight} + + {end} + + ); + }, + [value], + ); + + const options = useMemo(() => { + let list; + const allTags = getAllTags(); + const filterRegex = new RegExp(value, 'i'); + + if (value) { + list = allTags.filter((tag) => tag.match(filterRegex)); + } else { + list = allTags; + } + + return [...list]; + }, [value, getAllTags]); + + const verticalContentMarkup = + selectedTags.length > 0 ? ( + + {selectedTags.map((tag) => ( + + {tag} + + ))} + + ) : null; + + const optionMarkup = + options.length > 0 + ? options.map((option) => { + return ( + + + {formatOptionText(option)} + + + ); + }) + : null; + + const noResults = value && !getAllTags().includes(value); + + const actionMarkup = noResults ? ( + {`Add "${value}"`} ) : null; - return ( -
- } - onChange={updateText} - label="Search tags" - labelHidden - value={inputValue} - placeholder="Search tags" - /> + const emptyStateMarkup = optionMarkup ? null : ( + + ); + + const listboxMarkup = + optionMarkup || actionMarkup || emptyStateMarkup ? ( + + {actionMarkup} + {optionMarkup} + + ) : null; + + return ( +
+ + } + > + {listboxMarkup} + +
+ ); + }, +}; + +export const WithLoading = { + render() { + const deselectedOptions = useMemo( + () => [ + {value: 'rustic', label: 'Rustic'}, + {value: 'antique', label: 'Antique'}, + {value: 'vinyl', label: 'Vinyl'}, + {value: 'vintage', label: 'Vintage'}, + {value: 'refurbished', label: 'Refurbished'}, + ], + [], + ); + + const [selectedOption, setSelectedOption] = useState(); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState(deselectedOptions); + const [loading, setLoading] = useState(false); + + const updateText = useCallback( + (value) => { + setInputValue(value); + + if (!loading) { + setLoading(true); } + + setTimeout(() => { + if (value === '') { + setOptions(deselectedOptions); + setLoading(false); + return; + } + const filterRegex = new RegExp(value, 'i'); + const resultOptions = options.filter((option) => + option.label.match(filterRegex), + ); + setOptions(resultOptions); + setLoading(false); + }, 400); + }, + [deselectedOptions, loading, options], + ); + + const updateSelection = useCallback( + (selected) => { + const matchedOption = options.find((option) => { + return option.value.match(selected); + }); + + setSelectedOption(selected); + setInputValue((matchedOption && matchedOption.label) || ''); + }, + [options], + ); + + const optionsMarkup = + options.length > 0 && !loading + ? options.map((option) => { + const {label, value} = option; + + return ( + + {label} + + ); + }) + : null; + + const loadingMarkup = loading ? ( +
- {listboxMarkup} - -
- ); -} + +
+ ) : null; + + const listboxMarkup = + optionsMarkup || loadingMarkup ? ( + + {optionsMarkup} + {loadingMarkup} + + ) : null; + + return ( +
+ } + onChange={updateText} + label="Search tags" + labelHidden + value={inputValue} + placeholder="Search tags" + /> + } + > + {listboxMarkup} + +
+ ); + }, +}; diff --git a/polaris-react/src/components/ContextualSaveBar/ContextualSaveBar.stories.tsx b/polaris-react/src/components/ContextualSaveBar/ContextualSaveBar.stories.tsx index ee4fcc4fd43..18c8b44fed4 100644 --- a/polaris-react/src/components/ContextualSaveBar/ContextualSaveBar.stories.tsx +++ b/polaris-react/src/components/ContextualSaveBar/ContextualSaveBar.stories.tsx @@ -1,112 +1,120 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {ContextualSaveBar, Frame} from '@shopify/polaris'; export default { component: ContextualSaveBar, parameters: {layout: 'fullscreen'}, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( -
- - console.log('add form submit logic'), - loading: false, - disabled: false, +export const Default = { + render() { + return ( +
+ console.log('add clear form logic'), - }} - /> - -
- ); -} + > + console.log('add form submit logic'), + loading: false, + disabled: false, + }} + discardAction={{ + onAction: () => console.log('add clear form logic'), + }} + /> + +
+ ); + }, +}; -export function Disabled() { - return ( -
- - console.log('add form submit logic'), - loading: false, - disabled: true, - }} - discardAction={{ - onAction: () => console.log('add clear form logic'), +export const Disabled = { + render() { + return ( +
+ - -
- ); -} + > + console.log('add form submit logic'), + loading: false, + disabled: true, + }} + discardAction={{ + onAction: () => console.log('add clear form logic'), + }} + /> + +
+ ); + }, +}; -export function WithFlushContents() { - return ( -
- - console.log('add form submit logic'), +export const WithFlushContents = { + render() { + return ( +
+ console.log('add clear form logic'), - }} - /> - -
- ); -} + > + console.log('add form submit logic'), + }} + discardAction={{ + onAction: () => console.log('add clear form logic'), + }} + /> + +
+ ); + }, +}; -export function WithFullWidth() { - return ( -
- - console.log('add form submit logic'), - loading: false, - disabled: false, - }} - discardAction={{ - onAction: () => console.log('add clear form logic'), +export const WithFullWidth = { + render() { + return ( +
+ - -
- ); -} + > + console.log('add form submit logic'), + loading: false, + disabled: false, + }} + discardAction={{ + onAction: () => console.log('add clear form logic'), + }} + /> + +
+ ); + }, +}; diff --git a/polaris-react/src/components/DataTable/DataTable.stories.tsx b/polaris-react/src/components/DataTable/DataTable.stories.tsx index 0f111a97ce5..5b3a883f009 100644 --- a/polaris-react/src/components/DataTable/DataTable.stories.tsx +++ b/polaris-react/src/components/DataTable/DataTable.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {LegacyCard, DataTable, Link, Page} from '@shopify/polaris'; export default { @@ -11,7 +11,7 @@ export default { }, }, }, -} as ComponentMeta; +} as Meta; function sortCurrency(rows, index, direction) { return [...rows].sort((rowA, rowB) => { @@ -22,898 +22,928 @@ function sortCurrency(rows, index, direction) { }); } -export function Default() { - const rows = [ - ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], - ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], - [ - 'Navy Merino Wool Blazer with khaki chinos and yellow belt', - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const Default = { + render() { + const rows = [ + ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], + ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], + [ + 'Navy Merino Wool Blazer with khaki chinos and yellow belt', + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function Sortable() { - const [sortedRows, setSortedRows] = useState(); +export const Sortable = { + render() { + const [sortedRows, setSortedRows] = useState(); - const initiallySortedRows = [ - ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], - ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], - [ - 'Navy Merino Wool Blazer with khaki chinos and yellow belt', - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; - const rows = sortedRows ? sortedRows : initiallySortedRows; + const initiallySortedRows = [ + ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], + ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], + [ + 'Navy Merino Wool Blazer with khaki chinos and yellow belt', + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; + const rows = sortedRows ? sortedRows : initiallySortedRows; - const handleSort = useCallback( - (index, direction) => setSortedRows(sortCurrency(rows, index, direction)), - [rows], - ); + const handleSort = useCallback( + (index, direction) => setSortedRows(sortCurrency(rows, index, direction)), + [rows], + ); - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithFooter() { - const rows = [ - ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], - ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], - [ - 'Navy Merino Wool Blazer with khaki chinos and yellow belt', - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const WithFooter = { + render() { + const rows = [ + ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], + ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], + [ + 'Navy Merino Wool Blazer with khaki chinos and yellow belt', + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithCustomTotalsHeading() { - const rows = [ - ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], - ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], - [ - 'Navy Merino Wool Blazer with khaki chinos and yellow belt', - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const WithCustomTotalsHeading = { + render() { + const rows = [ + ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], + ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], + [ + 'Navy Merino Wool Blazer with khaki chinos and yellow belt', + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithTotalsInFooter() { - const rows = [ - ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], - ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], - [ - 'Navy Merino Wool Blazer with khaki chinos and yellow belt', - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const WithTotalsInFooter = { + render() { + const rows = [ + ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], + ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], + [ + 'Navy Merino Wool Blazer with khaki chinos and yellow belt', + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithRowHeadingLinks() { - const rows = [ - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$122,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const WithRowHeadingLinks = { + render() { + const rows = [ + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$122,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithAllOfItsElements() { - const [sortedRows, setSortedRows] = useState(); +export const WithAllOfItsElements = { + render() { + const [sortedRows, setSortedRows] = useState(); - const initiallySortedRows = [ - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; + const initiallySortedRows = [ + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - const rows = sortedRows ? sortedRows : initiallySortedRows; - const handleSort = useCallback( - (index, direction) => setSortedRows(sortCurrency(rows, index, direction)), - [rows], - ); + const rows = sortedRows ? sortedRows : initiallySortedRows; + const handleSort = useCallback( + (index, direction) => setSortedRows(sortCurrency(rows, index, direction)), + [rows], + ); - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithColumnSpanning() { - const rows = [ - [ - 'Sep 19, 2010, 1:02 pm NDT', - '#1234', - 'Adjustment', - '$1.00', - '$1.00', - '$1.00', - '$1.00', - '$1.00', - ], - // eslint-disable-next-line react/jsx-key - [Hello], - [ - 'Sep 19, 2010, 1:02 pm NDT', - '#1234', - 'Adjustment', - '$1.00', - '$1.00', - '$1.00', - '$1.00', - '$1.00', - ], - ]; +export const WithColumnSpanning = { + render() { + const rows = [ + [ + 'Sep 19, 2010, 1:02 pm NDT', + '#1234', + 'Adjustment', + '$1.00', + '$1.00', + '$1.00', + '$1.00', + '$1.00', + ], + // eslint-disable-next-line react/jsx-key + [Hello], + [ + 'Sep 19, 2010, 1:02 pm NDT', + '#1234', + 'Adjustment', + '$1.00', + '$1.00', + '$1.00', + '$1.00', + '$1.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithFixedColumns() { - const rows = [ - [ - 'Emerald Silk Gown', - 'Formalwear', - "Jill's formal", - 10, - '$875.00', - 124689, - 140, - '$426.00', - '$122,500.00', - ], - [ - 'Mauve Cashmere Scarf', - 'Accessories', - "Jack's Accessories", - 253, - '$230.00', - 124533, - 83, - '$620.00', - '$19,090.00', - ], - [ - 'Navy Merino Wool Blazer with khaki chinos and yellow belt', - 'Ensembles', - 'Avocado Fashions', - 23, - '$445.00', - 124518, - 32, - '$353.00', - '$14,240.00', - ], - [ - 'Socks', - 'Essentials', - 'Avocado Fashions', - 465, - '$4.00', - 124518, - 32, - '$3.00', - '$140.00', - ], - ]; +export const WithFixedColumns = { + render() { + const rows = [ + [ + 'Emerald Silk Gown', + 'Formalwear', + "Jill's formal", + 10, + '$875.00', + 124689, + 140, + '$426.00', + '$122,500.00', + ], + [ + 'Mauve Cashmere Scarf', + 'Accessories', + "Jack's Accessories", + 253, + '$230.00', + 124533, + 83, + '$620.00', + '$19,090.00', + ], + [ + 'Navy Merino Wool Blazer with khaki chinos and yellow belt', + 'Ensembles', + 'Avocado Fashions', + 23, + '$445.00', + 124518, + 32, + '$353.00', + '$14,240.00', + ], + [ + 'Socks', + 'Essentials', + 'Avocado Fashions', + 465, + '$4.00', + 124518, + 32, + '$3.00', + '$140.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithIncreasedDensityAndZebraStriping() { - const rows = [ - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const WithIncreasedDensityAndZebraStriping = { + render() { + const rows = [ + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithStickyHeaderEnabled() { - const rows = [ - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - [ - - Emerald Silk Gown - , - '$875.00', - 124689, - 140, - '$121,500.00', - ], - [ - - Mauve Cashmere Scarf - , - '$230.00', - 124533, - 83, - '$19,090.00', - ], - [ - - Navy Merino Wool Blazer with khaki chinos and yellow belt - , - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const WithStickyHeaderEnabled = { + render() { + const rows = [ + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + [ + + Emerald Silk Gown + , + '$875.00', + 124689, + 140, + '$121,500.00', + ], + [ + + Mauve Cashmere Scarf + , + '$230.00', + 124533, + 83, + '$19,090.00', + ], + [ + + Navy Merino Wool Blazer with khaki chinos and yellow belt + , + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - - - - ); -} + return ( + + + + + + ); + }, +}; -export function WithPagination() { - const rows = [ - ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], - ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], - [ - 'Navy Merino Wool Blazer with khaki chinos and yellow belt', - '$445.00', - 124518, - 32, - '$14,240.00', - ], - ]; +export const WithPagination = { + render() { + const rows = [ + ['Emerald Silk Gown', '$875.00', 124689, 140, '$122,500.00'], + ['Mauve Cashmere Scarf', '$230.00', 124533, 83, '$19,090.00'], + [ + 'Navy Merino Wool Blazer with khaki chinos and yellow belt', + '$445.00', + 124518, + 32, + '$14,240.00', + ], + ]; - return ( - - - {}, - }} - /> - - - ); -} + return ( + + + {}, + }} + /> + + + ); + }, +}; diff --git a/polaris-react/src/components/DatePicker/DatePicker.stories.tsx b/polaris-react/src/components/DatePicker/DatePicker.stories.tsx index 53eb519828c..98003ef8360 100644 --- a/polaris-react/src/components/DatePicker/DatePicker.stories.tsx +++ b/polaris-react/src/components/DatePicker/DatePicker.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Box, Card, DatePicker, BlockStack} from '@shopify/polaris'; export default { @@ -7,167 +7,181 @@ export default { parameters: { chromatic: {delay: 300}, }, -} as ComponentMeta; - -export function All() { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} - -export function Default() { - const [{month, year}, setDate] = useState({month: 1, year: 2018}); - const [selectedDates, setSelectedDates] = useState({ - start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), - end: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), - }); - - const handleMonthChange = useCallback( - (month, year) => setDate({month, year}), - [], - ); - - return ( - - ); -} - -export function Ranged() { - const [{month, year}, setDate] = useState({month: 1, year: 2018}); - const [selectedDates, setSelectedDates] = useState({ - start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), - end: new Date('Sat Feb 10 2018 00:00:00 GMT-0500 (EST)'), - }); - - const handleMonthChange = useCallback( - (month, year) => setDate({month, year}), - [], - ); - - return ( - - ); -} - -export function MultiMonthRanged() { - const [{month, year}, setDate] = useState({month: 1, year: 2018}); - const [selectedDates, setSelectedDates] = useState({ - start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), - end: new Date('Mon Mar 12 2018 00:00:00 GMT-0500 (EST)'), - }); - - const handleMonthChange = useCallback( - (month, year) => setDate({month, year}), - [], - ); - - return ( - - ); -} - -export function WithDisabledDateRanges() { - const [{month, year}, setDate] = useState({month: 1, year: 2018}); - const [selectedDates, setSelectedDates] = useState({ - start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), - end: new Date('Sat Feb 10 2018 00:00:00 GMT-0500 (EST)'), - }); - - const handleMonthChange = useCallback( - (month, year) => setDate({month, year}), - [], - ); - - return ( - - ); -} - -export function WithSpecificDisabledDates() { - const [{month, year}, setDate] = useState({month: 1, year: 2018}); - const [selectedDates, setSelectedDates] = useState( - new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), - ); - - const handleMonthChange = useCallback( - (month, year) => setDate({month, year}), - [], - ); - - const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; - - const disableSpecificDates = [ - new Date('Mon Feb 12 2018 00:00:00 GMT-0500 (EST)'), - new Date('Sat Feb 10 2018 00:00:00 GMT-0500 (EST)'), - new Date('Wed Feb 21 2018 00:00:00 GMT-0500 (EST)'), - ]; - - return ( - - ); -} +} as Meta; + +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; + +export const Default = { + render() { + const [{month, year}, setDate] = useState({month: 1, year: 2018}); + const [selectedDates, setSelectedDates] = useState({ + start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), + end: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), + }); + + const handleMonthChange = useCallback( + (month, year) => setDate({month, year}), + [], + ); + + return ( + + ); + }, +}; + +export const Ranged = { + render() { + const [{month, year}, setDate] = useState({month: 1, year: 2018}); + const [selectedDates, setSelectedDates] = useState({ + start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), + end: new Date('Sat Feb 10 2018 00:00:00 GMT-0500 (EST)'), + }); + + const handleMonthChange = useCallback( + (month, year) => setDate({month, year}), + [], + ); + + return ( + + ); + }, +}; + +export const MultiMonthRanged = { + render() { + const [{month, year}, setDate] = useState({month: 1, year: 2018}); + const [selectedDates, setSelectedDates] = useState({ + start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), + end: new Date('Mon Mar 12 2018 00:00:00 GMT-0500 (EST)'), + }); + + const handleMonthChange = useCallback( + (month, year) => setDate({month, year}), + [], + ); + + return ( + + ); + }, +}; + +export const WithDisabledDateRanges = { + render() { + const [{month, year}, setDate] = useState({month: 1, year: 2018}); + const [selectedDates, setSelectedDates] = useState({ + start: new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), + end: new Date('Sat Feb 10 2018 00:00:00 GMT-0500 (EST)'), + }); + + const handleMonthChange = useCallback( + (month, year) => setDate({month, year}), + [], + ); + + return ( + + ); + }, +}; + +export const WithSpecificDisabledDates = { + render() { + const [{month, year}, setDate] = useState({month: 1, year: 2018}); + const [selectedDates, setSelectedDates] = useState( + new Date('Wed Feb 07 2018 00:00:00 GMT-0500 (EST)'), + ); + + const handleMonthChange = useCallback( + (month, year) => setDate({month, year}), + [], + ); + + const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; + + const disableSpecificDates = [ + new Date('Mon Feb 12 2018 00:00:00 GMT-0500 (EST)'), + new Date('Sat Feb 10 2018 00:00:00 GMT-0500 (EST)'), + new Date('Wed Feb 21 2018 00:00:00 GMT-0500 (EST)'), + ]; + + return ( + + ); + }, +}; diff --git a/polaris-react/src/components/DescriptionList/DescriptionList.stories.tsx b/polaris-react/src/components/DescriptionList/DescriptionList.stories.tsx index 72b371173b2..fd1e266b5b3 100644 --- a/polaris-react/src/components/DescriptionList/DescriptionList.stories.tsx +++ b/polaris-react/src/components/DescriptionList/DescriptionList.stories.tsx @@ -1,56 +1,60 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {DescriptionList} from '@shopify/polaris'; export default { component: DescriptionList, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - ); -} +export const Default = { + render() { + return ( + + ); + }, +}; -export function Tight() { - return ( - - ); -} +export const Tight = { + render() { + return ( + + ); + }, +}; diff --git a/polaris-react/src/components/Divider/Divider.stories.tsx b/polaris-react/src/components/Divider/Divider.stories.tsx index 2fae94e32ff..29aec8d4710 100644 --- a/polaris-react/src/components/Divider/Divider.stories.tsx +++ b/polaris-react/src/components/Divider/Divider.stories.tsx @@ -1,34 +1,38 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {BlockStack, Divider, Text} from '@shopify/polaris'; export default { component: Divider, -} as ComponentMeta; +} as Meta; -export function Default() { - return ; -} +export const Default = { + render() { + return ; + }, +}; -export function WithBorderStyles() { - return ( - - - Default - - - - Border - - - - Border inverse - - - - Transparent - - - - ); -} +export const WithBorderStyles = { + render() { + return ( + + + Default + + + + Border + + + + Border inverse + + + + Transparent + + + + ); + }, +}; diff --git a/polaris-react/src/components/DropZone/DropZone.stories.tsx b/polaris-react/src/components/DropZone/DropZone.stories.tsx index 3f732f4e3c7..6e6aeb29779 100644 --- a/polaris-react/src/components/DropZone/DropZone.stories.tsx +++ b/polaris-react/src/components/DropZone/DropZone.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Banner, Text, @@ -15,22 +15,183 @@ import {NoteIcon} from '@shopify/polaris-icons'; export default { component: DropZone, -} as ComponentMeta; +} as Meta; + +export const Default = { + render() { + const [files, setFiles] = useState([]); + + const handleDropZoneDrop = useCallback( + (_dropFiles, acceptedFiles, _rejectedFiles) => + setFiles((files) => [...files, ...acceptedFiles]), + [], + ); + + const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + + const fileUpload = !files.length && ; + const uploadedFiles = files.length > 0 && ( +
+ + {files.map((file, index) => ( + + +
+ {file.name}{' '} + + {file.size} bytes + +
+
+ ))} +
+
+ ); -export function Default() { - const [files, setFiles] = useState([]); + return ( + + {uploadedFiles} + {fileUpload} + + ); + }, +}; + +export const WithALabel = { + render() { + return ( + + + + ); + }, +}; + +export const WithImageFileUpload = { + render() { + const [files, setFiles] = useState([]); + const [rejectedFiles, setRejectedFiles] = useState([]); + const hasError = rejectedFiles.length > 0; + + const handleDrop = useCallback( + (_droppedFiles, acceptedFiles, rejectedFiles) => { + setFiles((files) => [...files, ...acceptedFiles]); + setRejectedFiles(rejectedFiles); + }, + [], + ); + + const fileUpload = !files.length && ; + const uploadedFiles = files.length > 0 && ( + + {files.map((file, index) => ( + + +
+ {file.name}{' '} + + {file.size} bytes + +
+
+ ))} +
+ ); - const handleDropZoneDrop = useCallback( - (_dropFiles, acceptedFiles, _rejectedFiles) => - setFiles((files) => [...files, ...acceptedFiles]), - [], - ); + const errorMessage = hasError && ( + + + {rejectedFiles.map((file, index) => ( + + {`"${file.name}" is not supported. File type must be .gif, .jpg, .png or .svg.`} + + ))} + + + ); + + return ( + + {errorMessage} + + {uploadedFiles} + {fileUpload} + + + ); + }, +}; + +export const WithSingleFileUpload = { + render() { + const [file, setFile] = useState(); + + const handleDropZoneDrop = useCallback( + (_dropFiles, acceptedFiles, _rejectedFiles) => + setFile((file) => acceptedFiles[0]), + [], + ); + + const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + + const fileUpload = !file && ; + const uploadedFile = file && ( + + +
+ {file.name}{' '} + + {file.size} bytes + +
+
+ ); + + return ( + + {uploadedFile} + {fileUpload} + + ); + }, +}; + +export const WithDropOnPage = { + render() { + const [files, setFiles] = useState([]); - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + const handleDropZoneDrop = useCallback( + (dropFiles, _acceptedFiles, _rejectedFiles) => + setFiles((files) => [...files, ...dropFiles]), + [], + ); - const fileUpload = !files.length && ; - const uploadedFiles = files.length > 0 && ( -
+ const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + + const uploadedFiles = files.length > 0 && ( {files.map((file, index) => ( @@ -52,501 +213,252 @@ export function Default() { ))} -
- ); - - return ( - - {uploadedFiles} - {fileUpload} - - ); -} - -export function WithALabel() { - return ( - - - - ); -} - -export function WithImageFileUpload() { - const [files, setFiles] = useState([]); - const [rejectedFiles, setRejectedFiles] = useState([]); - const hasError = rejectedFiles.length > 0; - - const handleDrop = useCallback( - (_droppedFiles, acceptedFiles, rejectedFiles) => { - setFiles((files) => [...files, ...acceptedFiles]); - setRejectedFiles(rejectedFiles); - }, - [], - ); - - const fileUpload = !files.length && ; - const uploadedFiles = files.length > 0 && ( - - {files.map((file, index) => ( - - -
- {file.name}{' '} - - {file.size} bytes - -
-
- ))} -
- ); - - const errorMessage = hasError && ( - - - {rejectedFiles.map((file, index) => ( - - {`"${file.name}" is not supported. File type must be .gif, .jpg, .png or .svg.`} - + ); + + const uploadMessage = !uploadedFiles && ; + + return ( + + + {uploadedFiles} + {uploadMessage} + + + ); + }, +}; + +export const AcceptsOnlySVGFiles = { + render() { + const [files, setFiles] = useState([]); + const [rejectedFiles, setRejectedFiles] = useState([]); + const hasError = rejectedFiles.length > 0; + + const handleDropZoneDrop = useCallback( + (_dropFiles, acceptedFiles, rejectedFiles) => { + setFiles((files) => [...files, ...acceptedFiles]); + setRejectedFiles(rejectedFiles); + }, + [], + ); + + const uploadedFiles = files.length > 0 && ( + + {files.map((file, index) => ( + + +
+ {file.name}{' '} + + {file.size} bytes + +
+
))} -
-
- ); - - return ( - - {errorMessage} - - {uploadedFiles} - {fileUpload} + + ); + + const errorMessage = hasError && ( + + + {rejectedFiles.map((file, index) => ( + + {`"${file.name}" is not supported. File type must be .svg.`} + + ))} + + + ); + + return ( + + {errorMessage} + + {uploadedFiles} + + + ); + }, +}; + +export const Nested = { + render() { + const [files, setFiles] = useState([]); + + const handleDrop = useCallback((dropFiles) => { + setFiles((files) => [...files, dropFiles]); + }, []); + + const handleDropZoneClick = useCallback(() => {}, []); + + const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + + const fileUpload = !files.length && ; + const uploadedFiles = files.length > 0 && ( + + {files.map((file, index) => ( + + +
+ {file.name}{' '} + + {file.size} bytes + +
+
+ ))} +
+ ); + + return ( + + + + {uploadedFiles} + {fileUpload} + + - - ); -} - -export function WithSingleFileUpload() { - const [file, setFile] = useState(); - - const handleDropZoneDrop = useCallback( - (_dropFiles, acceptedFiles, _rejectedFiles) => - setFile((file) => acceptedFiles[0]), - [], - ); - - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; - - const fileUpload = !file && ; - const uploadedFile = file && ( - - -
- {file.name}{' '} - - {file.size} bytes - -
-
- ); - - return ( - - {uploadedFile} - {fileUpload} - - ); -} - -export function WithDropOnPage() { - const [files, setFiles] = useState([]); - - const handleDropZoneDrop = useCallback( - (dropFiles, _acceptedFiles, _rejectedFiles) => - setFiles((files) => [...files, ...dropFiles]), - [], - ); - - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; - - const uploadedFiles = files.length > 0 && ( - - {files.map((file, index) => ( - - + ); + }, +}; + +export const MediumSized = { + render() { + return ( + +
- {file.name}{' '} - - {file.size} bytes + + Medium sized Drop zone
-
- ))} -
- ); - - const uploadMessage = !uploadedFiles && ; - - return ( - - - {uploadedFiles} - {uploadMessage} - - - ); -} - -export function AcceptsOnlySVGFiles() { - const [files, setFiles] = useState([]); - const [rejectedFiles, setRejectedFiles] = useState([]); - const hasError = rejectedFiles.length > 0; - - const handleDropZoneDrop = useCallback( - (_dropFiles, acceptedFiles, rejectedFiles) => { - setFiles((files) => [...files, ...acceptedFiles]); - setRejectedFiles(rejectedFiles); - }, - [], - ); - - const uploadedFiles = files.length > 0 && ( - - {files.map((file, index) => ( - - -
- {file.name}{' '} - - {file.size} bytes - +
+ + +
- - ))} - - ); - - const errorMessage = hasError && ( - - - {rejectedFiles.map((file, index) => ( - - {`"${file.name}" is not supported. File type must be .svg.`} - - ))} - - - ); - - return ( - - {errorMessage} - - {uploadedFiles} - - - ); -} - -export function Nested() { - const [files, setFiles] = useState([]); - - const handleDrop = useCallback((dropFiles) => { - setFiles((files) => [...files, dropFiles]); - }, []); - - const handleDropZoneClick = useCallback(() => {}, []); - - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; - - const fileUpload = !files.length && ; - const uploadedFiles = files.length > 0 && ( - - {files.map((file, index) => ( - - + +
- {file.name}{' '} - - {file.size} bytes + + Medium sized Drop zone with label and hint
- - ))} -
- ); - - return ( - - - - {uploadedFiles} - {fileUpload} - - - - ); -} +
+ + + +
+ + + ); + }, +}; -export function MediumSized() { - return ( - - -
+export const SmallSized = { + render() { + return ( + + - Medium sized Drop zone + Small sized Drop zone (40px) -
-
- - - -
-
- -
+ +
+ + + +
+ + - Medium sized Drop zone with label and hint + Small sized Drop zone without outline -
-
- - - -
-
-
- ); -} -export function SmallSized() { - return ( - - - - Small sized Drop zone (40px) - +
+ + + +
+
+ + + Small sized Drop zone with error + + Drag file in to see error state -
- - - -
-
- - - Small sized Drop zone without outline - +
+ + + +
+
+ + + Small sized Drop zone with disabled state + -
- - - -
-
- - - Small sized Drop zone with error - - Drag file in to see error state - -
- - - -
+
+ + + +
+
- - - Small sized Drop zone with disabled state - + ); + }, +}; -
- - - -
-
- - ); -} - -export function WithCustomFileUploadText() { - const [files, setFiles] = useState([]); - - const handleDropZoneDrop = useCallback( - (_dropFiles, acceptedFiles, _rejectedFiles) => - setFiles((files) => [...files, ...acceptedFiles]), - [], - ); - - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; - - const fileUpload = !files.length && ( - - ); - - const uploadedFiles = files.length > 0 && ( - - {files.map((file, index) => ( - - -
- {file.name}{' '} - - {file.size} bytes - -
-
- ))} -
- ); - - return ( - - {uploadedFiles} - {fileUpload} - - ); -} - -export function WithCustomFileDialogTrigger() { - const [files, setFiles] = useState([]); - const [openFileDialog, setOpenFileDialog] = useState(false); - - const handleDropZoneDrop = useCallback( - (dropFiles, _acceptedFiles, _rejectedFiles) => - setFiles((files) => [...files, ...dropFiles]), - [], - ); - const toggleOpenFileDialog = useCallback( - () => setOpenFileDialog((openFileDialog) => !openFileDialog), - [], - ); - - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; - - const uploadedFiles = files.length > 0 && ( - - {files.map((file, index) => ( - - -
- {file.name}{' '} - - {file.size} bytes - -
-
- ))} -
- ); - - return ( - - - {uploadedFiles} - - - ); -} +export const WithCustomFileUploadText = { + render() { + const [files, setFiles] = useState([]); -export function Error() { - const [files, setFiles] = useState([]); + const handleDropZoneDrop = useCallback( + (_dropFiles, acceptedFiles, _rejectedFiles) => + setFiles((files) => [...files, ...acceptedFiles]), + [], + ); - const handleDropZoneDrop = useCallback( - (_dropFiles, acceptedFiles, _rejectedFiles) => - setFiles((files) => [...files, ...acceptedFiles]), - [], - ); + const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; - const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + const fileUpload = !files.length && ( + + ); - const fileUpload = !files.length && ; - const uploadedFiles = files.length > 0 && ( -
+ const uploadedFiles = files.length > 0 && ( {files.map((file, index) => ( @@ -568,34 +480,148 @@ export function Error() { ))} -
- ); - - return ( - -
- - Drop zone with error - - Drag file in to see error state -
- + ); + + return ( + {uploadedFiles} {fileUpload} -
- ); -} - -export function Disabled() { - const handleDropZoneDrop = () => { - // eslint-disable-next-line no-alert - alert("this shouldn't be called"); - }; - - return ( - - - - ); -} + ); + }, +}; + +export const WithCustomFileDialogTrigger = { + render() { + const [files, setFiles] = useState([]); + const [openFileDialog, setOpenFileDialog] = useState(false); + + const handleDropZoneDrop = useCallback( + (dropFiles, _acceptedFiles, _rejectedFiles) => + setFiles((files) => [...files, ...dropFiles]), + [], + ); + const toggleOpenFileDialog = useCallback( + () => setOpenFileDialog((openFileDialog) => !openFileDialog), + [], + ); + + const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + + const uploadedFiles = files.length > 0 && ( + + {files.map((file, index) => ( + + +
+ {file.name}{' '} + + {file.size} bytes + +
+
+ ))} +
+ ); + + return ( + + + {uploadedFiles} + + + ); + }, +}; + +export const Error = { + render() { + const [files, setFiles] = useState([]); + + const handleDropZoneDrop = useCallback( + (_dropFiles, acceptedFiles, _rejectedFiles) => + setFiles((files) => [...files, ...acceptedFiles]), + [], + ); + + const validImageTypes = ['image/gif', 'image/jpeg', 'image/png']; + + const fileUpload = !files.length && ; + const uploadedFiles = files.length > 0 && ( +
+ + {files.map((file, index) => ( + + +
+ {file.name}{' '} + + {file.size} bytes + +
+
+ ))} +
+
+ ); + + return ( + +
+ + Drop zone with error + + Drag file in to see error state +
+ + {uploadedFiles} + {fileUpload} + +
+ ); + }, +}; + +export const Disabled = { + render() { + const handleDropZoneDrop = () => { + // eslint-disable-next-line no-alert + alert("this shouldn't be called"); + }; + + return ( + + + + ); + }, +}; diff --git a/polaris-react/src/components/EmptyState/EmptyState.stories.tsx b/polaris-react/src/components/EmptyState/EmptyState.stories.tsx index d31879b9981..83ccb1b0866 100644 --- a/polaris-react/src/components/EmptyState/EmptyState.stories.tsx +++ b/polaris-react/src/components/EmptyState/EmptyState.stories.tsx @@ -1,34 +1,89 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {LegacyCard, EmptyState, Link, Text} from '@shopify/polaris'; export default { component: EmptyState, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - - - Track and receive your incoming inventory from suppliers. - - - - ); -} +export const Default = { + render() { + return ( + + + + Track and receive your incoming inventory from suppliers. + + + + ); + }, +}; -export function WithSubduedFooterContext() { - return ( - +export const WithSubduedFooterContext = { + render() { + return ( + + + If you don’t want to add a transfer, you can import your inventory + from{' '} + + settings + + . + + } + image="https://cdn.shopify.com/s/files/1/0262/4071/2726/files/emptystate-files.png" + > + + Track and receive your incoming inventory from suppliers. + + + + ); + }, +}; + +export const WithFullWidthLayout = { + render() { + return ( + + + + You can use the Files section to upload images, videos, and other + documents. This example shows the content with a centered layout and + full width. + + + + ); + }, +}; + +export const WithoutContentContainer = { + render() { + return ( - If you don’t want to add a transfer, you can import your inventory - from{' '} - - settings - - . - - } image="https://cdn.shopify.com/s/files/1/0262/4071/2726/files/emptystate-files.png" > Track and receive your incoming inventory from suppliers. - - ); -} - -export function WithFullWidthLayout() { - return ( - - - - You can use the Files section to upload images, videos, and other - documents. This example shows the content with a centered layout and - full width. - - - - ); -} - -export function WithoutContentContainer() { - return ( - - - Track and receive your incoming inventory from suppliers. - - - ); -} + ); + }, +}; diff --git a/polaris-react/src/components/ExceptionList/ExceptionList.stories.tsx b/polaris-react/src/components/ExceptionList/ExceptionList.stories.tsx index e223128c373..885b6d81857 100644 --- a/polaris-react/src/components/ExceptionList/ExceptionList.stories.tsx +++ b/polaris-react/src/components/ExceptionList/ExceptionList.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {ExceptionList} from '@shopify/polaris'; import { NoteIcon, @@ -9,63 +9,65 @@ import { export default { component: ExceptionList, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - - ); -} +export const All = { + render() { + return ( + + ); + }, +}; diff --git a/polaris-react/src/components/Filters/Filters.stories.tsx b/polaris-react/src/components/Filters/Filters.stories.tsx index b84ee9d36b4..facbdfbf363 100644 --- a/polaris-react/src/components/Filters/Filters.stories.tsx +++ b/polaris-react/src/components/Filters/Filters.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import type {FiltersProps} from '@shopify/polaris'; import { Avatar, @@ -27,2019 +27,2048 @@ export default { }, }, }, -} as ComponentMeta; - -export function WithAResourceList() { - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - pinned: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - pinned: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters: FiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; +} as Meta; + +export const WithAResourceList = { + render() { + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; + + const appliedFilters: FiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + return ( +
+ + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } } - } -} - -export function WithADataTable() { - const [availability, setAvailability] = useState(null); - const [productType, setProductType] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAvailabilityChange = useCallback( - (value) => setAvailability(value), - [], - ); - const handleProductTypeChange = useCallback( - (value) => setProductType(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAvailabilityRemove = useCallback(() => setAvailability(null), []); - const handleProductTypeRemove = useCallback(() => setProductType(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAvailabilityRemove(); - handleProductTypeRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAvailabilityRemove, - handleQueryValueRemove, - handleProductTypeRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'availability', - label: 'Availability', - filter: ( - - ), - shortcut: true, - }, - { - key: 'productType', - label: 'Product type', - filter: ( - - ), - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - }, - ]; - - const appliedFilters: FiltersProps['appliedFilters'] = []; - if (!isEmpty(availability)) { - const key = 'availability'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, availability), - onRemove: handleAvailabilityRemove, - }); - } - if (!isEmpty(productType)) { - const key = 'productType'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, productType), - onRemove: handleProductTypeRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - - -
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - case 'availability': - return value.map((val) => `Available on ${val}`).join(', '); - case 'productType': - return value.join(', '); - default: - return value; + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } + }, +}; + +export const WithADataTable = { + render() { + const [availability, setAvailability] = useState(null); + const [productType, setProductType] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAvailabilityChange = useCallback( + (value) => setAvailability(value), + [], + ); + const handleProductTypeChange = useCallback( + (value) => setProductType(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAvailabilityRemove = useCallback( + () => setAvailability(null), + [], + ); + const handleProductTypeRemove = useCallback(() => setProductType(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAvailabilityRemove(); + handleProductTypeRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAvailabilityRemove, + handleQueryValueRemove, + handleProductTypeRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'availability', + label: 'Availability', + filter: ( + + ), + shortcut: true, + }, + { + key: 'productType', + label: 'Product type', + filter: ( + + ), + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + }, + ]; - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + const appliedFilters: FiltersProps['appliedFilters'] = []; + if (!isEmpty(availability)) { + const key = 'availability'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, availability), + onRemove: handleAvailabilityRemove, + }); + } + if (!isEmpty(productType)) { + const key = 'productType'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, productType), + onRemove: handleProductTypeRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); } - } -} - -export function WithChildrenContent() { - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - ]; - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - return ( -
- - -
- -
- - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - + + + + +
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + case 'availability': + return value.map((val) => `Available on ${val}`).join(', '); + case 'productType': + return value.join(', '); + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithChildrenContent = { + render() { + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleQueryValueChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + return ( +
+ + - - {name} - -
{location}
- - ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; +
+ +
+ + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> + +
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} - -export function WithChildrenContentAndUnsavedChanges() { - const emptyFilterState: { - query: { - label: string; - value: ''; - }; - accountStatus: { - label: string; - value: string[]; + }, +}; + +export const WithChildrenContentAndUnsavedChanges = { + render() { + const emptyFilterState: { + query: { + label: string; + value: ''; + }; + accountStatus: { + label: string; + value: string[]; + }; + moneySpent: { + label: string; + value: [number, number]; + }; + taggedWith: { + label: string; + value: ''; + }; + } = { + query: { + label: 'Search', + value: '', + }, + accountStatus: { + label: 'Account status', + value: [], + }, + moneySpent: { + label: 'Money spent', + value: [0, 0], + }, + taggedWith: { + label: 'Tagged with', + value: '', + }, }; - moneySpent: { - label: string; - value: [number, number]; + + const [queryValue, setQueryValue] = useState(''); + const [taggedWith, setTaggedWith] = useState(''); + const [moneySpent, setMoneySpent] = useState<[number, number]>([0, 0]); + const [accountStatus, setAccountStatus] = useState(['enabled']); + const [savedFilterState, setSavedFilterState] = useState< + Map< + string, + { + label: string; + value: string | string[] | number | [number, number]; + } + > + >(new Map(Object.entries(emptyFilterState))); + + const handleFilterChange = + (key: string) => + (value: string | string[] | number | [number, number]) => { + if (key === 'taggedWith') setTaggedWith(value as string); + if (key === 'moneySpent') setMoneySpent(value as [number, number]); + if (key === 'accountStatus') setAccountStatus(value as string[]); + }; + + const handleFilterRemove = (key: string) => { + if (key === 'taggedWith') { + setTaggedWith(emptyFilterState.taggedWith.value); + } else if (key === 'moneySpent') { + setMoneySpent(emptyFilterState.moneySpent.value); + } else if (key === 'accountStatus') { + setAccountStatus(emptyFilterState.accountStatus.value); + } }; - taggedWith: { - label: string; - value: ''; + + const handleFiltersQueryChange = (value: string) => setQueryValue(value); + + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + + const handleFiltersClearAll = () => { + Object.entries(emptyFilterState).forEach(([key]) => + handleFilterRemove(key), + ); + + handleQueryValueRemove(); }; - } = { - query: { - label: 'Search', - value: '', - }, - accountStatus: { - label: 'Account status', - value: [], - }, - moneySpent: { - label: 'Money spent', - value: [0, 0], - }, - taggedWith: { - label: 'Tagged with', - value: '', - }, - }; - - const [queryValue, setQueryValue] = useState(''); - const [taggedWith, setTaggedWith] = useState(''); - const [moneySpent, setMoneySpent] = useState<[number, number]>([0, 0]); - const [accountStatus, setAccountStatus] = useState(['enabled']); - const [savedFilterState, setSavedFilterState] = useState< - Map< - string, + + const filters = [ { - label: string; - value: string | string[] | number | [number, number]; + key: 'accountStatus', + label: 'Account status', + value: accountStatus, + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + value: taggedWith, + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + value: moneySpent, + filter: ( + + ), + }, + ]; + + const appliedFilters: FiltersProps['appliedFilters'] = []; + + filters.forEach(({key, label, value}) => { + if (!isEmpty(value)) { + appliedFilters.push({ + key, + label: `${label}: ${humanReadableValue(key, value)}`, + unsavedChanges: !isUnchanged(key, value), + onRemove: () => handleFilterRemove(key), + }); } - > - >(new Map(Object.entries(emptyFilterState))); - - const handleFilterChange = - (key: string) => (value: string | string[] | number | [number, number]) => { - if (key === 'taggedWith') setTaggedWith(value as string); - if (key === 'moneySpent') setMoneySpent(value as [number, number]); - if (key === 'accountStatus') setAccountStatus(value as string[]); + }); + + const handleSaveFilters = () => { + const nextSavedFilterState = new Map(savedFilterState); + appliedFilters.forEach(({key, unsavedChanges}) => { + const savedFilter = nextSavedFilterState.get(key); + const value = filters.find((filter) => filter.key === key)?.value; + console.log(`Saving filter: ${key}, ${value}`, savedFilter); + + if (value && unsavedChanges && savedFilter) { + savedFilter.value = value; + } + }); + + setSavedFilterState(nextSavedFilterState); }; - const handleFilterRemove = (key: string) => { - if (key === 'taggedWith') { - setTaggedWith(emptyFilterState.taggedWith.value); - } else if (key === 'moneySpent') { - setMoneySpent(emptyFilterState.moneySpent.value); - } else if (key === 'accountStatus') { - setAccountStatus(emptyFilterState.accountStatus.value); + const disableAction = appliedFilters.every( + ({unsavedChanges}) => !unsavedChanges, + ); + + return ( +
+ + + + + + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ( + nm.substring(0, 1)) + .join('')} + size="md" + name={name} + /> + ); + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function humanReadableValue( + key: string, + value: string | string[] | number | [number, number], + ): string { + if (isEmpty(value)) return ''; + + switch (key) { + case 'moneySpent': { + const [min, max] = value as [number, number]; + if (min === 0 && max === 0) return ''; + if (min === 0) return `up to $${max}`; + if (max === 0) return `more than $${min}`; + return `between $${min} and $${max}`; + } + case 'taggedWith': { + const tags = (value as string).trim().split(','); + if (tags.length === 1) return ` ${tags[0]}`; + else if (tags.length === 2) return `${tags[0]} and ${tags[1]}`; + return tags + .map((tag, index) => { + return index !== tags.length - 1 ? tag : `and ${tag}`; + }) + .join(', '); + } + case 'accountStatus': { + const statuses = value as string[]; + if (statuses.length === 1) { + return statuses[0]; + } else if (statuses.length === 2) { + return `${statuses[0]} or ${statuses[1]}`; + } else { + return statuses + .map((status, index) => { + return index !== statuses.length - 1 ? status : `or ${status}`; + }) + .join(', '); + } + } + default: + return ''; + } + } + + function isEmpty(value: string | string[] | number | [number, number]) { + if (Array.isArray(value)) { + return value.length === 0 || value[1] === 0; + } else { + return value === '' || value === 0 || value == null; + } } - }; - const handleFiltersQueryChange = (value: string) => setQueryValue(value); + function isUnchanged( + key: string, + value: string | string[] | number | [number, number], + ) { + if (key === 'taggedWith') { + return value === savedFilterState.get(key)?.value; + } else if (key === 'moneySpent') { + const [min, max] = value as [number, number]; + const savedMoneySpent = savedFilterState.get(key)?.value as [ + number, + number, + ]; + + return min === savedMoneySpent?.[0] && max === savedMoneySpent?.[1]; + } else if (key === 'accountStatus') { + const savedAccountStatus = + (savedFilterState.get(key)?.value as string[]) || []; + return ( + Array.isArray(value) && + value.every( + (val) => + typeof val === 'string' && + savedAccountStatus?.includes(val as string), + ) + ); + } + } + }, +}; - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); +export const Disabled = { + render() { + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); - const handleFiltersClearAll = () => { - Object.entries(emptyFilterState).forEach(([key]) => - handleFilterRemove(key), + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], ); + const handleQueryValueChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - handleQueryValueRemove(); - }; - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - value: accountStatus, - filter: ( - - ), - shortcut: true, - pinned: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - value: taggedWith, - filter: ( - - ), - shortcut: true, - pinned: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - value: moneySpent, - filter: ( - - ), - }, - ]; + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); - const appliedFilters: FiltersProps['appliedFilters'] = []; + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + return ( +
+ + +
+ +
+ + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); - filters.forEach(({key, label, value}) => { - if (!isEmpty(value)) { - appliedFilters.push({ - key, - label: `${label}: ${humanReadableValue(key, value)}`, - unsavedChanges: !isUnchanged(key, value), - onRemove: () => handleFilterRemove(key), - }); + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; + } } - }); - - const handleSaveFilters = () => { - const nextSavedFilterState = new Map(savedFilterState); - appliedFilters.forEach(({key, unsavedChanges}) => { - const savedFilter = nextSavedFilterState.get(key); - const value = filters.find((filter) => filter.key === key)?.value; - console.log(`Saving filter: ${key}, ${value}`, savedFilter); - if (value && unsavedChanges && savedFilter) { - savedFilter.value = value; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; } - }); + } + }, +}; - setSavedFilterState(nextSavedFilterState); - }; - - const disableAction = appliedFilters.every( - ({unsavedChanges}) => !unsavedChanges, - ); - - return ( -
- - - - - - - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ( - nm.substring(0, 1)) - .join('')} - size="md" - name={name} - /> - ); - - return ( - setTaggedWith(value), + [], + ); + const handleQueryValueChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleVendorChange = useCallback((value) => setVendor(value), []); + + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleVendorRemove = useCallback(() => setVendor(''), []); + + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + handleVendorRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove, handleVendorRemove]); + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'vendor', + label: 'Vendor', + filter: ( + + ), + shortcut: true, + disabled: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + return ( +
+ + - - {name} - -
{location}
- - ); - }} - /> - -
- ); - - function humanReadableValue( - key: string, - value: string | string[] | number | [number, number], - ): string { - if (isEmpty(value)) return ''; - - switch (key) { - case 'moneySpent': { - const [min, max] = value as [number, number]; - if (min === 0 && max === 0) return ''; - if (min === 0) return `up to $${max}`; - if (max === 0) return `more than $${min}`; - return `between $${min} and $${max}`; - } - case 'taggedWith': { - const tags = (value as string).trim().split(','); - if (tags.length === 1) return ` ${tags[0]}`; - else if (tags.length === 2) return `${tags[0]} and ${tags[1]}`; - return tags - .map((tag, index) => { - return index !== tags.length - 1 ? tag : `and ${tag}`; - }) - .join(', '); +
+ +
+ + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> + +
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; } - case 'accountStatus': { - const statuses = value as string[]; - if (statuses.length === 1) { - return statuses[0]; - } else if (statuses.length === 2) { - return `${statuses[0]} or ${statuses[1]}`; - } else { - return statuses - .map((status, index) => { - return index !== statuses.length - 1 ? status : `or ${status}`; - }) - .join(', '); - } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; } - default: - return ''; } - } + }, +}; + +export const WithQueryFieldHidden = { + render() { + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; - function isEmpty(value: string | string[] | number | [number, number]) { - if (Array.isArray(value)) { - return value.length === 0 || value[1] === 0; - } else { - return value === '' || value === 0 || value == null; + const appliedFilters: FiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); } - } - - function isUnchanged( - key: string, - value: string | string[] | number | [number, number], - ) { - if (key === 'taggedWith') { - return value === savedFilterState.get(key)?.value; - } else if (key === 'moneySpent') { - const [min, max] = value as [number, number]; - const savedMoneySpent = savedFilterState.get(key)?.value as [ - number, - number, - ]; - - return min === savedMoneySpent?.[0] && max === savedMoneySpent?.[1]; - } else if (key === 'accountStatus') { - const savedAccountStatus = - (savedFilterState.get(key)?.value as string[]) || []; - return ( - Array.isArray(value) && - value.every( - (val) => - typeof val === 'string' && - savedAccountStatus?.includes(val as string), - ) - ); + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); } - } -} - -export function Disabled() { - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - ]; - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - return ( -
- - -
+ return ( +
+ + -
- - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> - -
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} - -export function SomeDisabled() { - const [taggedWith, setTaggedWith] = useState(''); - const [vendor, setVendor] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleVendorChange = useCallback((value) => setVendor(value), []); - - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleVendorRemove = useCallback(() => setVendor(''), []); - - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - handleVendorRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove, handleVendorRemove]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'vendor', - label: 'Vendor', - filter: ( - - ), - shortcut: true, - disabled: true, - }, - ]; + }, +}; + +export const WithQueryFieldDisabled = { + render() { + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - return ( -
- - -
- -
- - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; + const appliedFilters: FiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + return ( +
+ + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } } - } -} - -export function WithQueryFieldHidden() { - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters: FiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - - - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } + }, +}; + +export const WithAdditionalFilterSections = { + render() { + const [accountStatus, setAccountStatus] = useState(null); + const [accountId, setAccountId] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleAccountIdChange = useCallback( + (value) => setAccountId(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleAccountIdRemove = useCallback(() => setAccountId(null), []); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleAccountIdRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleAccountIdRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + }, + { + key: 'accountStatus', + label: 'Account status', + section: 'Account filters', + filter: ( + + ), + }, + { + key: 'accountId', + label: 'Account ID', + section: 'Account filters', + filter: ( + + ), + }, + { + key: 'moneySpent', + label: 'Money spent', + section: 'Money filters', + filter: ( + + ), + }, + ]; - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + const appliedFilters: FiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); } - } -} - -export function WithQueryFieldDisabled() { - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters: FiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; + if (!isEmpty(accountId)) { + const key = 'accountId'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountId), + onRemove: handleAccountIdRemove, + }); } - } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } + + return ( +
+ + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + case 'accountId': + return `Account id: ${value}`; + default: + return value; + } } - } -} - -export function WithAdditionalFilterSections() { - const [accountStatus, setAccountStatus] = useState(null); - const [accountId, setAccountId] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleAccountIdChange = useCallback((value) => setAccountId(value), []); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleAccountIdRemove = useCallback(() => setAccountId(null), []); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleAccountIdRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleAccountIdRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - }, - { - key: 'accountStatus', - label: 'Account status', - section: 'Account filters', - filter: ( - - ), - }, - { - key: 'accountId', - label: 'Account ID', - section: 'Account filters', - filter: ( - - ), - }, - { - key: 'moneySpent', - label: 'Money spent', - section: 'Money filters', - filter: ( - - ), - }, - ]; - - const appliedFilters: FiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(accountId)) { - const key = 'accountId'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountId), - onRemove: handleAccountIdRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - case 'accountId': - return `Account id: ${value}`; - default: - return value; + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } + }, +}; + +export const WithFilterBarHidden = { + render() { + const [queryValue, setQueryValue] = useState(''); + + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleQueryValueRemove(); + }, [handleQueryValueRemove]); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + + return ( +
+ + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + }, +}; + +export const WithAllFiltersPinned = { + render() { + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + shortcut: true, + pinned: true, + }, + ]; - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + const appliedFilters: FiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); } - } -} - -export function WithFilterBarHidden() { - const [queryValue, setQueryValue] = useState(''); - - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleQueryValueRemove(); - }, [handleQueryValueRemove]); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - - return ( -
- - - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); -} - -export function WithAllFiltersPinned() { - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - pinned: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - pinned: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - shortcut: true, - pinned: true, - }, - ]; - - const appliedFilters: FiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - } - flushFilters - items={[ - { - id: '341', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: '256', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } + + return ( +
+ + + } + flushFilters + items={[ + { + id: '341', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: '256', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} + }, +}; diff --git a/polaris-react/src/components/FooterHelp/FooterHelp.stories.tsx b/polaris-react/src/components/FooterHelp/FooterHelp.stories.tsx index 134fc6a7849..32293a6fb62 100644 --- a/polaris-react/src/components/FooterHelp/FooterHelp.stories.tsx +++ b/polaris-react/src/components/FooterHelp/FooterHelp.stories.tsx @@ -6,35 +6,41 @@ export default { component: FooterHelp, } as Meta; -export function Default() { - return ( - - Learn more about{' '} - - fulfilling orders - - - ); -} +export const Default = { + render() { + return ( + + Learn more about{' '} + + fulfilling orders + + + ); + }, +}; -export function LeftAligned() { - return ( - - Learn more about{' '} - - fulfilling orders - - - ); -} +export const LeftAligned = { + render() { + return ( + + Learn more about{' '} + + fulfilling orders + + + ); + }, +}; -export function RightAligned() { - return ( - - Learn more about{' '} - - fulfilling orders - - - ); -} +export const RightAligned = { + render() { + return ( + + Learn more about{' '} + + fulfilling orders + + + ); + }, +}; diff --git a/polaris-react/src/components/Form/Form.stories.tsx b/polaris-react/src/components/Form/Form.stories.tsx index ab957bc0417..e14e50d5ee9 100644 --- a/polaris-react/src/components/Form/Form.stories.tsx +++ b/polaris-react/src/components/Form/Form.stories.tsx @@ -1,76 +1,80 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Button, Checkbox, Form, FormLayout, TextField} from '@shopify/polaris'; export default { component: Form, -} as ComponentMeta; +} as Meta; -export function CustomOnSubmit() { - const [newsletter, setNewsletter] = useState(false); - const [email, setEmail] = useState(''); +export const CustomOnSubmit = { + render() { + const [newsletter, setNewsletter] = useState(false); + const [email, setEmail] = useState(''); - const handleSubmit = useCallback((_event) => { - setEmail(''); - setNewsletter(false); - }, []); + const handleSubmit = useCallback((_event) => { + setEmail(''); + setNewsletter(false); + }, []); - const handleNewsLetterChange = useCallback( - (value) => setNewsletter(value), - [], - ); + const handleNewsLetterChange = useCallback( + (value) => setNewsletter(value), + [], + ); - const handleEmailChange = useCallback((value) => setEmail(value), []); + const handleEmailChange = useCallback((value) => setEmail(value), []); - return ( -
- - + return ( + + + - - We’ll use this email address to inform you on future changes to - Polaris. - - } - /> + + We’ll use this email address to inform you on future changes to + Polaris. + + } + /> - - - - ); -} + +
+ + ); + }, +}; -export function WithoutNativeValidation() { - const [url, setUrl] = useState(''); +export const WithoutNativeValidation = { + render() { + const [url, setUrl] = useState(''); - const handleSubmit = useCallback((_event) => setUrl(''), []); + const handleSubmit = useCallback((_event) => setUrl(''), []); - const handleUrlChange = useCallback((value) => setUrl(value), []); + const handleUrlChange = useCallback((value) => setUrl(value), []); - return ( -
- - + return ( + + + - - - - ); -} + +
+ + ); + }, +}; diff --git a/polaris-react/src/components/FormLayout/FormLayout.stories.tsx b/polaris-react/src/components/FormLayout/FormLayout.stories.tsx index 66f7958275f..35a05f161a7 100644 --- a/polaris-react/src/components/FormLayout/FormLayout.stories.tsx +++ b/polaris-react/src/components/FormLayout/FormLayout.stories.tsx @@ -1,70 +1,120 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Card, FormLayout, TextField, Text, BlockStack} from '@shopify/polaris'; export default { component: FormLayout, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - {}} autoComplete="off" /> - {}} - autoComplete="email" - /> - - ); -} - -export function FieldGroup() { - return ( - - - {}} - autoComplete="off" - /> +export const Default = { + render() { + return ( + + {}} autoComplete="off" /> {}} - autoComplete="off" + autoComplete="email" /> - - - ); -} + + ); + }, +}; + +export const FieldGroup = { + render() { + return ( + + + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + + + ); + }, +}; -export function CondensedFieldGroup() { - return ( - - - {}} autoComplete="off" /> - {}} autoComplete="off" /> - {}} autoComplete="off" /> - {}} autoComplete="off" /> - - - ); -} +export const CondensedFieldGroup = { + render() { + return ( + + + {}} autoComplete="off" /> + {}} autoComplete="off" /> + {}} autoComplete="off" /> + {}} autoComplete="off" /> + + + ); + }, +}; -export function All() { - return ( - - - - - Card title - +export const All = { + render() { + return ( + + + + + Card title + + + + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + + + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + + + + + {}} autoComplete="off" /> - - - {}} - autoComplete="off" - /> - {}} - autoComplete="off" - /> {}} autoComplete="off" /> + + + + + + {}} autoComplete="off" + helpText="Field help text" /> - - - - - - {}} autoComplete="off" /> - {}} autoComplete="off" /> - {}} autoComplete="off" /> - - - - - - - {}} - autoComplete="off" - helpText="Field help text" - /> - - - - - ); -} + +
+ ); + }, +}; diff --git a/polaris-react/src/components/Frame/Frame.stories.tsx b/polaris-react/src/components/Frame/Frame.stories.tsx index c4d7f7990cc..19e02332eb5 100644 --- a/polaris-react/src/components/Frame/Frame.stories.tsx +++ b/polaris-react/src/components/Frame/Frame.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useRef, useState} from 'react'; -import type {Args, ComponentMeta} from '@storybook/react'; +import type {Args, Meta} from '@storybook/react'; import { ActionList, AppProvider, @@ -32,7 +32,7 @@ export default { component: Frame, args: {omitAppProvider: true}, parameters: {layout: 'fullscreen'}, -} as ComponentMeta; +} as Meta; export const InAnApplication = { render: (_args: Args) => , diff --git a/polaris-react/src/components/FullscreenBar/FullscreenBar.stories.tsx b/polaris-react/src/components/FullscreenBar/FullscreenBar.stories.tsx index f4f7a8c6615..4da17a8c886 100644 --- a/polaris-react/src/components/FullscreenBar/FullscreenBar.stories.tsx +++ b/polaris-react/src/components/FullscreenBar/FullscreenBar.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Badge, Button, @@ -14,113 +14,121 @@ import {useBreakpoints} from '../../utilities/breakpoints'; export default { component: FullscreenBar, parameters: {layout: 'fullscreen'}, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - <> - - - With children - - - +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + <> + + + With children + + + - - - No children - - - - - ); -} + + + No children + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function WithChildren() { - const [isFullscreen, setFullscreen] = useState(true); - const breakpoints = useBreakpoints(); +export const WithChildren = { + render() { + const [isFullscreen, setFullscreen] = useState(true); + const breakpoints = useBreakpoints(); - const handleActionClick = useCallback(() => { - setFullscreen(false); - }, []); + const handleActionClick = useCallback(() => { + setFullscreen(false); + }, []); - const titleContentMarkup = breakpoints.mdUp ? ( - - Join our email list - - ) : null; + const titleContentMarkup = breakpoints.mdUp ? ( + + Join our email list + + ) : null; - const titleMarkup = ( -
- {titleContentMarkup} -
- ); - - const fullscreenBarMarkup = ( - + const titleMarkup = (
- Draft - {titleMarkup} - - - - + {titleContentMarkup}
-
- ); + ); + + const fullscreenBarMarkup = ( + +
+ Draft + {titleMarkup} + + + + +
+
+ ); - return ( -
- {isFullscreen && fullscreenBarMarkup} -
- {!isFullscreen && ( - - )} - - Page content - + return ( +
+ {isFullscreen && fullscreenBarMarkup} +
+ {!isFullscreen && ( + + )} + + Page content + +
-
- ); -} + ); + }, +}; -export function NoChildren() { - const [isFullscreen, setFullscreen] = useState(true); +export const NoChildren = { + render() { + const [isFullscreen, setFullscreen] = useState(true); - const handleActionClick = useCallback(() => { - setFullscreen(false); - }, []); + const handleActionClick = useCallback(() => { + setFullscreen(false); + }, []); - const fullscreenBarMarkup = ; + const fullscreenBarMarkup = ; - return ( -
- {isFullscreen && fullscreenBarMarkup} -
- {!isFullscreen && ( - - )} - - Page content - + return ( +
+ {isFullscreen && fullscreenBarMarkup} +
+ {!isFullscreen && ( + + )} + + Page content + +
-
- ); -} + ); + }, +}; diff --git a/polaris-react/src/components/Grid/Grid.stories.tsx b/polaris-react/src/components/Grid/Grid.stories.tsx index 935ecb6bbf2..d4f070a2208 100644 --- a/polaris-react/src/components/Grid/Grid.stories.tsx +++ b/polaris-react/src/components/Grid/Grid.stories.tsx @@ -1,130 +1,138 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {LegacyCard, Grid, Page, Text} from '@shopify/polaris'; export default { component: Grid, -} as ComponentMeta; +} as Meta; -export function TwoColumn() { - return ( - - - - - - View a summary of your online store’s sales. - - - - - - - View a summary of your online store’s orders. - - - - - - ); -} - -export function TwoThirdsAndOneThirdColumn() { - return ( - - - - - - View a summary of your online store’s sales. - - - - - - - View a summary of your online store’s orders. - - - - - - ); -} +export const TwoColumn = { + render() { + return ( + + + + + + View a summary of your online store’s sales. + + + + + + + View a summary of your online store’s orders. + + + + + + ); + }, +}; -export function ThreeOneThirdColumn() { - return ( - - - - - - View a summary of your online store’s sales. - - - - - - - View a summary of your online store’s orders. - - - - - - - View a summary of your online store’s orders. - - - - - - ); -} +export const TwoThirdsAndOneThirdColumn = { + render() { + return ( + + + + + + View a summary of your online store’s sales. + + + + + + + View a summary of your online store’s orders. + + + + + + ); + }, +}; -export function CustomLayout() { - return ( - - - - -
+export const ThreeOneThirdColumn = { + render() { + return ( + + + + + + View a summary of your online store’s sales. + + - -
+ + + + View a summary of your online store’s orders. + + - -
+ + + + View a summary of your online store’s orders. + + - - - ); -} + + ); + }, +}; + +export const CustomLayout = { + render() { + return ( + + + + +
+ + +
+ + +
+ + + + + ); + }, +}; diff --git a/polaris-react/src/components/Icon/Icon.stories.tsx b/polaris-react/src/components/Icon/Icon.stories.tsx index aa05149f350..24412a01fb4 100644 --- a/polaris-react/src/components/Icon/Icon.stories.tsx +++ b/polaris-react/src/components/Icon/Icon.stories.tsx @@ -1,171 +1,187 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Icon, Text, BlockStack, InlineStack} from '@shopify/polaris'; import * as polarisIcons from '@shopify/polaris-icons'; import iconMetadata from '@shopify/polaris-icons/metadata'; export default { component: Icon, -} as ComponentMeta; +} as Meta; interface Icons { [key: string]: any; } const icons: Icons = polarisIcons; -export function Default() { - return ; -} - -export function Colored() { - return ( - - - Base tone - - - - Subdued tone - - - - Primary tone - - - - Info tone - - - - Success tone - - - - Caution tone - - - - Warning tone - - - - Critical tone - - - - Emphasis tone - - - - Magic tone - - - - Text Primary tone - - - - Text Caution tone - - - - Text Warning tone - - - - Text Critical tone - - - - Text Info tone - - - - Text Success tone - - - - Text Magic tone - - - - ); -} +export const Default = { + render() { + return ; + }, +}; -export function WithToneInherit() { - return ( - - - Caution tone - - - - Critical tone - - - - Magic tone - - - - Magic subdued tone - - - - Subdued tone - - - - Success tone - - - - Text inverse tone - - - - ); -} +export const Colored = { + render() { + return ( + + + Base tone + + + + Subdued tone + + + + Primary tone + + + + Info tone + + + + Success tone + + + + Caution tone + + + + Warning tone + + + + Critical tone + + + + Emphasis tone + + + + Magic tone + + + + Text Primary tone + + + + Text Caution tone + + + + Text Warning tone + + + + Text Critical tone + + + + Text Info tone + + + + Text Success tone + + + + Text Magic tone + + + + ); + }, +}; -export function WithPlaceholder() { - return ; -} +export const WithToneInherit = { + render() { + return ( + + + Caution tone + + + + Critical tone + + + + Magic tone + + + + Magic subdued tone + + + + Subdued tone + + + + Success tone + + + + Text inverse tone + + + + ); + }, +}; -export function WithExternalIcon() { - return ( - - ); -} +export const WithPlaceholder = { + render() { + return ; + }, +}; -export function WithCustomSVG() { - return ( - - ); -} +export const WithExternalIcon = { + render() { + return ( + + ); + }, +}; -export function WithCustomSVGAndColor() { - const iconContent = () => { +export const WithCustomSVG = { + render() { return ( - - - - - + ); - }; + }, +}; - return ; -} +export const WithCustomSVGAndColor = { + render() { + const iconContent = () => { + return ( + + + + + + ); + }; -export function PolarisIconsLibrary() { - return ( - - {Object.keys(iconMetadata).map((icon) => ( - - - {icon} - - ))} - - ); -} + return ; + }, +}; + +export const PolarisIconsLibrary = { + render() { + return ( + + {Object.keys(iconMetadata).map((icon) => ( + + + {icon} + + ))} + + ); + }, +}; diff --git a/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx b/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx index bcd43e1f216..bf66c5f12b1 100644 --- a/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx +++ b/polaris-react/src/components/IndexFilters/IndexFilters.stories.tsx @@ -1,5 +1,5 @@ import React, {useState, useCallback, useEffect} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import type {TabProps} from '@shopify/polaris'; import { ChoiceList, @@ -30,7 +30,7 @@ export default { }, }, }, -} as ComponentMeta; +} as Meta; function Table() { const customers = [ @@ -419,2101 +419,2134 @@ function BasicExample( } } -export function Default() { - return ; -} - -export function WithFilteringByDefault() { - return ; -} - -export function WithEditColumsButton() { - return ; -} - -export function WithoutKeyboardShortcuts() { - return ; -} - -export function WithLoading() { - return ; -} - -export function WithPinnedFilters() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [itemStrings, setItemStrings] = useState([ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ]); - const deleteView = (index: number) => { - const newItemStrings = [...itemStrings]; - newItemStrings.splice(index, 1); - setItemStrings(newItemStrings); - setSelected(0); - }; - - const duplicateView = async (name: string) => { - setItemStrings([...itemStrings, name]); - setSelected(itemStrings.length); - await sleep(1); - return true; - }; - - const tabs: TabProps[] = itemStrings.map((item, index) => ({ - content: item, - index, - onAction: () => {}, - id: `${item}-${index}`, - isLocked: index === 0, - actions: - index === 0 - ? [] - : [ - { - type: 'rename', - onAction: () => {}, - onPrimaryAction: async (value: string) => { - const newItemsStrings = tabs.map((item, idx) => { - if (idx === index) { - return value; - } - return item.content; - }); - await sleep(1); - setItemStrings(newItemsStrings); - return true; - }, - }, - { - type: 'duplicate', - onPrimaryAction: async (name) => { - await sleep(1); - duplicateView(name); - return true; - }, - }, - { - type: 'edit', - }, - { - type: 'delete', - onPrimaryAction: async (id: string) => { - await sleep(1); - deleteView(index); - return true; - }, - }, - ], - })); - const [selected, setSelected] = useState(0); - const onCreateNewView = async (value: string) => { - await sleep(500); - setItemStrings([...itemStrings, value]); - setSelected(itemStrings.length); - return true; - }; - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(); - const onHandleCancel = () => {}; - - const onHandleSave = async () => { - await sleep(1); - return true; - }; - - const primaryAction: IndexFiltersProps['primaryAction'] = - selected === 0 - ? { - type: 'save-as', - onAction: onCreateNewView, - disabled: false, - loading: false, - } - : { - type: 'save', - onAction: onHandleSave, - disabled: false, - loading: false, - }; - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - pinned: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - pinned: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters: IndexFiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( - - setQueryValue('')} - onSort={setSortSelected} - primaryAction={primaryAction} - cancelAction={{ - onAction: onHandleCancel, - disabled: false, - loading: false, - }} - tabs={tabs} - selected={selected} - onSelect={setSelected} - canCreateNewView - onCreateNewView={onCreateNewView} - filters={filters} - appliedFilters={appliedFilters} - onClearAll={handleFiltersClearAll} - mode={mode} - setMode={setMode} - /> - - - ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; - } - } - - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function WithPrefilledFilters() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [itemStrings, setItemStrings] = useState([ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ]); - const deleteView = (index: number) => { - const newItemStrings = [...itemStrings]; - newItemStrings.splice(index, 1); - setItemStrings(newItemStrings); - setSelected(0); - }; - - const duplicateView = async (name: string) => { - setItemStrings([...itemStrings, name]); - setSelected(itemStrings.length); - await sleep(1); - return true; - }; - - const tabs: TabProps[] = itemStrings.map((item, index) => ({ - content: item, - index, - onAction: () => {}, - id: `${item}-${index}`, - isLocked: index === 0, - actions: - index === 0 - ? [] - : [ - { - type: 'rename', - onAction: () => {}, - onPrimaryAction: async (value: string) => { - const newItemsStrings = tabs.map((item, idx) => { - if (idx === index) { - return value; - } - return item.content; - }); - await sleep(1); - setItemStrings(newItemsStrings); - return true; - }, - }, - { - type: 'duplicate', - onPrimaryAction: async (name) => { - await sleep(1); - duplicateView(name); - return true; - }, - }, - { - type: 'edit', - }, - { - type: 'delete', - onPrimaryAction: async (id: string) => { - await sleep(1); - deleteView(index); - return true; - }, - }, - ], - })); - const [selected, setSelected] = useState(0); - const onCreateNewView = async (value: string) => { - await sleep(500); - setItemStrings([...itemStrings, value]); - setSelected(itemStrings.length); - return true; - }; - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(); - const onHandleCancel = () => {}; - - const onHandleSave = async () => { - await sleep(1); - return true; - }; - - const primaryAction: IndexFiltersProps['primaryAction'] = - selected === 0 - ? { - type: 'save-as', - onAction: onCreateNewView, - disabled: false, - loading: false, - } - : { - type: 'save', - onAction: onHandleSave, - disabled: false, - loading: false, - }; - const [accountStatus, setAccountStatus] = useState([ - 'enabled', - ]); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState('Returning customer'); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters: IndexFiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( - - setQueryValue('')} - onSort={setSortSelected} - primaryAction={primaryAction} - cancelAction={{ - onAction: onHandleCancel, - disabled: false, - loading: false, - }} - tabs={tabs} - selected={selected} - onSelect={setSelected} - canCreateNewView - onCreateNewView={onCreateNewView} - filters={filters} - appliedFilters={appliedFilters} - onClearAll={handleFiltersClearAll} - mode={mode} - setMode={setMode} - /> -
- - ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; - } - } - - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function WithHiddenFilter() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [itemStrings, setItemStrings] = useState([ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ]); - const deleteView = (index: number) => { - const newItemStrings = [...itemStrings]; - newItemStrings.splice(index, 1); - setItemStrings(newItemStrings); - setSelected(0); - }; - - const duplicateView = async (name: string) => { - setItemStrings([...itemStrings, name]); - setSelected(itemStrings.length); - await sleep(1); - return true; - }; - - const tabs: TabProps[] = itemStrings.map((item, index) => ({ - content: item, - index, - onAction: () => {}, - id: `${item}-${index}`, - isLocked: index === 0, - actions: - index === 0 - ? [] - : [ - { - type: 'rename', - onAction: () => {}, - onPrimaryAction: async (value: string) => { - const newItemsStrings = tabs.map((item, idx) => { - if (idx === index) { - return value; - } - return item.content; - }); - await sleep(1); - setItemStrings(newItemsStrings); - return true; - }, - }, - { - type: 'duplicate', - onPrimaryAction: async (name) => { - await sleep(1); - duplicateView(name); - return true; - }, - }, - { - type: 'edit', - }, - { - type: 'delete', - onPrimaryAction: async (id: string) => { - await sleep(1); - deleteView(index); - return true; - }, - }, - ], - })); - const [selected, setSelected] = useState(0); - const onCreateNewView = async (value: string) => { - await sleep(500); - setItemStrings([...itemStrings, value]); - setSelected(itemStrings.length); - return true; - }; - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(IndexFiltersMode.Filtering); - const onHandleCancel = () => {}; - - const onHandleSave = async () => { - await sleep(1); - return true; - }; - - const primaryAction: IndexFiltersProps['primaryAction'] = - selected === 0 - ? { - type: 'save-as', - onAction: onCreateNewView, - disabled: false, - loading: false, - } - : { - type: 'save', - onAction: onHandleSave, - disabled: false, - loading: false, - }; - const [accountStatus, setAccountStatus] = useState([ - 'enabled', - ]); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState('Returning customer'); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - { - key: 'hiddenFilter', - label: 'Filter not accessible from the dropdown', - hidden: true, - filter: null, - }, - ]; - - const appliedFilters: IndexFiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - appliedFilters.push({ - key: 'hiddenFilter', - label: 'Filter not accessible from the dropdown', - onRemove: handleTaggedWithRemove, - }); - - return ( - - setQueryValue('')} - onSort={setSortSelected} - primaryAction={primaryAction} - cancelAction={{ - onAction: onHandleCancel, - disabled: false, - loading: false, - }} - tabs={tabs} - selected={selected} - onSelect={setSelected} - canCreateNewView - onCreateNewView={onCreateNewView} - filters={filters} - appliedFilters={appliedFilters} - onClearAll={handleFiltersClearAll} - mode={mode} - setMode={setMode} - /> -
- - ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; - } - } - - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function WithAsyncData() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [loadData, setLoadData] = useState(false); - const [addAsyncFilter, setAddAsyncFilter] = useState(false); - const [itemStrings, setItemStrings] = useState([ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ]); - const deleteView = (index: number) => { - const newItemStrings = [...itemStrings]; - newItemStrings.splice(index, 1); - setItemStrings(newItemStrings); - setSelected(0); - }; - - const duplicateView = async (name: string) => { - setItemStrings([...itemStrings, name]); - setSelected(itemStrings.length); - await sleep(1); - return true; - }; - - const tabs: TabProps[] = itemStrings.map((item, index) => ({ - content: item, - index, - onAction: () => {}, - id: `${item}-${index}`, - isLocked: index === 0, - actions: - index === 0 - ? [] - : [ - { - type: 'rename', - onAction: () => {}, - onPrimaryAction: async (value: string) => { - const newItemsStrings = tabs.map((item, idx) => { - if (idx === index) { - return value; - } - return item.content; - }); - await sleep(1); - setItemStrings(newItemsStrings); - return true; - }, - }, - { - type: 'duplicate', - onPrimaryAction: async (name) => { - await sleep(1); - duplicateView(name); - return true; - }, - }, - { - type: 'edit', - }, - { - type: 'delete', - onPrimaryAction: async (id: string) => { - await sleep(1); - deleteView(index); - return true; - }, - }, - ], - })); - const [selected, setSelected] = useState(0); - const onCreateNewView = async (value: string) => { - await sleep(500); - setItemStrings([...itemStrings, value]); - setSelected(itemStrings.length); - return true; - }; - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(IndexFiltersMode.Filtering); - const onHandleCancel = () => {}; - - const onHandleSave = async () => { - await sleep(1); - return true; - }; - - const primaryAction: IndexFiltersProps['primaryAction'] = - selected === 0 - ? { - type: 'save-as', - onAction: onCreateNewView, - disabled: false, - loading: false, - } - : { - type: 'save', - onAction: onHandleSave, - disabled: false, - loading: false, - }; - const [accountStatus, setAccountStatus] = useState([ - 'enabled', - ]); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState('Returning customer'); - const [deliveryMethod, setDeliveryMethod] = useState([ - 'local_pick_up', - 'local_delivery', - ]); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleDeliveryMethodChange = useCallback( - (value) => setDeliveryMethod(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleDeliveryMethodRemove = useCallback( - () => setDeliveryMethod(null), - [], - ); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleDeliveryMethodRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - handleDeliveryMethodRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - if (addAsyncFilter) { - filters.push({ - key: 'delivery_method', - label: 'Delivery method', - filter: ( - - ), - }); - } - - const appliedFilters: IndexFiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - if (!isEmpty(deliveryMethod)) { - const key = 'delivery_method'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, deliveryMethod), - onRemove: handleDeliveryMethodRemove, - }); - } - - return ( - - setQueryValue('')} - onSort={setSortSelected} - primaryAction={primaryAction} - cancelAction={{ - onAction: onHandleCancel, - disabled: false, - loading: false, - }} - tabs={tabs} - selected={selected} - onSelect={setSelected} - canCreateNewView - onCreateNewView={onCreateNewView} - filters={loadData ? filters : []} - appliedFilters={loadData ? appliedFilters : []} - onClearAll={handleFiltersClearAll} - mode={mode} - setMode={setMode} - /> -
-
- - - - -
- - ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - case 'delivery_method': - return `Delivery method: ${value.join(', ')}`; - default: - return value; - } - } - - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function Disabled() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [itemStrings, setItemStrings] = useState([ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ]); - const deleteView = (index: number) => { - const newItemStrings = [...itemStrings]; - newItemStrings.splice(index, 1); - setItemStrings(newItemStrings); - setSelected(0); - }; - - const duplicateView = async (name: string) => { - setItemStrings([...itemStrings, name]); - setSelected(itemStrings.length); - await sleep(1); - return true; - }; - - const tabs: TabProps[] = itemStrings.map((item, index) => ({ - content: item, - index, - onAction: () => {}, - id: `${item}-${index}`, - isLocked: index === 0, - actions: - index === 0 - ? [] - : [ - { - type: 'rename', - onAction: () => {}, - onPrimaryAction: async (value: string) => { - const newItemsStrings = tabs.map((item, idx) => { - if (idx === index) { - return value; - } - return item.content; - }); - await sleep(1); - setItemStrings(newItemsStrings); - return true; - }, - }, - { - type: 'duplicate', - onPrimaryAction: async (name) => { - await sleep(1); - duplicateView(name); - return true; - }, - }, - { - type: 'edit', - }, - { - type: 'delete', - onPrimaryAction: async (id: string) => { - await sleep(1); - deleteView(index); - return true; - }, - }, - ], - })); - const [selected, setSelected] = useState(0); - const onCreateNewView = async (value: string) => { - await sleep(500); - setItemStrings([...itemStrings, value]); - setSelected(itemStrings.length); - return true; - }; - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(); - const onHandleCancel = () => {}; - - const onHandleSave = async () => { - await sleep(1); - return true; - }; - - const primaryAction: IndexFiltersProps['primaryAction'] = - selected === 0 - ? { - type: 'save-as', - onAction: onCreateNewView, - disabled: false, - loading: false, - } - : { - type: 'save', - onAction: onHandleSave, - disabled: false, - loading: false, - }; - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(''); - const [queryValue, setQueryValue] = useState(''); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters: IndexFiltersProps['appliedFilters'] = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( - - setQueryValue('')} - onSort={setSortSelected} - primaryAction={primaryAction} - cancelAction={{ - onAction: onHandleCancel, - disabled: false, - loading: false, - }} - tabs={tabs} - selected={selected} - onSelect={setSelected} - canCreateNewView - onCreateNewView={onCreateNewView} - filters={filters} - appliedFilters={appliedFilters} - onClearAll={handleFiltersClearAll} - mode={mode} - setMode={setMode} - disabled - showEditColumnsButton - /> -
- - ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; - } - } - - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function WithQueryFieldAndFiltersHidden() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [itemStrings, setItemStrings] = useState([ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ]); - const deleteView = (index: number) => { - const newItemStrings = [...itemStrings]; - newItemStrings.splice(index, 1); - setItemStrings(newItemStrings); - setSelected(0); - }; - - const duplicateView = async (name: string) => { - setItemStrings([...itemStrings, name]); - setSelected(itemStrings.length); - await sleep(1); - return true; - }; - - const tabs: TabProps[] = itemStrings.map((item, index) => ({ - content: item, - index, - onAction: () => {}, - id: `${item}-${index}`, - isLocked: index === 0, - actions: - index === 0 - ? [] - : [ - { - type: 'rename', - onAction: () => {}, - onPrimaryAction: async (value: string) => { - const newItemsStrings = tabs.map((item, idx) => { - if (idx === index) { - return value; - } - return item.content; - }); - await sleep(1); - setItemStrings(newItemsStrings); - return true; - }, - }, - { - type: 'duplicate', - onPrimaryAction: async (name) => { - await sleep(1); - duplicateView(name); - return true; - }, - }, - { - type: 'edit', - }, - { - type: 'delete', - onPrimaryAction: async (id: string) => { - await sleep(1); - deleteView(index); - return true; - }, - }, - ], - })); - const [selected, setSelected] = useState(0); - const onCreateNewView = async (value: string) => { - await sleep(500); - setItemStrings([...itemStrings, value]); - setSelected(itemStrings.length); - return true; - }; - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(); - const onHandleCancel = () => {}; - - const onHandleSave = async () => { - await sleep(1); - return true; - }; - - const primaryAction: IndexFiltersProps['primaryAction'] = - selected === 0 - ? { - type: 'save-as', - onAction: onCreateNewView, - disabled: false, - loading: false, - } - : { - type: 'save', - onAction: onHandleSave, - disabled: false, - loading: false, - }; +export const Default = { + render() { + return ; + }, +}; - return ( - - {}} - onQueryClear={() => {}} - onSort={setSortSelected} - primaryAction={primaryAction} - cancelAction={{ - onAction: onHandleCancel, - disabled: false, - loading: false, - }} - tabs={tabs} - selected={selected} - onSelect={setSelected} - canCreateNewView - onCreateNewView={onCreateNewView} - filters={[]} - onClearAll={() => {}} - mode={mode} - setMode={setMode} - hideQueryField - hideFilters - /> -
- - ); -} +export const WithFilteringByDefault = { + render() { + return ; + }, +}; -export function WithNoFilters() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [itemStrings, setItemStrings] = useState([ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ]); - const deleteView = (index: number) => { - const newItemStrings = [...itemStrings]; - newItemStrings.splice(index, 1); - setItemStrings(newItemStrings); - setSelected(0); - }; +export const WithEditColumsButton = { + render() { + return ; + }, +}; - const duplicateView = async (name: string) => { - setItemStrings([...itemStrings, name]); - setSelected(itemStrings.length); - await sleep(1); - return true; - }; +export const WithoutKeyboardShortcuts = { + render() { + return ; + }, +}; - const tabs: TabProps[] = itemStrings.map((item, index) => ({ - content: item, - index, - onAction: () => {}, - id: `${item}-${index}`, - isLocked: index === 0, - actions: - index === 0 - ? [] - : [ - { - type: 'rename', - onAction: () => {}, - onPrimaryAction: async (value: string): Promise => { - const newItemsStrings = tabs.map((item, idx) => { - if (idx === index) { - return value; - } - return item.content; - }); - await sleep(1); - setItemStrings(newItemsStrings); - return true; +export const WithLoading = { + render() { + return ; + }, +}; + +export const WithPinnedFilters = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [itemStrings, setItemStrings] = useState([ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ]); + const deleteView = (index: number) => { + const newItemStrings = [...itemStrings]; + newItemStrings.splice(index, 1); + setItemStrings(newItemStrings); + setSelected(0); + }; + + const duplicateView = async (name: string) => { + setItemStrings([...itemStrings, name]); + setSelected(itemStrings.length); + await sleep(1); + return true; + }; + + const tabs: TabProps[] = itemStrings.map((item, index) => ({ + content: item, + index, + onAction: () => {}, + id: `${item}-${index}`, + isLocked: index === 0, + actions: + index === 0 + ? [] + : [ + { + type: 'rename', + onAction: () => {}, + onPrimaryAction: async (value: string) => { + const newItemsStrings = tabs.map((item, idx) => { + if (idx === index) { + return value; + } + return item.content; + }); + await sleep(1); + setItemStrings(newItemsStrings); + return true; + }, }, - }, - { - type: 'duplicate', - onPrimaryAction: async (value: string): Promise => { - await sleep(1); - duplicateView(value); - return true; + { + type: 'duplicate', + onPrimaryAction: async (name) => { + await sleep(1); + duplicateView(name); + return true; + }, }, - }, - { - type: 'edit', - }, - { - type: 'delete', - onPrimaryAction: async () => { - await sleep(1); - deleteView(index); - return true; + { + type: 'edit', }, - }, - ], - })); - const [selected, setSelected] = useState(0); - const onCreateNewView = async (value: string) => { - await sleep(500); - setItemStrings([...itemStrings, value]); - setSelected(itemStrings.length); - return true; - }; - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(); - const onHandleCancel = () => {}; - - const onHandleSave = async () => { - await sleep(1); - return true; - }; - - const primaryAction: IndexFiltersProps['primaryAction'] = - selected === 0 - ? { - type: 'save-as', - onAction: onCreateNewView, - disabled: false, - loading: false, - } - : { - type: 'save', - onAction: onHandleSave, - disabled: false, - loading: false, - }; - const [queryValue, setQueryValue] = useState(''); - - const handleFiltersQueryChange = useCallback( - (value: string) => setQueryValue(value), - [], - ); - - const orders = [ - { - id: '1020', - order: ( - - #1020 - - ), - date: 'Jul 20 at 4:34pm', - customer: 'Jaydon Stanton', - total: '$969.44', - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - }, - { - id: '1019', - order: ( - - #1019 - - ), - date: 'Jul 20 at 3:46pm', - customer: 'Ruben Westerfelt', - total: '$701.19', - paymentStatus: Partially paid, - fulfillmentStatus: Unfulfilled, - }, - { - id: '1018', - order: ( - - #1018 - - ), - date: 'Jul 20 at 3.44pm', - customer: 'Leo Carder', - total: '$798.24', - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - }, - ]; - const resourceName = { - singular: 'order', - plural: 'orders', - }; + { + type: 'delete', + onPrimaryAction: async (id: string) => { + await sleep(1); + deleteView(index); + return true; + }, + }, + ], + })); + const [selected, setSelected] = useState(0); + const onCreateNewView = async (value: string) => { + await sleep(500); + setItemStrings([...itemStrings, value]); + setSelected(itemStrings.length); + return true; + }; + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const primaryAction: IndexFiltersProps['primaryAction'] = + selected === 0 + ? { + type: 'save-as', + onAction: onCreateNewView, + disabled: false, + loading: false, + } + : { + type: 'save', + onAction: onHandleSave, + disabled: false, + loading: false, + }; + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + pinned: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + pinned: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; + + const appliedFilters: IndexFiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(orders); + return ( + + setQueryValue('')} + onSort={setSortSelected} + primaryAction={primaryAction} + cancelAction={{ + onAction: onHandleCancel, + disabled: false, + loading: false, + }} + tabs={tabs} + selected={selected} + onSelect={setSelected} + canCreateNewView + onCreateNewView={onCreateNewView} + filters={filters} + appliedFilters={appliedFilters} + onClearAll={handleFiltersClearAll} + mode={mode} + setMode={setMode} + /> +
+ + ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } + } - const rowMarkup = orders.map( - ( - {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithPrefilledFilters = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [itemStrings, setItemStrings] = useState([ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ]); + const deleteView = (index: number) => { + const newItemStrings = [...itemStrings]; + newItemStrings.splice(index, 1); + setItemStrings(newItemStrings); + setSelected(0); + }; + + const duplicateView = async (name: string) => { + setItemStrings([...itemStrings, name]); + setSelected(itemStrings.length); + await sleep(1); + return true; + }; + + const tabs: TabProps[] = itemStrings.map((item, index) => ({ + content: item, index, - ) => ( - - - - {order} - - - - - {date} - - - - - {customer} - - - - - {total} - - - - - {paymentStatus} - - - - - {fulfillmentStatus} - - - - ), - ); + onAction: () => {}, + id: `${item}-${index}`, + isLocked: index === 0, + actions: + index === 0 + ? [] + : [ + { + type: 'rename', + onAction: () => {}, + onPrimaryAction: async (value: string) => { + const newItemsStrings = tabs.map((item, idx) => { + if (idx === index) { + return value; + } + return item.content; + }); + await sleep(1); + setItemStrings(newItemsStrings); + return true; + }, + }, + { + type: 'duplicate', + onPrimaryAction: async (name) => { + await sleep(1); + duplicateView(name); + return true; + }, + }, + { + type: 'edit', + }, + { + type: 'delete', + onPrimaryAction: async (id: string) => { + await sleep(1); + deleteView(index); + return true; + }, + }, + ], + })); + const [selected, setSelected] = useState(0); + const onCreateNewView = async (value: string) => { + await sleep(500); + setItemStrings([...itemStrings, value]); + setSelected(itemStrings.length); + return true; + }; + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const primaryAction: IndexFiltersProps['primaryAction'] = + selected === 0 + ? { + type: 'save-as', + onAction: onCreateNewView, + disabled: false, + loading: false, + } + : { + type: 'save', + onAction: onHandleSave, + disabled: false, + loading: false, + }; + const [accountStatus, setAccountStatus] = useState([ + 'enabled', + ]); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState('Returning customer'); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; + + const appliedFilters: IndexFiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } - return ( - - setQueryValue('')} - onSort={setSortSelected} - primaryAction={primaryAction} - cancelAction={{ - onAction: onHandleCancel, - disabled: false, - loading: false, - }} - tabs={tabs} - selected={selected} - onSelect={setSelected} - canCreateNewView - onCreateNewView={onCreateNewView} - filters={[]} - appliedFilters={[]} - onClearAll={() => {}} - mode={mode} - setMode={setMode} - hideFilters - filteringAccessibilityTooltip="Search (F)" - /> - - {rowMarkup} - - - ); -} + return ( + + setQueryValue('')} + onSort={setSortSelected} + primaryAction={primaryAction} + cancelAction={{ + onAction: onHandleCancel, + disabled: false, + loading: false, + }} + tabs={tabs} + selected={selected} + onSelect={setSelected} + canCreateNewView + onCreateNewView={onCreateNewView} + filters={filters} + appliedFilters={appliedFilters} + onClearAll={handleFiltersClearAll} + mode={mode} + setMode={setMode} + /> +
+ + ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } + } -export function WithOnlySearchAndSort() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, - {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, - {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, - {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, - {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, - {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, - {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, - {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, - ]; - const [sortSelected, setSortSelected] = useState(['order asc']); - const {mode, setMode} = useSetIndexFiltersMode(IndexFiltersMode.Filtering); - const onHandleCancel = () => {}; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithHiddenFilter = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [itemStrings, setItemStrings] = useState([ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ]); + const deleteView = (index: number) => { + const newItemStrings = [...itemStrings]; + newItemStrings.splice(index, 1); + setItemStrings(newItemStrings); + setSelected(0); + }; + + const duplicateView = async (name: string) => { + setItemStrings([...itemStrings, name]); + setSelected(itemStrings.length); + await sleep(1); + return true; + }; + + const tabs: TabProps[] = itemStrings.map((item, index) => ({ + content: item, + index, + onAction: () => {}, + id: `${item}-${index}`, + isLocked: index === 0, + actions: + index === 0 + ? [] + : [ + { + type: 'rename', + onAction: () => {}, + onPrimaryAction: async (value: string) => { + const newItemsStrings = tabs.map((item, idx) => { + if (idx === index) { + return value; + } + return item.content; + }); + await sleep(1); + setItemStrings(newItemsStrings); + return true; + }, + }, + { + type: 'duplicate', + onPrimaryAction: async (name) => { + await sleep(1); + duplicateView(name); + return true; + }, + }, + { + type: 'edit', + }, + { + type: 'delete', + onPrimaryAction: async (id: string) => { + await sleep(1); + deleteView(index); + return true; + }, + }, + ], + })); + const [selected, setSelected] = useState(0); + const onCreateNewView = async (value: string) => { + await sleep(500); + setItemStrings([...itemStrings, value]); + setSelected(itemStrings.length); + return true; + }; + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(IndexFiltersMode.Filtering); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const primaryAction: IndexFiltersProps['primaryAction'] = + selected === 0 + ? { + type: 'save-as', + onAction: onCreateNewView, + disabled: false, + loading: false, + } + : { + type: 'save', + onAction: onHandleSave, + disabled: false, + loading: false, + }; + const [accountStatus, setAccountStatus] = useState([ + 'enabled', + ]); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState('Returning customer'); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + { + key: 'hiddenFilter', + label: 'Filter not accessible from the dropdown', + hidden: true, + filter: null, + }, + ]; + + const appliedFilters: IndexFiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } - const onHandleSave = async () => { - await sleep(1); - return true; - }; + appliedFilters.push({ + key: 'hiddenFilter', + label: 'Filter not accessible from the dropdown', + onRemove: handleTaggedWithRemove, + }); - const [queryValue, setQueryValue] = useState(''); + return ( + + setQueryValue('')} + onSort={setSortSelected} + primaryAction={primaryAction} + cancelAction={{ + onAction: onHandleCancel, + disabled: false, + loading: false, + }} + tabs={tabs} + selected={selected} + onSelect={setSelected} + canCreateNewView + onCreateNewView={onCreateNewView} + filters={filters} + appliedFilters={appliedFilters} + onClearAll={handleFiltersClearAll} + mode={mode} + setMode={setMode} + /> +
+ + ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } + } - const handleFiltersQueryChange = useCallback( - (value: string) => setQueryValue(value), - [], - ); + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithAsyncData = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [loadData, setLoadData] = useState(false); + const [addAsyncFilter, setAddAsyncFilter] = useState(false); + const [itemStrings, setItemStrings] = useState([ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ]); + const deleteView = (index: number) => { + const newItemStrings = [...itemStrings]; + newItemStrings.splice(index, 1); + setItemStrings(newItemStrings); + setSelected(0); + }; + + const duplicateView = async (name: string) => { + setItemStrings([...itemStrings, name]); + setSelected(itemStrings.length); + await sleep(1); + return true; + }; + + const tabs: TabProps[] = itemStrings.map((item, index) => ({ + content: item, + index, + onAction: () => {}, + id: `${item}-${index}`, + isLocked: index === 0, + actions: + index === 0 + ? [] + : [ + { + type: 'rename', + onAction: () => {}, + onPrimaryAction: async (value: string) => { + const newItemsStrings = tabs.map((item, idx) => { + if (idx === index) { + return value; + } + return item.content; + }); + await sleep(1); + setItemStrings(newItemsStrings); + return true; + }, + }, + { + type: 'duplicate', + onPrimaryAction: async (name) => { + await sleep(1); + duplicateView(name); + return true; + }, + }, + { + type: 'edit', + }, + { + type: 'delete', + onPrimaryAction: async (id: string) => { + await sleep(1); + deleteView(index); + return true; + }, + }, + ], + })); + const [selected, setSelected] = useState(0); + const onCreateNewView = async (value: string) => { + await sleep(500); + setItemStrings([...itemStrings, value]); + setSelected(itemStrings.length); + return true; + }; + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(IndexFiltersMode.Filtering); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const primaryAction: IndexFiltersProps['primaryAction'] = + selected === 0 + ? { + type: 'save-as', + onAction: onCreateNewView, + disabled: false, + loading: false, + } + : { + type: 'save', + onAction: onHandleSave, + disabled: false, + loading: false, + }; + const [accountStatus, setAccountStatus] = useState([ + 'enabled', + ]); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState('Returning customer'); + const [deliveryMethod, setDeliveryMethod] = useState([ + 'local_pick_up', + 'local_delivery', + ]); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleDeliveryMethodChange = useCallback( + (value) => setDeliveryMethod(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleDeliveryMethodRemove = useCallback( + () => setDeliveryMethod(null), + [], + ); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleDeliveryMethodRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + handleDeliveryMethodRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; + + if (addAsyncFilter) { + filters.push({ + key: 'delivery_method', + label: 'Delivery method', + filter: ( + + ), + }); + } - const orders = [ - { - id: '1020', - order: ( - - #1020 - - ), - date: 'Jul 20 at 4:34pm', - customer: 'Jaydon Stanton', - total: '$969.44', - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - }, - { - id: '1019', - order: ( - - #1019 - - ), - date: 'Jul 20 at 3:46pm', - customer: 'Ruben Westerfelt', - total: '$701.19', - paymentStatus: Partially paid, - fulfillmentStatus: Unfulfilled, - }, - { - id: '1018', - order: ( - - #1018 - - ), - date: 'Jul 20 at 3.44pm', - customer: 'Leo Carder', - total: '$798.24', - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - }, - ]; - const resourceName = { - singular: 'order', - plural: 'orders', - }; + const appliedFilters: IndexFiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } + if (!isEmpty(deliveryMethod)) { + const key = 'delivery_method'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, deliveryMethod), + onRemove: handleDeliveryMethodRemove, + }); + } - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(orders); + return ( + + setQueryValue('')} + onSort={setSortSelected} + primaryAction={primaryAction} + cancelAction={{ + onAction: onHandleCancel, + disabled: false, + loading: false, + }} + tabs={tabs} + selected={selected} + onSelect={setSelected} + canCreateNewView + onCreateNewView={onCreateNewView} + filters={loadData ? filters : []} + appliedFilters={loadData ? appliedFilters : []} + onClearAll={handleFiltersClearAll} + mode={mode} + setMode={setMode} + /> +
+
+ + + + +
+ + ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + case 'delivery_method': + return `Delivery method: ${value.join(', ')}`; + default: + return value; + } + } - const rowMarkup = orders.map( - ( - {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const Disabled = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [itemStrings, setItemStrings] = useState([ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ]); + const deleteView = (index: number) => { + const newItemStrings = [...itemStrings]; + newItemStrings.splice(index, 1); + setItemStrings(newItemStrings); + setSelected(0); + }; + + const duplicateView = async (name: string) => { + setItemStrings([...itemStrings, name]); + setSelected(itemStrings.length); + await sleep(1); + return true; + }; + + const tabs: TabProps[] = itemStrings.map((item, index) => ({ + content: item, index, - ) => ( - - - - {order} + onAction: () => {}, + id: `${item}-${index}`, + isLocked: index === 0, + actions: + index === 0 + ? [] + : [ + { + type: 'rename', + onAction: () => {}, + onPrimaryAction: async (value: string) => { + const newItemsStrings = tabs.map((item, idx) => { + if (idx === index) { + return value; + } + return item.content; + }); + await sleep(1); + setItemStrings(newItemsStrings); + return true; + }, + }, + { + type: 'duplicate', + onPrimaryAction: async (name) => { + await sleep(1); + duplicateView(name); + return true; + }, + }, + { + type: 'edit', + }, + { + type: 'delete', + onPrimaryAction: async (id: string) => { + await sleep(1); + deleteView(index); + return true; + }, + }, + ], + })); + const [selected, setSelected] = useState(0); + const onCreateNewView = async (value: string) => { + await sleep(500); + setItemStrings([...itemStrings, value]); + setSelected(itemStrings.length); + return true; + }; + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const primaryAction: IndexFiltersProps['primaryAction'] = + selected === 0 + ? { + type: 'save-as', + onAction: onCreateNewView, + disabled: false, + loading: false, + } + : { + type: 'save', + onAction: onHandleSave, + disabled: false, + loading: false, + }; + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(''); + const [queryValue, setQueryValue] = useState(''); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; + + const appliedFilters: IndexFiltersProps['appliedFilters'] = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); + } + + return ( + + setQueryValue('')} + onSort={setSortSelected} + primaryAction={primaryAction} + cancelAction={{ + onAction: onHandleCancel, + disabled: false, + loading: false, + }} + tabs={tabs} + selected={selected} + onSelect={setSelected} + canCreateNewView + onCreateNewView={onCreateNewView} + filters={filters} + appliedFilters={appliedFilters} + onClearAll={handleFiltersClearAll} + mode={mode} + setMode={setMode} + disabled + showEditColumnsButton + /> +
+ + ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithQueryFieldAndFiltersHidden = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [itemStrings, setItemStrings] = useState([ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ]); + const deleteView = (index: number) => { + const newItemStrings = [...itemStrings]; + newItemStrings.splice(index, 1); + setItemStrings(newItemStrings); + setSelected(0); + }; + + const duplicateView = async (name: string) => { + setItemStrings([...itemStrings, name]); + setSelected(itemStrings.length); + await sleep(1); + return true; + }; + + const tabs: TabProps[] = itemStrings.map((item, index) => ({ + content: item, + index, + onAction: () => {}, + id: `${item}-${index}`, + isLocked: index === 0, + actions: + index === 0 + ? [] + : [ + { + type: 'rename', + onAction: () => {}, + onPrimaryAction: async (value: string) => { + const newItemsStrings = tabs.map((item, idx) => { + if (idx === index) { + return value; + } + return item.content; + }); + await sleep(1); + setItemStrings(newItemsStrings); + return true; + }, + }, + { + type: 'duplicate', + onPrimaryAction: async (name) => { + await sleep(1); + duplicateView(name); + return true; + }, + }, + { + type: 'edit', + }, + { + type: 'delete', + onPrimaryAction: async (id: string) => { + await sleep(1); + deleteView(index); + return true; + }, + }, + ], + })); + const [selected, setSelected] = useState(0); + const onCreateNewView = async (value: string) => { + await sleep(500); + setItemStrings([...itemStrings, value]); + setSelected(itemStrings.length); + return true; + }; + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const primaryAction: IndexFiltersProps['primaryAction'] = + selected === 0 + ? { + type: 'save-as', + onAction: onCreateNewView, + disabled: false, + loading: false, + } + : { + type: 'save', + onAction: onHandleSave, + disabled: false, + loading: false, + }; + + return ( + + {}} + onQueryClear={() => {}} + onSort={setSortSelected} + primaryAction={primaryAction} + cancelAction={{ + onAction: onHandleCancel, + disabled: false, + loading: false, + }} + tabs={tabs} + selected={selected} + onSelect={setSelected} + canCreateNewView + onCreateNewView={onCreateNewView} + filters={[]} + onClearAll={() => {}} + mode={mode} + setMode={setMode} + hideQueryField + hideFilters + /> +
+ + ); + }, +}; + +export const WithNoFilters = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [itemStrings, setItemStrings] = useState([ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ]); + const deleteView = (index: number) => { + const newItemStrings = [...itemStrings]; + newItemStrings.splice(index, 1); + setItemStrings(newItemStrings); + setSelected(0); + }; + + const duplicateView = async (name: string) => { + setItemStrings([...itemStrings, name]); + setSelected(itemStrings.length); + await sleep(1); + return true; + }; + + const tabs: TabProps[] = itemStrings.map((item, index) => ({ + content: item, + index, + onAction: () => {}, + id: `${item}-${index}`, + isLocked: index === 0, + actions: + index === 0 + ? [] + : [ + { + type: 'rename', + onAction: () => {}, + onPrimaryAction: async (value: string): Promise => { + const newItemsStrings = tabs.map((item, idx) => { + if (idx === index) { + return value; + } + return item.content; + }); + await sleep(1); + setItemStrings(newItemsStrings); + return true; + }, + }, + { + type: 'duplicate', + onPrimaryAction: async (value: string): Promise => { + await sleep(1); + duplicateView(value); + return true; + }, + }, + { + type: 'edit', + }, + { + type: 'delete', + onPrimaryAction: async () => { + await sleep(1); + deleteView(index); + return true; + }, + }, + ], + })); + const [selected, setSelected] = useState(0); + const onCreateNewView = async (value: string) => { + await sleep(500); + setItemStrings([...itemStrings, value]); + setSelected(itemStrings.length); + return true; + }; + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const primaryAction: IndexFiltersProps['primaryAction'] = + selected === 0 + ? { + type: 'save-as', + onAction: onCreateNewView, + disabled: false, + loading: false, + } + : { + type: 'save', + onAction: onHandleSave, + disabled: false, + loading: false, + }; + const [queryValue, setQueryValue] = useState(''); + + const handleFiltersQueryChange = useCallback( + (value: string) => setQueryValue(value), + [], + ); + + const orders = [ + { + id: '1020', + order: ( + + #1020 - - - - {date} + ), + date: 'Jul 20 at 4:34pm', + customer: 'Jaydon Stanton', + total: '$969.44', + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + }, + { + id: '1019', + order: ( + + #1019 - - - - {customer} + ), + date: 'Jul 20 at 3:46pm', + customer: 'Ruben Westerfelt', + total: '$701.19', + paymentStatus: ( + Partially paid + ), + fulfillmentStatus: Unfulfilled, + }, + { + id: '1018', + order: ( + + #1018 - - - - {total} + ), + date: 'Jul 20 at 3.44pm', + customer: 'Leo Carder', + total: '$798.24', + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + }, + ]; + const resourceName = { + singular: 'order', + plural: 'orders', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(orders); + + const rowMarkup = orders.map( + ( + {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + index, + ) => ( + + + + {order} + + + + + {date} + + + + + {customer} + + + + + {total} + + + + + {paymentStatus} + + + + + {fulfillmentStatus} + + + + ), + ); + + return ( + + setQueryValue('')} + onSort={setSortSelected} + primaryAction={primaryAction} + cancelAction={{ + onAction: onHandleCancel, + disabled: false, + loading: false, + }} + tabs={tabs} + selected={selected} + onSelect={setSelected} + canCreateNewView + onCreateNewView={onCreateNewView} + filters={[]} + appliedFilters={[]} + onClearAll={() => {}} + mode={mode} + setMode={setMode} + hideFilters + filteringAccessibilityTooltip="Search (F)" + /> + + {rowMarkup} + + + ); + }, +}; + +export const WithOnlySearchAndSort = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Order', value: 'order asc', directionLabel: 'Ascending'}, + {label: 'Order', value: 'order desc', directionLabel: 'Descending'}, + {label: 'Customer', value: 'customer asc', directionLabel: 'A-Z'}, + {label: 'Customer', value: 'customer desc', directionLabel: 'Z-A'}, + {label: 'Date', value: 'date asc', directionLabel: 'A-Z'}, + {label: 'Date', value: 'date desc', directionLabel: 'Z-A'}, + {label: 'Total', value: 'total asc', directionLabel: 'Ascending'}, + {label: 'Total', value: 'total desc', directionLabel: 'Descending'}, + ]; + const [sortSelected, setSortSelected] = useState(['order asc']); + const {mode, setMode} = useSetIndexFiltersMode(IndexFiltersMode.Filtering); + const onHandleCancel = () => {}; + + const onHandleSave = async () => { + await sleep(1); + return true; + }; + + const [queryValue, setQueryValue] = useState(''); + + const handleFiltersQueryChange = useCallback( + (value: string) => setQueryValue(value), + [], + ); + + const orders = [ + { + id: '1020', + order: ( + + #1020 - - - - {paymentStatus} + ), + date: 'Jul 20 at 4:34pm', + customer: 'Jaydon Stanton', + total: '$969.44', + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + }, + { + id: '1019', + order: ( + + #1019 - - - - {fulfillmentStatus} + ), + date: 'Jul 20 at 3:46pm', + customer: 'Ruben Westerfelt', + total: '$701.19', + paymentStatus: ( + Partially paid + ), + fulfillmentStatus: Unfulfilled, + }, + { + id: '1018', + order: ( + + #1018 - - - ), - ); - - return ( - - setQueryValue('')} - onSort={setSortSelected} - autoFocusSearchField={false} - tabs={[]} - filters={[]} - appliedFilters={[]} - onClearAll={() => {}} - mode={mode} - setMode={setMode} - hideFilters - filteringAccessibilityTooltip="Search (F)" - /> - - {rowMarkup} - - - ); -} + ), + date: 'Jul 20 at 3.44pm', + customer: 'Leo Carder', + total: '$798.24', + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + }, + ]; + const resourceName = { + singular: 'order', + plural: 'orders', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(orders); + + const rowMarkup = orders.map( + ( + {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + index, + ) => ( + + + + {order} + + + + + {date} + + + + + {customer} + + + + + {total} + + + + + {paymentStatus} + + + + + {fulfillmentStatus} + + + + ), + ); + + return ( + + setQueryValue('')} + onSort={setSortSelected} + autoFocusSearchField={false} + tabs={[]} + filters={[]} + appliedFilters={[]} + onClearAll={() => {}} + mode={mode} + setMode={setMode} + hideFilters + filteringAccessibilityTooltip="Search (F)" + /> + + {rowMarkup} + + + ); + }, +}; diff --git a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx index 209c8d1e9ba..d9370288dda 100644 --- a/polaris-react/src/components/IndexTable/IndexTable.stories.tsx +++ b/polaris-react/src/components/IndexTable/IndexTable.stories.tsx @@ -1,5 +1,5 @@ import React, {Fragment, useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import type { IndexFiltersProps, IndexTableProps, @@ -38,432 +38,93 @@ import {IndexTable} from './IndexTable'; export default { component: IndexTable, -} as ComponentMeta; - -export function Default() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function Condensed() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function Flush() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function SmallScreen() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - -
- - {name} - - +} as Meta; + +export const Default = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + {location} - - - {orders} - - - {amountSpent} - -
-
- ), - ); + + + + {orders} + + + + + {amountSpent} + + + + ), + ); - return ( -
+ return ( -
- ); -} - -export function SmallScreenLoading() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - -
- - {name} - - + ); + }, +}; + +export const Condensed = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + {location} - - - {orders} - - - {amountSpent} - -
-
- ), - ); + + + + {orders} + + + + + {amountSpent} + + + + ), + ); - return ( -
+ return ( {rowMarkup} -
- ); -} - -export function WithDisabledRows() { - const customers = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - disabled: false, - }, - { - id: '2561', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - disabled: true, - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const selectableCustomers = customers.filter( - (customer) => !customer.disabled, - ); - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(selectableCustomers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent, disabled}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithSubduedRows() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithEmptyState() { - const customers = []; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const emptyStateMarkup = ( - - ); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithBulkActions() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - ]; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithSelectionAndNoBulkActions() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithMultiplePromotedBulkActions() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const promotedBulkActions = [ - { - content: 'Capture payments', - onAction: () => console.log('Todo: implement payment capture'), - }, - { - title: 'Edit customers', - actions: [ - { - content: 'Add customers', - onAction: () => console.log('Todo: implement adding customers'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement deleting customers'), - }, - ], - }, - { - title: 'Export', - actions: [ - { - content: 'Export as PDF', - onAction: () => console.log('Todo: implement PDF exporting'), - }, - { - content: 'Export as CSV', - onAction: () => console.log('Todo: implement CSV exporting'), - }, - ], - }, - ]; - const bulkActions = [ - { - title: 'Import', - items: [ - { - content: 'Import from PDF', - onAction: () => console.log('Todo: implement PDF importing'), - }, - { - content: 'Import from CSV', - onAction: () => console.log('Todo: implement CSV importing'), - }, - ], - }, - { - title: 'Customers', - items: [ - { - content: 'Add customers', - onAction: () => console.log('Todo: implement Adding customers'), - }, - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement Editing customers'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement Deleting customers'), - }, - ], - }, - ]; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithBulkActionsAndSelectionAcrossPages() { - const customers = Array.from({length: 50}, (_, num) => { - return { - id: `${num}`, - url: '#', - name: `Mae Jemison ${num}`, - location: 'Truth or Consequences, New Mexico, United States of America', - orders: 20, - amountSpent: '$24,00', - }; - }); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const promotedBulkActions = [ - { - content: 'Rename customers', - onAction: () => console.log('Todo: implement bulk rename'), - }, - { - title: 'Edit customers', - actions: [ - { - content: 'Add customers', - onAction: () => console.log('Todo: implement adding customers'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement deleting customers'), - }, - ], - }, - { - title: 'Export', - actions: [ - { - content: 'Export as PDF', - onAction: () => console.log('Todo: implement PDF exporting'), - }, - { - content: 'Export as CSV', - onAction: () => console.log('Todo: implement CSV exporting'), - }, - ], - }, - ]; - const bulkActions = [ - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - title: 'Bulk action section', - items: [ - { - content: 'Edit data', - }, - { - content: 'Manage data', - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete data', - }, - ], - }, - { - content: 'Edit prices', - onAction: () => console.log('Todo: implement bulk delete'), - }, - { - content: 'Edit quantities', - onAction: () => console.log('Todo: implement bulk delete'), - }, - { - content: 'Edit SKUs', - onAction: () => console.log('Todo: implement bulk delete'), - }, - { - content: 'Edit barcodes', - onAction: () => console.log('Todo: implement bulk delete'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithLoadingState() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithFiltering() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - const [taggedWith, setTaggedWith] = useState('VIP'); - const [queryValue, setQueryValue] = useState(''); - const [sortValue, setSortValue] = useState(['today asc']); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - const handleSortChange = useCallback((value) => setSortValue(value), []); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - ]; + ); + }, +}; - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Date', value: 'today asc', directionLabel: 'Ascending'}, - {label: 'Date', value: 'today desc', directionLabel: 'Descending'}, - ]; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - const tabs = [ - { - id: 'all', - content: 'All customers', - }, - ]; - - const {mode, setMode} = useSetIndexFiltersMode(); - - const cancelAction = { - onAction: () => {}, - }; - - async function emptyPromise() { - const prom = Promise.resolve(); - return prom.then(() => { - return true; - }); - } - - const primaryAction: IndexFiltersProps['primaryAction'] = { - onAction: emptyPromise, - type: 'save-as', - }; - - return ( - - {}} - onCreateNewView={emptyPromise} - queryValue={queryValue} - queryPlaceholder="Searching in all" - filters={filters} - appliedFilters={appliedFilters} - onQueryChange={setQueryValue} - onQueryClear={handleQueryValueRemove} - onClearAll={handleClearAll} - sortOptions={sortOptions} - sortSelected={sortValue} - onSort={handleSortChange} - mode={mode} - setMode={setMode} - cancelAction={cancelAction} - primaryAction={primaryAction} - /> - - {rowMarkup} - - - ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; - } - } +export const Flush = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function WithRowStatus() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Astronaut', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Baker', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - status: 'subdued', - }, - { - id: '3412', - url: '#', - name: 'Candlestick maker', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - status: 'success', - }, - { - id: '3413', - url: '#', - name: 'Rice Cooker', - location: 'Los Angeles, USA', - orders: 40, - amountSpent: '$40', - status: 'critical', - }, - { - id: '3414', - url: '#', - name: 'Volleyball Player', - location: 'Delaware, USA', - orders: 50, - amountSpent: '$80', - status: 'warning', - }, - ]; - - const customersForNestedRows = [ - { - id: '34101', - url: '#', - name: 'Astronaut', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '34111', - url: '#', - name: 'Baker', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - status: 'subdued', - }, - { - id: '34121', - url: '#', - name: 'Candlestick maker', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - status: 'success', - }, - { - id: '34131', - url: '#', - name: 'Rice Cooker', - location: 'Los Angeles, USA', - orders: 40, - amountSpent: '$40', - status: 'critical', - }, - { - id: '34141', - url: '#', - name: 'Volleyball Player', - location: 'Delaware, USA', - orders: 50, - amountSpent: '$80', - status: 'warning', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent, status}, index) => ( - - - - {name} - - - - {status} - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - const rowMarkupNested = customersForNestedRows.map( - ({id, name, location, orders, amountSpent, status}, index) => ( - 0 ? 'child' : 'subheader'} - > - - - {name} - - - - {status} - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - return ( - - - {rowMarkup} - {rowMarkupNested} - - - ); -} - -export function WithStickyLastColumn() { - const customers = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - channel: 'Point of Sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - }, - { - id: '2561', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - channel: 'Online Store', - paymentStatus: 'Paid', - fulfillmentStatus: 'Unfulfilled', - }, - { - id: '2562', - url: '#', - name: 'Helen Troy', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$975', - lastOrderDate: 'May 31, 2023', - status: 'success', - }, - { - id: '4102', - url: '#', - name: 'Colm Dillane', - location: 'New York, USA', - orders: 27, - amountSpent: '$2885', - lastOrderDate: 'May 31, 2023', - status: 'critical', - }, - { - id: '2564', - url: '#', - name: 'Al Chemist', - location: 'New York, USA', - orders: 19, - amountSpent: '$1,209', - lastOrderDate: 'April 4, 2023', - disabled: true, - status: 'warning', - }, - { - id: '2563', - url: '#', - name: 'Larry June', - location: 'San Francisco, USA', - orders: 22, - amountSpent: '$1,400', - lastOrderDate: 'March 19, 2023', - status: 'subdued', - }, - ]; - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ( - { - id, - name, - location, - orders, - amountSpent, - status, - channel, - paymentStatus, - fulfillmentStatus, - }, - index, - ) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - {channel} - {paymentStatus} - {fulfillmentStatus} - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithRowNavigationLink() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, url, name, location, orders, amountSpent}, index) => ( - - - console.log(`Clicked ${name}`)} - > + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithClickableButtonColumn() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, url, name, location, orders, amountSpent}, index) => ( - - - console.log(`Clicked ${name}`)} - > - - {name} + + + + {location} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithoutCheckboxes() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithTonesWithoutCheckboxes() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - status: 'success', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - status: 'critical', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - status: 'warning', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - status: 'subdued', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent, status}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithAllOfItsElements() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - const [taggedWith, setTaggedWith] = useState('VIP'); - const [queryValue, setQueryValue] = useState(''); - const [sortValue, setSortValue] = useState(['today asc']); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - const handleSortChange = useCallback((value) => setSortValue(value), []); - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - + + + + {orders} + + + + + {amountSpent} + + + ), - shortcut: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Date', value: 'today asc', directionLabel: 'Ascending'}, - {label: 'Date', value: 'today desc', directionLabel: 'Descending'}, - ]; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - const tabs = [ - { - id: 'all', - content: 'All customers', - }, - ]; - - const {mode, setMode} = useSetIndexFiltersMode(); - - const cancelAction = { - onAction: () => {}, - }; - - async function emptyPromise() { - const prom = Promise.resolve(); - return prom.then(() => { - return true; - }); - } - - const primaryAction: IndexFiltersProps['primaryAction'] = { - onAction: emptyPromise, - type: 'save-as', - }; - - return ( - - {}} - onCreateNewView={emptyPromise} - queryValue={queryValue} - queryPlaceholder="Searching in all" - filters={filters} - appliedFilters={appliedFilters} - onQueryChange={setQueryValue} - onQueryClear={handleQueryValueRemove} - onClearAll={handleClearAll} - sortOptions={sortOptions} - sortSelected={sortValue} - onSort={handleSortChange} - mode={mode} - setMode={setMode} - cancelAction={cancelAction} - primaryAction={primaryAction} - /> - - {rowMarkup} - - - ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; - } - } + ); - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function WithSortableHeadings() { - const [sortIndex, setSortIndex] = useState(0); - const [sortDirection, setSortDirection] = - useState('descending'); - - const sortToggleLabels = { - 0: {ascending: 'A-Z', descending: 'Z-A'}, - 1: {ascending: 'Ascending', descending: 'Descending'}, - 2: {ascending: 'Newest', descending: 'Oldest'}, - 3: {ascending: 'Ascending', descending: 'Ascending'}, - 4: {ascending: 'A-Z', descending: 'Z-A'}, - 5: {ascending: 'A-Z', descending: 'Z-A'}, - 6: {ascending: 'A-Z', descending: 'Z-A'}, - 7: {ascending: 'A-Z', descending: 'Z-A'}, - }; - - const initialRows = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - date: '2022-02-04', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Paid', - notes: '', - }, - { - id: '2561', - url: '#', - date: '2022-01-19', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: 'This customer lives on the 3rd floor', - }, - { - id: '1245', - url: '#', - date: '2021-12-12', - name: 'Anne-Marie Johnson', - location: 'Portland, USA', - orders: 10, - amountSpent: '$250', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: '', - }, - { - id: '8741', - url: '#', - date: '2022-05-11', - name: 'Bradley Stevens', - location: 'Hialeah, USA', - orders: 5, - amountSpent: '$26', - fulfillmentStatus: 'Unfulfilled', - paymentStatus: 'Not paid', - notes: 'This customer has requested fragile delivery', - }, - ]; - const [sortedRows, setSortedRows] = useState( - sortRows(initialRows, sortIndex, sortDirection), - ); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const rows = sortedRows ?? initialRows; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows); - - function handleClickSortHeading(index, direction) { - setSortIndex(index); - setSortDirection(direction); - const newSortedRows = sortRows(rows, index, direction); - setSortedRows(newSortedRows); - } - - function sortRows(localRows, index, direction) { - return [...localRows].sort((rowA, rowB) => { - const key = index === 0 ? 'name' : 'location'; - if (rowA[key] < rowB[key]) { - return direction === 'descending' ? -1 : 1; - } - if (rowA[key] > rowB[key]) { - return direction === 'descending' ? 1 : -1; - } - return 0; - }); - } - - const rowMarkup = rows.map( - ( - { - id, - name, - date, - location, - orders, - amountSpent, - fulfillmentStatus, - paymentStatus, - notes, - }, - index, - ) => ( - - - - {name} - - - {date} - - - {orders} - - - - - {amountSpent} - - - - - {location} - - - {fulfillmentStatus} - {paymentStatus} - {notes} - - ), - ); - - return ( - - + + {rowMarkup} + + + ); + }, +}; - {title: 'Location'}, - {title: 'Fulfillment status'}, - {title: 'Payment status'}, - {title: 'Notes'}, - ]} - sortable={[true, true, false, true, true, false, false]} - sortDirection={sortDirection} - sortColumnIndex={sortIndex} - onSort={handleClickSortHeading} - sortToggleLabels={sortToggleLabels} - lastColumnSticky - > - {rowMarkup} - - - ); -} - -export function WithSortableHeadingsLastElementAlignmentEnd() { - const [sortIndex, setSortIndex] = useState(0); - const [sortDirection, setSortDirection] = - useState('descending'); - - const sortToggleLabels = { - 0: {ascending: 'A-Z', descending: 'Z-A'}, - 1: {ascending: 'Ascending', descending: 'Descending'}, - 2: {ascending: 'Newest', descending: 'Oldest'}, - 3: {ascending: 'Ascending', descending: 'Ascending'}, - 4: {ascending: 'A-Z', descending: 'Z-A'}, - 5: {ascending: 'A-Z', descending: 'Z-A'}, - 6: {ascending: 'A-Z', descending: 'Z-A'}, - 7: {ascending: 'A-Z', descending: 'Z-A'}, - }; - - const initialRows = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - date: '2022-02-04', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Paid', - notes: '', - }, - { - id: '2561', - url: '#', - date: '2022-01-19', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: 'This customer lives on the 3rd floor', - }, - { - id: '1245', - url: '#', - date: '2021-12-12', - name: 'Anne-Marie Johnson', - location: 'Portland, USA', - orders: 10, - amountSpent: '$250', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: '', - }, - { - id: '8741', - url: '#', - date: '2022-05-11', - name: 'Bradley Stevens', - location: 'Hialeah, USA', - orders: 5, - amountSpent: '$26', - fulfillmentStatus: 'Unfulfilled', - paymentStatus: 'Not paid', - notes: 'This customer has requested fragile delivery', - }, - ]; - const [sortedRows, setSortedRows] = useState( - sortRows(initialRows, sortIndex, sortDirection), - ); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const rows = sortedRows ?? initialRows; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows); - - function handleClickSortHeading(index, direction) { - setSortIndex(index); - setSortDirection(direction); - const newSortedRows = sortRows(rows, index, direction); - setSortedRows(newSortedRows); - } - - function sortRows(localRows, index, direction) { - return [...localRows].sort((rowA, rowB) => { - const key = index === 0 ? 'name' : 'location'; - if (rowA[key] < rowB[key]) { - return direction === 'descending' ? -1 : 1; +export const SmallScreen = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + +
+ + {name} + + + + {location} + + + + {orders} + + + {amountSpent} + +
+
+ ), + ); + + return ( +
+ + + {rowMarkup} + + +
+ ); + }, +}; + +export const SmallScreenLoading = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + +
+ + {name} + + + + {location} + + + + {orders} + + + {amountSpent} + +
+
+ ), + ); + + return ( +
+ + + {rowMarkup} + + +
+ ); + }, +}; + +export const WithDisabledRows = { + render() { + const customers = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + disabled: false, + }, + { + id: '2561', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + disabled: true, + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const selectableCustomers = customers.filter( + (customer) => !customer.disabled, + ); + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(selectableCustomers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent, disabled}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithSubduedRows = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithEmptyState = { + render() { + const customers = []; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const emptyStateMarkup = ( + + ); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithBulkActions = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + ]; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithSelectionAndNoBulkActions = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithMultiplePromotedBulkActions = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const promotedBulkActions = [ + { + content: 'Capture payments', + onAction: () => console.log('Todo: implement payment capture'), + }, + { + title: 'Edit customers', + actions: [ + { + content: 'Add customers', + onAction: () => console.log('Todo: implement adding customers'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement deleting customers'), + }, + ], + }, + { + title: 'Export', + actions: [ + { + content: 'Export as PDF', + onAction: () => console.log('Todo: implement PDF exporting'), + }, + { + content: 'Export as CSV', + onAction: () => console.log('Todo: implement CSV exporting'), + }, + ], + }, + ]; + const bulkActions = [ + { + title: 'Import', + items: [ + { + content: 'Import from PDF', + onAction: () => console.log('Todo: implement PDF importing'), + }, + { + content: 'Import from CSV', + onAction: () => console.log('Todo: implement CSV importing'), + }, + ], + }, + { + title: 'Customers', + items: [ + { + content: 'Add customers', + onAction: () => console.log('Todo: implement Adding customers'), + }, + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement Editing customers'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement Deleting customers'), + }, + ], + }, + ]; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithBulkActionsAndSelectionAcrossPages = { + render() { + const customers = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '#', + name: `Mae Jemison ${num}`, + location: 'Truth or Consequences, New Mexico, United States of America', + orders: 20, + amountSpent: '$24,00', + }; + }); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const promotedBulkActions = [ + { + content: 'Rename customers', + onAction: () => console.log('Todo: implement bulk rename'), + }, + { + title: 'Edit customers', + actions: [ + { + content: 'Add customers', + onAction: () => console.log('Todo: implement adding customers'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement deleting customers'), + }, + ], + }, + { + title: 'Export', + actions: [ + { + content: 'Export as PDF', + onAction: () => console.log('Todo: implement PDF exporting'), + }, + { + content: 'Export as CSV', + onAction: () => console.log('Todo: implement CSV exporting'), + }, + ], + }, + ]; + const bulkActions = [ + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + title: 'Bulk action section', + items: [ + { + content: 'Edit data', + }, + { + content: 'Manage data', + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete data', + }, + ], + }, + { + content: 'Edit prices', + onAction: () => console.log('Todo: implement bulk delete'), + }, + { + content: 'Edit quantities', + onAction: () => console.log('Todo: implement bulk delete'), + }, + { + content: 'Edit SKUs', + onAction: () => console.log('Todo: implement bulk delete'), + }, + { + content: 'Edit barcodes', + onAction: () => console.log('Todo: implement bulk delete'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithLoadingState = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithFiltering = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + const [taggedWith, setTaggedWith] = useState('VIP'); + const [queryValue, setQueryValue] = useState(''); + const [sortValue, setSortValue] = useState(['today asc']); + + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + const handleSortChange = useCallback((value) => setSortValue(value), []); + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Date', value: 'today asc', directionLabel: 'Ascending'}, + {label: 'Date', value: 'today desc', directionLabel: 'Descending'}, + ]; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + const tabs = [ + { + id: 'all', + content: 'All customers', + }, + ]; + + const {mode, setMode} = useSetIndexFiltersMode(); + + const cancelAction = { + onAction: () => {}, + }; + + async function emptyPromise() { + const prom = Promise.resolve(); + return prom.then(() => { + return true; + }); + } + + const primaryAction: IndexFiltersProps['primaryAction'] = { + onAction: emptyPromise, + type: 'save-as', + }; + + return ( + + {}} + onCreateNewView={emptyPromise} + queryValue={queryValue} + queryPlaceholder="Searching in all" + filters={filters} + appliedFilters={appliedFilters} + onQueryChange={setQueryValue} + onQueryClear={handleQueryValueRemove} + onClearAll={handleClearAll} + sortOptions={sortOptions} + sortSelected={sortValue} + onSort={handleSortChange} + mode={mode} + setMode={setMode} + cancelAction={cancelAction} + primaryAction={primaryAction} + /> + + {rowMarkup} + + + ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithRowStatus = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Astronaut', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Baker', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + status: 'subdued', + }, + { + id: '3412', + url: '#', + name: 'Candlestick maker', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + status: 'success', + }, + { + id: '3413', + url: '#', + name: 'Rice Cooker', + location: 'Los Angeles, USA', + orders: 40, + amountSpent: '$40', + status: 'critical', + }, + { + id: '3414', + url: '#', + name: 'Volleyball Player', + location: 'Delaware, USA', + orders: 50, + amountSpent: '$80', + status: 'warning', + }, + ]; + + const customersForNestedRows = [ + { + id: '34101', + url: '#', + name: 'Astronaut', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '34111', + url: '#', + name: 'Baker', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + status: 'subdued', + }, + { + id: '34121', + url: '#', + name: 'Candlestick maker', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + status: 'success', + }, + { + id: '34131', + url: '#', + name: 'Rice Cooker', + location: 'Los Angeles, USA', + orders: 40, + amountSpent: '$40', + status: 'critical', + }, + { + id: '34141', + url: '#', + name: 'Volleyball Player', + location: 'Delaware, USA', + orders: 50, + amountSpent: '$80', + status: 'warning', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent, status}, index) => ( + + + + {name} + + + + {status} + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + const rowMarkupNested = customersForNestedRows.map( + ({id, name, location, orders, amountSpent, status}, index) => ( + 0 ? 'child' : 'subheader'} + > + + + {name} + + + + {status} + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + return ( + + + {rowMarkup} + {rowMarkupNested} + + + ); + }, +}; + +export const WithStickyLastColumn = { + render() { + const customers = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + channel: 'Point of Sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + }, + { + id: '2561', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + channel: 'Online Store', + paymentStatus: 'Paid', + fulfillmentStatus: 'Unfulfilled', + }, + { + id: '2562', + url: '#', + name: 'Helen Troy', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$975', + lastOrderDate: 'May 31, 2023', + status: 'success', + }, + { + id: '4102', + url: '#', + name: 'Colm Dillane', + location: 'New York, USA', + orders: 27, + amountSpent: '$2885', + lastOrderDate: 'May 31, 2023', + status: 'critical', + }, + { + id: '2564', + url: '#', + name: 'Al Chemist', + location: 'New York, USA', + orders: 19, + amountSpent: '$1,209', + lastOrderDate: 'April 4, 2023', + disabled: true, + status: 'warning', + }, + { + id: '2563', + url: '#', + name: 'Larry June', + location: 'San Francisco, USA', + orders: 22, + amountSpent: '$1,400', + lastOrderDate: 'March 19, 2023', + status: 'subdued', + }, + ]; + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ( + { + id, + name, + location, + orders, + amountSpent, + status, + channel, + paymentStatus, + fulfillmentStatus, + }, + index, + ) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + {channel} + {paymentStatus} + {fulfillmentStatus} + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithRowNavigationLink = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, url, name, location, orders, amountSpent}, index) => ( + + + console.log(`Clicked ${name}`)} + > + + {name} + + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithClickableButtonColumn = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, url, name, location, orders, amountSpent}, index) => ( + + + console.log(`Clicked ${name}`)} + > + + {name} + + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithoutCheckboxes = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithTonesWithoutCheckboxes = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + status: 'success', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + status: 'critical', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + status: 'warning', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + status: 'subdued', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent, status}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithAllOfItsElements = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + const [taggedWith, setTaggedWith] = useState('VIP'); + const [queryValue, setQueryValue] = useState(''); + const [sortValue, setSortValue] = useState(['today asc']); + + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + const handleSortChange = useCallback((value) => setSortValue(value), []); + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Date', value: 'today asc', directionLabel: 'Ascending'}, + {label: 'Date', value: 'today desc', directionLabel: 'Descending'}, + ]; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + const tabs = [ + { + id: 'all', + content: 'All customers', + }, + ]; + + const {mode, setMode} = useSetIndexFiltersMode(); + + const cancelAction = { + onAction: () => {}, + }; + + async function emptyPromise() { + const prom = Promise.resolve(); + return prom.then(() => { + return true; + }); + } + + const primaryAction: IndexFiltersProps['primaryAction'] = { + onAction: emptyPromise, + type: 'save-as', + }; + + return ( + + {}} + onCreateNewView={emptyPromise} + queryValue={queryValue} + queryPlaceholder="Searching in all" + filters={filters} + appliedFilters={appliedFilters} + onQueryChange={setQueryValue} + onQueryClear={handleQueryValueRemove} + onClearAll={handleClearAll} + sortOptions={sortOptions} + sortSelected={sortValue} + onSort={handleSortChange} + mode={mode} + setMode={setMode} + cancelAction={cancelAction} + primaryAction={primaryAction} + /> + + {rowMarkup} + + + ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; } - if (rowA[key] > rowB[key]) { - return direction === 'descending' ? 1 : -1; + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; } - return 0; - }); - } - - const rowMarkup = rows.map( - ( - { - id, - name, - date, - location, - orders, - amountSpent, - fulfillmentStatus, - paymentStatus, - notes, - }, - index, - ) => ( - - - - {name} - - - {date} - - - {orders} - - - - - {amountSpent} - - - - - {location} - - - {fulfillmentStatus} - {paymentStatus} - {notes} - - ), - ); - - return ( - - ('descending'); + + const sortToggleLabels = { + 0: {ascending: 'A-Z', descending: 'Z-A'}, + 1: {ascending: 'Ascending', descending: 'Descending'}, + 2: {ascending: 'Newest', descending: 'Oldest'}, + 3: {ascending: 'Ascending', descending: 'Ascending'}, + 4: {ascending: 'A-Z', descending: 'Z-A'}, + 5: {ascending: 'A-Z', descending: 'Z-A'}, + 6: {ascending: 'A-Z', descending: 'Z-A'}, + 7: {ascending: 'A-Z', descending: 'Z-A'}, + }; + + const initialRows = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + date: '2022-02-04', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Paid', + notes: '', + }, + { + id: '2561', + url: '#', + date: '2022-01-19', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: 'This customer lives on the 3rd floor', + }, + { + id: '1245', + url: '#', + date: '2021-12-12', + name: 'Anne-Marie Johnson', + location: 'Portland, USA', + orders: 10, + amountSpent: '$250', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: '', + }, + { + id: '8741', + url: '#', + date: '2022-05-11', + name: 'Bradley Stevens', + location: 'Hialeah, USA', + orders: 5, + amountSpent: '$26', + fulfillmentStatus: 'Unfulfilled', + paymentStatus: 'Not paid', + notes: 'This customer has requested fragile delivery', + }, + ]; + const [sortedRows, setSortedRows] = useState( + sortRows(initialRows, sortIndex, sortDirection), + ); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const rows = sortedRows ?? initialRows; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows); + + function handleClickSortHeading(index, direction) { + setSortIndex(index); + setSortDirection(direction); + const newSortedRows = sortRows(rows, index, direction); + setSortedRows(newSortedRows); + } + + function sortRows(localRows, index, direction) { + return [...localRows].sort((rowA, rowB) => { + const key = index === 0 ? 'name' : 'location'; + if (rowA[key] < rowB[key]) { + return direction === 'descending' ? -1 : 1; + } + if (rowA[key] > rowB[key]) { + return direction === 'descending' ? 1 : -1; + } + return 0; + }); + } + + const rowMarkup = rows.map( + ( + { + id, + name, + date, + location, + orders, + amountSpent, + fulfillmentStatus, + paymentStatus, + notes, + }, + index, + ) => ( + + + + {name} + + + {date} + + + {orders} + + + + + {amountSpent} + + + + + {location} + + + {fulfillmentStatus} + {paymentStatus} + {notes} + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithSortableHeadingsLastElementAlignmentEnd = { + render() { + const [sortIndex, setSortIndex] = useState(0); + const [sortDirection, setSortDirection] = + useState('descending'); + + const sortToggleLabels = { + 0: {ascending: 'A-Z', descending: 'Z-A'}, + 1: {ascending: 'Ascending', descending: 'Descending'}, + 2: {ascending: 'Newest', descending: 'Oldest'}, + 3: {ascending: 'Ascending', descending: 'Ascending'}, + 4: {ascending: 'A-Z', descending: 'Z-A'}, + 5: {ascending: 'A-Z', descending: 'Z-A'}, + 6: {ascending: 'A-Z', descending: 'Z-A'}, + 7: {ascending: 'A-Z', descending: 'Z-A'}, + }; + + const initialRows = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + date: '2022-02-04', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Paid', + notes: '', + }, + { + id: '2561', + url: '#', + date: '2022-01-19', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: 'This customer lives on the 3rd floor', + }, + { + id: '1245', + url: '#', + date: '2021-12-12', + name: 'Anne-Marie Johnson', + location: 'Portland, USA', + orders: 10, + amountSpent: '$250', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: '', + }, + { + id: '8741', + url: '#', + date: '2022-05-11', + name: 'Bradley Stevens', + location: 'Hialeah, USA', + orders: 5, + amountSpent: '$26', + fulfillmentStatus: 'Unfulfilled', + paymentStatus: 'Not paid', + notes: 'This customer has requested fragile delivery', + }, + ]; + const [sortedRows, setSortedRows] = useState( + sortRows(initialRows, sortIndex, sortDirection), + ); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const rows = sortedRows ?? initialRows; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows); + + function handleClickSortHeading(index, direction) { + setSortIndex(index); + setSortDirection(direction); + const newSortedRows = sortRows(rows, index, direction); + setSortedRows(newSortedRows); + } + + function sortRows(localRows, index, direction) { + return [...localRows].sort((rowA, rowB) => { + const key = index === 0 ? 'name' : 'location'; + if (rowA[key] < rowB[key]) { + return direction === 'descending' ? -1 : 1; + } + if (rowA[key] > rowB[key]) { + return direction === 'descending' ? 1 : -1; + } + return 0; + }); + } + + const rowMarkup = rows.map( + ( + { + id, + name, + date, + location, + orders, + amountSpent, + fulfillmentStatus, + paymentStatus, + notes, + }, + index, + ) => ( + + + + {name} + + + {date} + + + {orders} + + + + + {amountSpent} + + + + + {location} + + + {fulfillmentStatus} + {paymentStatus} + {notes} + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithSortableCustomHeadings = { + render() { + const [sortIndex, setSortIndex] = useState(0); + const [sortDirection, setSortDirection] = + useState('descending'); + + const sortToggleLabels = { + 0: {ascending: 'A-Z', descending: 'Z-A'}, + 1: {ascending: 'Ascending', descending: 'Descending'}, + 2: {ascending: 'Newest', descending: 'Oldest'}, + 3: {ascending: 'Ascending', descending: 'Ascending'}, + 4: {ascending: 'A-Z', descending: 'Z-A'}, + 5: {ascending: 'A-Z', descending: 'Z-A'}, + 6: {ascending: 'A-Z', descending: 'Z-A'}, + 7: {ascending: 'A-Z', descending: 'Z-A'}, + }; + + const initialRows = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + date: '2022-02-04', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Paid', + notes: '', + }, + { + id: '2561', + url: '#', + date: '2022-01-19', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: 'This customer lives on the 3rd floor', + }, + { + id: '1245', + url: '#', + date: '2021-12-12', + name: 'Anne-Marie Johnson', + location: 'Portland, USA', + orders: 10, + amountSpent: '$250', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: '', + }, + { + id: '8741', + url: '#', + date: '2022-05-11', + name: 'Bradley Stevens', + location: 'Hialeah, USA', + orders: 5, + amountSpent: '$26', + fulfillmentStatus: 'Unfulfilled', + paymentStatus: 'Not paid', + notes: 'This customer has requested fragile delivery', + }, + ]; + const [sortedRows, setSortedRows] = useState( + sortRows(initialRows, sortIndex, sortDirection), + ); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const rows = sortedRows ?? initialRows; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows); + + function handleClickSortHeading(index, direction) { + setSortIndex(index); + setSortDirection(direction); + const newSortedRows = sortRows(rows, index, direction); + setSortedRows(newSortedRows); + } + + function sortRows(localRows, index, direction) { + return [...localRows].sort((rowA, rowB) => { + const key = index === 0 ? 'name' : 'location'; + if (rowA[key] < rowB[key]) { + return direction === 'descending' ? -1 : 1; } - onSelectionChange={handleSelectionChange} - headings={[ - {title: 'Name'}, - {title: 'Date', defaultSortDirection: 'ascending'}, - { - alignment: 'end', - id: 'order-count', - title: 'Order count', - }, + if (rowA[key] > rowB[key]) { + return direction === 'descending' ? 1 : -1; + } + return 0; + }); + } + + const rowMarkup = rows.map( + ( + { + id, + name, + date, + location, + orders, + amountSpent, + fulfillmentStatus, + paymentStatus, + notes, + }, + index, + ) => ( + + + + {name} + + + {date} + + + {orders} + + + + + {amountSpent} + + + + + {location} + + + {fulfillmentStatus} + {paymentStatus} + {notes} + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithHeadingWithPaddingBlockEnd = { + render() { + const [sortIndex, setSortIndex] = useState(0); + const [sortDirection, setSortDirection] = + useState('descending'); + + const sortToggleLabels = { + 0: {ascending: 'A-Z', descending: 'Z-A'}, + 1: {ascending: 'Ascending', descending: 'Descending'}, + 2: {ascending: 'Newest', descending: 'Oldest'}, + 3: {ascending: 'Ascending', descending: 'Ascending'}, + 4: {ascending: 'A-Z', descending: 'Z-A'}, + 5: {ascending: 'A-Z', descending: 'Z-A'}, + 6: {ascending: 'A-Z', descending: 'Z-A'}, + 7: {ascending: 'A-Z', descending: 'Z-A'}, + }; + + const initialRows = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + date: '2022-02-04', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Paid', + notes: '', + }, + { + id: '2561', + url: '#', + date: '2022-01-19', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: 'This customer lives on the 3rd floor', + }, + { + id: '1245', + url: '#', + date: '2021-12-12', + name: 'Anne-Marie Johnson', + location: 'Portland, USA', + orders: 10, + amountSpent: '$250', + fulfillmentStatus: 'Fulfilled', + paymentStatus: 'Not paid', + notes: '', + }, + { + id: '8741', + url: '#', + date: '2022-05-11', + name: 'Bradley Stevens', + location: 'Hialeah, USA', + orders: 5, + amountSpent: '$26', + fulfillmentStatus: 'Unfulfilled', + paymentStatus: 'Not paid', + notes: 'This customer has requested fragile delivery', + }, + ]; + const [sortedRows, setSortedRows] = useState( + sortRows(initialRows, sortIndex, sortDirection), + ); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const rows = sortedRows ?? initialRows; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows); + + function handleClickSortHeading(index, direction) { + setSortIndex(index); + setSortDirection(direction); + const newSortedRows = sortRows(rows, index, direction); + setSortedRows(newSortedRows); + } + + function sortRows(localRows, index, direction) { + return [...localRows].sort((rowA, rowB) => { + const key = index === 0 ? 'name' : 'location'; + if (rowA[key] < rowB[key]) { + return direction === 'descending' ? -1 : 1; + } + if (rowA[key] > rowB[key]) { + return direction === 'descending' ? 1 : -1; + } + return 0; + }); + } + + const rowMarkup = rows.map( + ( + { + id, + name, + date, + location, + orders, + amountSpent, + fulfillmentStatus, + paymentStatus, + notes, + }, + index, + ) => ( + + + + {name} + + + {date} + + + {orders} + + + + + + {amountSpent} + + + + + + {location} + + + {fulfillmentStatus} + {paymentStatus} + {notes} + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithCustomTooltips = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithHeadingTooltips = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithZebraStriping = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + + const customersForNestedRows = [ + { + id: '34101', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '34111', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '34121', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '34131', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '25631', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + const nestedRowMarkup = customersForNestedRows.map( + ({id, name, location, orders, amountSpent}, index) => ( + 0 ? 'child' : 'subheader'} + > + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + {nestedRowMarkup} + + + ); + }, +}; + +export const WithZebraStripingCondensed = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithZebraStripingAndRowStatus = { + render() { + const customers = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + status: 'success', + }, + { + id: '2561', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + status: 'subdued', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent, status}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithZebraStripingAndStickyLastColumn = { + render() { + const customers = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + channel: 'Point of Sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + }, + { + id: '2561', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + channel: 'Online Store', + paymentStatus: 'Paid', + fulfillmentStatus: 'Unfulfilled', + }, + { + id: '2562', + url: '#', + name: 'Helen Troy', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$975', + lastOrderDate: 'May 31, 2023', + }, + { + id: '4102', + url: '#', + name: 'Colm Dillane', + location: 'New York, USA', + orders: 27, + amountSpent: '$2885', + lastOrderDate: 'May 31, 2023', + }, + { + id: '2564', + url: '#', + name: 'Al Chemist', + location: 'New York, USA', + orders: 19, + amountSpent: '$1,209', + lastOrderDate: 'April 4, 2023', + disabled: true, + }, + { + id: '2563', + url: '#', + name: 'Larry June', + location: 'San Francisco, USA', + orders: 22, + amountSpent: '$1,400', + lastOrderDate: 'March 19, 2023', + }, + ]; + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ( + { + id, + name, + location, + orders, + amountSpent, + channel, + paymentStatus, + fulfillmentStatus, + }, + index, + ) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + {channel} + {paymentStatus} + {fulfillmentStatus} + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithZebraStripingAndWithoutCheckboxes = { + render() { + const customers = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '2561', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ), + ); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const SmallScreenWithAllOfItsElements = { + render() { + const customers = [ + { + id: '3410', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$2,400', + }, + { + id: '3411', + url: '#', + name: 'Joe Jemison', + location: 'Sydney, AU', + orders: 20, + amountSpent: '$1,400', + }, + { + id: '3412', + url: '#', + name: 'Sam Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$400', + }, + { + id: '3413', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$4,300', + }, + { + id: '2563', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$140', + }, + ]; + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + const [taggedWith, setTaggedWith] = useState('VIP'); + const [queryValue, setQueryValue] = useState(''); + const [sortValue, setSortValue] = useState(['today asc']); + + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + const handleSortChange = useCallback((value) => setSortValue(value), []); + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ { - alignment: 'end', - id: 'amount-spent', - title: 'Amount spent', + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, }, + ] + : []; + + const sortOptions: IndexFiltersProps['sortOptions'] = [ + {label: 'Date', value: 'today asc', directionLabel: 'Ascending'}, + {label: 'Date', value: 'today desc', directionLabel: 'Descending'}, + ]; + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + +
+ + {name} + + + + {location} + + + + {orders} + + + {amountSpent} + +
+
+ ), + ); + + const tabs = [ + { + id: 'all', + content: 'All customers', + }, + ]; - {title: 'Location'}, - {title: 'Fulfillment status'}, - {title: 'Payment status'}, - {title: 'Notes', alignment: 'end'}, - ]} - sortable={[true, true, false, true, true, false, false, true]} - sortDirection={sortDirection} - sortColumnIndex={sortIndex} - onSort={handleClickSortHeading} - sortToggleLabels={sortToggleLabels} - lastColumnSticky - > - {rowMarkup} -
-
- ); -} - -export function WithSortableCustomHeadings() { - const [sortIndex, setSortIndex] = useState(0); - const [sortDirection, setSortDirection] = - useState('descending'); - - const sortToggleLabels = { - 0: {ascending: 'A-Z', descending: 'Z-A'}, - 1: {ascending: 'Ascending', descending: 'Descending'}, - 2: {ascending: 'Newest', descending: 'Oldest'}, - 3: {ascending: 'Ascending', descending: 'Ascending'}, - 4: {ascending: 'A-Z', descending: 'Z-A'}, - 5: {ascending: 'A-Z', descending: 'Z-A'}, - 6: {ascending: 'A-Z', descending: 'Z-A'}, - 7: {ascending: 'A-Z', descending: 'Z-A'}, - }; - - const initialRows = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - date: '2022-02-04', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Paid', - notes: '', - }, - { - id: '2561', - url: '#', - date: '2022-01-19', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: 'This customer lives on the 3rd floor', - }, - { - id: '1245', - url: '#', - date: '2021-12-12', - name: 'Anne-Marie Johnson', - location: 'Portland, USA', - orders: 10, - amountSpent: '$250', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: '', - }, - { - id: '8741', - url: '#', - date: '2022-05-11', - name: 'Bradley Stevens', - location: 'Hialeah, USA', - orders: 5, - amountSpent: '$26', - fulfillmentStatus: 'Unfulfilled', - paymentStatus: 'Not paid', - notes: 'This customer has requested fragile delivery', - }, - ]; - const [sortedRows, setSortedRows] = useState( - sortRows(initialRows, sortIndex, sortDirection), - ); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const rows = sortedRows ?? initialRows; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows); - - function handleClickSortHeading(index, direction) { - setSortIndex(index); - setSortDirection(direction); - const newSortedRows = sortRows(rows, index, direction); - setSortedRows(newSortedRows); - } - - function sortRows(localRows, index, direction) { - return [...localRows].sort((rowA, rowB) => { - const key = index === 0 ? 'name' : 'location'; - if (rowA[key] < rowB[key]) { - return direction === 'descending' ? -1 : 1; + const {mode, setMode} = useSetIndexFiltersMode(); + + const cancelAction = { + onAction: () => {}, + }; + + async function emptyPromise() { + const prom = Promise.resolve(); + return prom.then(() => { + return true; + }); + } + + const primaryAction: IndexFiltersProps['primaryAction'] = { + onAction: emptyPromise, + type: 'save-as', + }; + + return ( +
+ + {}} + onCreateNewView={emptyPromise} + queryValue={queryValue} + queryPlaceholder="Searching in all" + filters={filters} + appliedFilters={appliedFilters} + onQueryChange={setQueryValue} + onQueryClear={handleQueryValueRemove} + onClearAll={handleClearAll} + sortOptions={sortOptions} + sortSelected={sortValue} + onSort={handleSortChange} + mode={mode} + setMode={setMode} + cancelAction={cancelAction} + primaryAction={primaryAction} + /> + + {rowMarkup} + + +
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; } - if (rowA[key] > rowB[key]) { - return direction === 'descending' ? 1 : -1; + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; } - return 0; - }); - } - - const rowMarkup = rows.map( - ( - { - id, - name, - date, - location, - orders, - amountSpent, - fulfillmentStatus, - paymentStatus, - notes, - }, - index, - ) => ( - - - - {name} - - - {date} - - - {orders} - - - - - {amountSpent} - - - - - {location} - - - {fulfillmentStatus} - {paymentStatus} - {notes} - - ), - ); - - return ( - - string) => { + let position = -1; + const groups = rows.reduce((groups, customer) => { + const groupVal = customer[groupKey]; + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + customers: [], + id: resolveId(groupVal), + }; } - onSelectionChange={handleSelectionChange} - headings={[ - { - title: 'Name', - tooltipContent: 'I am a wide tooltip describing the Name column', - tooltipWidth: 'wide', - }, - {title: 'Date', tooltipContent: 'I am the Date tooltip'}, - { - alignment: 'end', - id: 'order-count', - title: 'Order count', - }, - { - alignment: 'end', - title: 'Amount spent', - tooltipContent: - 'I am a wide Amount spent tooltip that stays when clicked', - tooltipWidth: 'wide', - }, - {title: 'Location'}, - {title: 'Fulfillment status'}, - {title: 'Payment status'}, - {title: 'Notes'}, - ]} - sortable={[true, true, false, true, true, false, false]} - sortDirection={sortDirection} - sortColumnIndex={sortIndex} - onSort={handleClickSortHeading} - sortToggleLabels={sortToggleLabels} - lastColumnSticky - > - {rowMarkup} - - - ); -} - -export function WithHeadingWithPaddingBlockEnd() { - const [sortIndex, setSortIndex] = useState(0); - const [sortDirection, setSortDirection] = - useState('descending'); - - const sortToggleLabels = { - 0: {ascending: 'A-Z', descending: 'Z-A'}, - 1: {ascending: 'Ascending', descending: 'Descending'}, - 2: {ascending: 'Newest', descending: 'Oldest'}, - 3: {ascending: 'Ascending', descending: 'Ascending'}, - 4: {ascending: 'A-Z', descending: 'Z-A'}, - 5: {ascending: 'A-Z', descending: 'Z-A'}, - 6: {ascending: 'A-Z', descending: 'Z-A'}, - 7: {ascending: 'A-Z', descending: 'Z-A'}, - }; - - const initialRows = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - date: '2022-02-04', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Paid', - notes: '', - }, - { - id: '2561', - url: '#', - date: '2022-01-19', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: 'This customer lives on the 3rd floor', - }, - { - id: '1245', - url: '#', - date: '2021-12-12', - name: 'Anne-Marie Johnson', - location: 'Portland, USA', - orders: 10, - amountSpent: '$250', - fulfillmentStatus: 'Fulfilled', - paymentStatus: 'Not paid', - notes: '', - }, - { - id: '8741', - url: '#', - date: '2022-05-11', - name: 'Bradley Stevens', - location: 'Hialeah, USA', - orders: 5, - amountSpent: '$26', - fulfillmentStatus: 'Unfulfilled', - paymentStatus: 'Not paid', - notes: 'This customer has requested fragile delivery', - }, - ]; - const [sortedRows, setSortedRows] = useState( - sortRows(initialRows, sortIndex, sortDirection), - ); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const rows = sortedRows ?? initialRows; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows); - - function handleClickSortHeading(index, direction) { - setSortIndex(index); - setSortDirection(direction); - const newSortedRows = sortRows(rows, index, direction); - setSortedRows(newSortedRows); - } - - function sortRows(localRows, index, direction) { - return [...localRows].sort((rowA, rowB) => { - const key = index === 0 ? 'name' : 'location'; - if (rowA[key] < rowB[key]) { - return direction === 'descending' ? -1 : 1; - } - if (rowA[key] > rowB[key]) { - return direction === 'descending' ? 1 : -1; + + groups[groupVal].customers.push({ + ...customer, + position: position + 1, + }); + + position += 1; + return groups; + }, {}); + + return groups; + }; + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + + const orders = groupRowsBy( + 'lastOrderDate', + (date) => + `last-order-date--${date.replace(',', '').split(' ').join('-')}`, + ); + + const rowMarkup = Object.keys(orders).map((orderDate, index) => { + const {customers, position, id: subheaderId} = orders[orderDate]; + let selected: IndexTableRowProps['selected'] = false; + + const someCustomersSelected = customers.some(({id}) => + selectedResources.includes(id), + ); + + const allCustomersSelected = customers.every(({id}) => + selectedResources.includes(id), + ); + + if (allCustomersSelected) { + selected = true; + } else if (someCustomersSelected) { + selected = 'indeterminate'; } - return 0; + + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === customers[0].id), + selectableRows.findIndex( + (row) => row.id === customers[customers.length - 1].id, + ), + ]; + + const disabled = customers.every(({disabled}) => disabled); + + return ( + + + + {`Last order placed: ${orderDate}`} + + + + + + {customers.map( + ( + {id, name, location, orders, amountSpent, position, disabled}, + rowIndex, + ) => { + return ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ); + }, + )} + + ); + }); + + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithPagination = { + render() { + const customers = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '#', + name: `Mae Jemison ${num}`, + location: 'Decatur, USA', + orders: 20, + amountSpent: '$24,00', + }; }); - } - - const rowMarkup = rows.map( - ( - { - id, - name, - date, - location, - orders, - amountSpent, - fulfillmentStatus, - paymentStatus, - notes, - }, - index, - ) => ( - - - - {name} - - - {date} - - - {orders} - - - - - - {amountSpent} - - - - - - {location} - - - {fulfillmentStatus} - {paymentStatus} - {notes} - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithCustomTooltips() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithHeadingTooltips() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithZebraStriping() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - - const customersForNestedRows = [ - { - id: '34101', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '34111', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '34121', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '34131', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '25631', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - const nestedRowMarkup = customersForNestedRows.map( - ({id, name, location, orders, amountSpent}, index) => ( - 0 ? 'child' : 'subheader'} - > - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - {nestedRowMarkup} - - - ); -} - -export function WithZebraStripingCondensed() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithZebraStripingAndRowStatus() { - const customers = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - status: 'success', - }, - { - id: '2561', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - status: 'subdued', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent, status}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithZebraStripingAndStickyLastColumn() { - const customers = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - channel: 'Point of Sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - }, - { - id: '2561', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - channel: 'Online Store', - paymentStatus: 'Paid', - fulfillmentStatus: 'Unfulfilled', - }, - { - id: '2562', - url: '#', - name: 'Helen Troy', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$975', - lastOrderDate: 'May 31, 2023', - }, - { - id: '4102', - url: '#', - name: 'Colm Dillane', - location: 'New York, USA', - orders: 27, - amountSpent: '$2885', - lastOrderDate: 'May 31, 2023', - }, - { - id: '2564', - url: '#', - name: 'Al Chemist', - location: 'New York, USA', - orders: 19, - amountSpent: '$1,209', - lastOrderDate: 'April 4, 2023', - disabled: true, - }, - { - id: '2563', - url: '#', - name: 'Larry June', - location: 'San Francisco, USA', - orders: 22, - amountSpent: '$1,400', - lastOrderDate: 'March 19, 2023', - }, - ]; - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ( - { - id, - name, - location, - orders, - amountSpent, - channel, - paymentStatus, - fulfillmentStatus, - }, - index, - ) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - {channel} - {paymentStatus} - {fulfillmentStatus} - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithZebraStripingAndWithoutCheckboxes() { - const customers = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '2561', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function SmallScreenWithAllOfItsElements() { - const customers = [ - { - id: '3410', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$2,400', - }, - { - id: '3411', - url: '#', - name: 'Joe Jemison', - location: 'Sydney, AU', - orders: 20, - amountSpent: '$1,400', - }, - { - id: '3412', - url: '#', - name: 'Sam Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$400', - }, - { - id: '3413', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$4,300', - }, - { - id: '2563', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$140', - }, - ]; - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - const [taggedWith, setTaggedWith] = useState('VIP'); - const [queryValue, setQueryValue] = useState(''); - const [sortValue, setSortValue] = useState(['today asc']); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(''), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(''), []); - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - const handleSortChange = useCallback((value) => setSortValue(value), []); - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - ]; - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - const sortOptions: IndexFiltersProps['sortOptions'] = [ - {label: 'Date', value: 'today asc', directionLabel: 'Ascending'}, - {label: 'Date', value: 'today desc', directionLabel: 'Descending'}, - ]; - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - -
- - {name} - - + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ({id, name, location, orders, amountSpent}, index) => ( + + + + {name} + + + {location} - - - {orders} - - - {amountSpent} - -
-
- ), - ); - - const tabs = [ - { - id: 'all', - content: 'All customers', - }, - ]; - - const {mode, setMode} = useSetIndexFiltersMode(); - - const cancelAction = { - onAction: () => {}, - }; - - async function emptyPromise() { - const prom = Promise.resolve(); - return prom.then(() => { - return true; - }); - } - - const primaryAction: IndexFiltersProps['primaryAction'] = { - onAction: emptyPromise, - type: 'save-as', - }; + + + + {orders} + + + + + {amountSpent} + + + + ), + ); - return ( -
+ return ( - {}} - onCreateNewView={emptyPromise} - queryValue={queryValue} - queryPlaceholder="Searching in all" - filters={filters} - appliedFilters={appliedFilters} - onQueryChange={setQueryValue} - onQueryClear={handleQueryValueRemove} - onClearAll={handleClearAll} - sortOptions={sortOptions} - sortSelected={sortValue} - onSort={handleSortChange} - mode={mode} - setMode={setMode} - cancelAction={cancelAction} - primaryAction={primaryAction} - /> {}, + }} > {rowMarkup} -
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; - } - } + ); + }, +}; + +export const WithStickyScrollBar = { + render() { + const customers = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '#', + name: `Mae Jemison ${num}`, + location: 'Truth or Consequences, United States of America', + orders: 20, + amountSpent: '$24,00', + channel: 'Point of sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + tags: 'No tags applied', + }; + }); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const rowMarkup = customers.map( + ( + { + id, + name, + location, + orders, + amountSpent, + channel, + paymentStatus, + fulfillmentStatus, + tags, + }, + index, + ) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + {channel} + {paymentStatus} + {fulfillmentStatus} + {tags} + + ), + ); + + return ( + + + + + {rowMarkup} + + + + + ); + }, +}; + +export const WithPaginationAndBulkActions = { + render() { + const customers = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '#', + name: `Mae Jemison ${num}`, + location: 'Truth or Consequences, United States of America', + orders: 20, + amountSpent: '$24,00', + channel: 'Point of sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + tags: 'No tags applied', + }; + }); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(customers); + + const promotedBulkActions = [ + { + content: 'Capture payments', + onAction: () => console.log('Todo: implement payment capture'), + }, + { + title: 'Edit customers', + actions: [ + { + content: 'Add customers', + onAction: () => console.log('Todo: implement adding customers'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement deleting customers'), + }, + ], + }, + { + title: 'Export', + actions: [ + { + content: 'Export as PDF', + onAction: () => console.log('Todo: implement PDF exporting'), + }, + { + content: 'Export as CSV', + onAction: () => console.log('Todo: implement CSV exporting'), + }, + ], + }, + ]; + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + const rowMarkup = customers.map( + ( + { + id, + name, + location, + orders, + amountSpent, + channel, + paymentStatus, + fulfillmentStatus, + tags, + }, + index, + ) => ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + {channel} + {paymentStatus} + {fulfillmentStatus} + {tags} + + ), + ); + + return ( + + + {}, + }} + > + {rowMarkup} + + + + ); + }, +}; + +export const WithSubHeadersNonSelectable = { + render() { + const rows = [ + { + id: '3411', + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 11, + amountSpent: '$2,400', + lastOrderDate: 'May 31, 2023', + }, + { + id: '2562', + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + orders: 30, + amountSpent: '$975', + lastOrderDate: 'May 31, 2023', + }, + { + id: '4102', + url: '#', + name: 'Colm Dillane', + location: 'New York, USA', + orders: 27, + amountSpent: '$2885', + lastOrderDate: 'May 31, 2023', + }, + { + id: '2564', + url: '#', + name: 'Al Chemist', + location: 'New York, USA', + orders: 19, + amountSpent: '$1,209', + lastOrderDate: 'April 4, 2023', + disabled: true, + }, + { + id: '2563', + url: '#', + name: 'Larry June', + location: 'San Francisco, USA', + orders: 22, + amountSpent: '$1,400', + lastOrderDate: 'March 19, 2023', + }, + ]; + + const columnHeadings = [ + {title: 'Name', id: 'column-header--name'}, + {title: 'Location', id: 'column-header--location'}, + { + alignment: 'end', + id: 'column-header--order-count', + title: 'Order count', + }, + { + alignment: 'end', + hidden: false, + id: 'column-header--amount-spent', + title: 'Amount spent', + }, + ]; + + const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { + let position = -1; + const groups = rows.reduce((groups, customer) => { + const groupVal = customer[groupKey]; + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + customers: [], + id: resolveId(groupVal), + }; + } + + groups[groupVal].customers.push({ + ...customer, + position: position + 1, + }); - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; - } - } -} - -export function WithSubHeaders() { - const rows = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 11, - amountSpent: '$2,400', - lastOrderDate: 'May 31, 2023', - }, - { - id: '2562', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$975', - lastOrderDate: 'May 31, 2023', - }, - { - id: '4102', - url: '#', - name: 'Colm Dillane', - location: 'New York, USA', - orders: 27, - amountSpent: '$2885', - lastOrderDate: 'May 31, 2023', - }, - { - id: '2564', - url: '#', - name: 'Al Chemist', - location: 'New York, USA', - orders: 19, - amountSpent: '$1,209', - lastOrderDate: 'April 4, 2023', - disabled: true, - }, - { - id: '2563', - url: '#', - name: 'Larry June', - location: 'San Francisco, USA', - orders: 22, - amountSpent: '$1,400', - lastOrderDate: 'March 19, 2023', - }, - ]; - - const columnHeadings = [ - {title: 'Name', id: 'column-header--name'}, - {title: 'Location', id: 'column-header--location'}, - { - alignment: 'end', - id: 'column-header--order-count', - title: 'Order count', - }, - { - alignment: 'end', - hidden: false, - id: 'column-header--amount-spent', - title: 'Amount spent', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, customer) => { - const groupVal = customer[groupKey]; - if (!groups[groupVal]) { position += 1; + return groups; + }, {}); + + return groups; + }; + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + + const orders = groupRowsBy( + 'lastOrderDate', + (date) => + `last-order-date--${date.replace(',', '').split(' ').join('-')}`, + ); + + const rowMarkup = Object.keys(orders).map((orderDate, index) => { + const {customers, position, id: subheaderId} = orders[orderDate]; + let selected: IndexTableRowProps['selected'] = false; + + const someCustomersSelected = customers.some(({id}) => + selectedResources.includes(id), + ); + + const allCustomersSelected = customers.every(({id}) => + selectedResources.includes(id), + ); - groups[groupVal] = { - position, - customers: [], - id: resolveId(groupVal), - }; + if (allCustomersSelected) { + selected = true; + } else if (someCustomersSelected) { + selected = 'indeterminate'; } - groups[groupVal].customers.push({ - ...customer, - position: position + 1, - }); + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === customers[0].id), + selectableRows.findIndex( + (row) => row.id === customers[customers.length - 1].id, + ), + ]; + + const disabled = customers.every(({disabled}) => disabled); + + return ( + + + + {`Last order placed: ${orderDate}`} + + + + + + {customers.map( + ( + {id, name, location, orders, amountSpent, position, disabled}, + rowIndex, + ) => { + return ( + + + + {name} + + + + + {location} + + + + + {orders} + + + + + {amountSpent} + + + + ); + }, + )} + + ); + }); - position += 1; - return groups; - }, {}); + return ( + + + {rowMarkup} + + + ); + }, +}; + +export const WithNestedRows = { + render() { + const rows = [ + { + id: '3411', + quantity: 11, + price: '$2,400', + size: 'Small Lorem ipsum dolor sit amet', + color: 'Orange Lorem ipsum dolor sit amet', + }, + { + id: '2562', + quantity: 30, + price: '$975', + size: 'Medium', + color: 'Orange', + }, + { + id: '4102', + quantity: 27, + price: '$2885', + size: 'Large', + color: 'Orange', + }, + { + id: '2564', + quantity: 19, + price: '$1,209', + size: 'Small', + color: 'Red', + disabled: true, + }, + { + id: '2563', + quantity: 22, + price: '$1,400', + size: 'Small', + color: 'Green', + }, + ]; + + const columnHeadings = [ + {title: 'Name', id: 'column-header--name'}, + { + hidden: false, + id: 'column-header--price', + title: 'Price', + }, + { + alignment: 'end', + id: 'column-header--quantity', + title: 'Available', + }, + ]; - return groups; - }; + const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { + let position = -1; + const groups = rows.reduce((groups, product) => { + const groupVal = product[groupKey]; + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + products: [], + id: resolveId(groupVal), + }; + } + groups[groupVal].products.push({ + ...product, + position: position + 1, + }); - const resourceName = { - singular: 'customer', - plural: 'customers', - }; + position += 1; + return groups; + }, {}); - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + return groups; + }; - const orders = groupRowsBy( - 'lastOrderDate', - (date) => `last-order-date--${date.replace(',', '').split(' ').join('-')}`, - ); + const resourceName = { + singular: 'product', + plural: 'products', + }; - const rowMarkup = Object.keys(orders).map((orderDate, index) => { - const {customers, position, id: subheaderId} = orders[orderDate]; - let selected: IndexTableRowProps['selected'] = false; + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - const someCustomersSelected = customers.some(({id}) => - selectedResources.includes(id), + const groupedProducts = groupRowsBy( + 'color', + (color) => `color--${color.toLowerCase()}`, ); - const allCustomersSelected = customers.every(({id}) => - selectedResources.includes(id), - ); + const rowMarkup = Object.keys(groupedProducts).map((color, index) => { + const {products, position, id: subheaderId} = groupedProducts[color]; + let selected: IndexTableRowProps['selected'] = false; - if (allCustomersSelected) { - selected = true; - } else if (someCustomersSelected) { - selected = 'indeterminate'; - } + const someProductsSelected = products.some(({id}) => + selectedResources.includes(id), + ); - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === customers[0].id), - selectableRows.findIndex( - (row) => row.id === customers[customers.length - 1].id, - ), - ]; + const allProductsSelected = products.every(({id}) => + selectedResources.includes(id), + ); - const disabled = customers.every(({disabled}) => disabled); + if (allProductsSelected) { + selected = true; + } else if (someProductsSelected) { + selected = 'indeterminate'; + } - return ( - - - - {`Last order placed: ${orderDate}`} - - - - - - {customers.map( - ( - {id, name, location, orders, amountSpent, position, disabled}, - rowIndex, - ) => { - return ( - - !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === products[0].id), + selectableRows.findIndex( + (row) => row.id === products[products.length - 1].id, + ), + ]; + + const disabled = products.every(({disabled}) => disabled); + + return ( + + + + + {color} + + + + + + {products.map( + ({id, size, quantity, price, position, disabled}, rowIndex) => { + return ( + - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ); - }, - )} - - ); - }); + + + {size} + + + + + {price} + + + + + {quantity} + + + + ); + }, + )} + + ); + }); - return ( - - - {rowMarkup} - - - ); -} - -export function WithPagination() { - const customers = Array.from({length: 50}, (_, num) => { - return { - id: `${num}`, - url: '#', - name: `Mae Jemison ${num}`, - location: 'Decatur, USA', - orders: 20, - amountSpent: '$24,00', - }; - }); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ({id, name, location, orders, amountSpent}, index) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ), - ); - - return ( - - {}, - }} - > - {rowMarkup} - - - ); -} - -export function WithStickyScrollBar() { - const customers = Array.from({length: 50}, (_, num) => { - return { - id: `${num}`, - url: '#', - name: `Mae Jemison ${num}`, - location: 'Truth or Consequences, United States of America', - orders: 20, - amountSpent: '$24,00', - channel: 'Point of sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - tags: 'No tags applied', - }; - }); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const rowMarkup = customers.map( - ( - { - id, - name, - location, - orders, - amountSpent, - channel, - paymentStatus, - fulfillmentStatus, - tags, - }, - index, - ) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - {channel} - {paymentStatus} - {fulfillmentStatus} - {tags} - - ), - ); - - return ( - - - - - {rowMarkup} - - - - - ); -} - -export function WithPaginationAndBulkActions() { - const customers = Array.from({length: 50}, (_, num) => { - return { - id: `${num}`, - url: '#', - name: `Mae Jemison ${num}`, - location: 'Truth or Consequences, United States of America', - orders: 20, - amountSpent: '$24,00', - channel: 'Point of sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - tags: 'No tags applied', - }; - }); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(customers); - - const promotedBulkActions = [ - { - content: 'Capture payments', - onAction: () => console.log('Todo: implement payment capture'), - }, - { - title: 'Edit customers', - actions: [ - { - content: 'Add customers', - onAction: () => console.log('Todo: implement adding customers'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement deleting customers'), - }, - ], - }, - { - title: 'Export', - actions: [ - { - content: 'Export as PDF', - onAction: () => console.log('Todo: implement PDF exporting'), - }, - { - content: 'Export as CSV', - onAction: () => console.log('Todo: implement CSV exporting'), - }, - ], - }, - ]; - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - const rowMarkup = customers.map( - ( - { - id, - name, - location, - orders, - amountSpent, - channel, - paymentStatus, - fulfillmentStatus, - tags, - }, - index, - ) => ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - {channel} - {paymentStatus} - {fulfillmentStatus} - {tags} - - ), - ); - - return ( - - + return ( + {}, - }} + resourceName={resourceName} + itemCount={rows.length} + headings={columnHeadings as IndexTableProps['headings']} > {rowMarkup} - - - ); -} - -export function WithSubHeadersNonSelectable() { - const rows = [ - { - id: '3411', - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 11, - amountSpent: '$2,400', - lastOrderDate: 'May 31, 2023', - }, - { - id: '2562', - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - orders: 30, - amountSpent: '$975', - lastOrderDate: 'May 31, 2023', - }, - { - id: '4102', - url: '#', - name: 'Colm Dillane', - location: 'New York, USA', - orders: 27, - amountSpent: '$2885', - lastOrderDate: 'May 31, 2023', - }, - { - id: '2564', - url: '#', - name: 'Al Chemist', - location: 'New York, USA', - orders: 19, - amountSpent: '$1,209', - lastOrderDate: 'April 4, 2023', - disabled: true, - }, - { - id: '2563', - url: '#', - name: 'Larry June', - location: 'San Francisco, USA', - orders: 22, - amountSpent: '$1,400', - lastOrderDate: 'March 19, 2023', - }, - ]; - - const columnHeadings = [ - {title: 'Name', id: 'column-header--name'}, - {title: 'Location', id: 'column-header--location'}, - { - alignment: 'end', - id: 'column-header--order-count', - title: 'Order count', - }, - { - alignment: 'end', - hidden: false, - id: 'column-header--amount-spent', - title: 'Amount spent', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, customer) => { - const groupVal = customer[groupKey]; - if (!groups[groupVal]) { - position += 1; - - groups[groupVal] = { - position, - customers: [], - id: resolveId(groupVal), - }; - } + + ); + }, +}; - groups[groupVal].customers.push({ - ...customer, - position: position + 1, - }); +export const WithNestedRowsStickyLastColumn = { + render() { + const rows = [ + { + id: '3411', + quantity: 11, + price: '$2,400', + size: 'Small Lorem ipsum dolor sit amet', + color: 'Orange Lorem ipsum dolor sit amet', + vendor: 'Fit Lines', + channel: 'Point of Sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + }, + { + id: '2562', + quantity: 30, + price: '$975', + size: 'Medium', + color: 'Orange', + vendor: 'Fit Lines', + channel: 'Point of Sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + }, + { + id: '4102', + quantity: 27, + price: '$2885', + size: 'Large', + color: 'Orange', + vendor: 'Fit Lines', + channel: 'Point of Sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + }, + { + id: '2564', + quantity: 19, + price: '$1,209', + size: 'Small', + color: 'Red', + disabled: true, + vendor: 'Fit Lines', + channel: 'Point of Sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + }, + { + id: '2563', + quantity: 22, + price: '$1,400', + size: 'Small', + color: 'Green', + vendor: 'Fit Lines', + channel: 'Point of Sale', + paymentStatus: 'Refunded', + fulfillmentStatus: 'Fulfilled', + }, + ]; - position += 1; - return groups; - }, {}); + const columnHeadings = [ + {title: 'Name', id: 'column-header--size'}, + { + hidden: false, + id: 'column-header--price', + title: 'Price', + }, + { + alignment: 'end', + id: 'column-header--quantity', + title: 'Available', + }, + { + alignment: 'end', + id: 'column-header--vendor', + title: 'Vendor', + }, + { + alignment: 'end', + id: 'column-header--channel', + title: 'Channel', + }, + { + alignment: 'end', + id: 'column-header--paymentStatus', + title: 'Status', + }, + { + alignment: 'end', + id: 'column-header--fulfillmentStatus', + title: 'Fulfillment Status', + }, + ]; - return groups; - }; + const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { + let position = -1; + const groups = rows.reduce((groups, product) => { + const groupVal = product[groupKey]; + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + products: [], + id: resolveId(groupVal), + }; + } + groups[groupVal].products.push({ + ...product, + position: position + 1, + }); - const resourceName = { - singular: 'customer', - plural: 'customers', - }; + position += 1; + return groups; + }, {}); - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + return groups; + }; - const orders = groupRowsBy( - 'lastOrderDate', - (date) => `last-order-date--${date.replace(',', '').split(' ').join('-')}`, - ); + const resourceName = { + singular: 'product', + plural: 'products', + }; - const rowMarkup = Object.keys(orders).map((orderDate, index) => { - const {customers, position, id: subheaderId} = orders[orderDate]; - let selected: IndexTableRowProps['selected'] = false; + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - const someCustomersSelected = customers.some(({id}) => - selectedResources.includes(id), + const groupedProducts = groupRowsBy( + 'color', + (color) => `color--${color.toLowerCase()}`, ); - const allCustomersSelected = customers.every(({id}) => - selectedResources.includes(id), - ); + const rowMarkup = Object.keys(groupedProducts).map((color, index) => { + const {products, position, id: subheaderId} = groupedProducts[color]; + let selected: IndexTableRowProps['selected'] = false; - if (allCustomersSelected) { - selected = true; - } else if (someCustomersSelected) { - selected = 'indeterminate'; - } + const someProductsSelected = products.some(({id}) => + selectedResources.includes(id), + ); - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === customers[0].id), - selectableRows.findIndex( - (row) => row.id === customers[customers.length - 1].id, - ), - ]; + const allProductsSelected = products.every(({id}) => + selectedResources.includes(id), + ); + + if (allProductsSelected) { + selected = true; + } else if (someProductsSelected) { + selected = 'indeterminate'; + } - const disabled = customers.every(({disabled}) => disabled); + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === products[0].id), + selectableRows.findIndex( + (row) => row.id === products[products.length - 1].id, + ), + ]; + + const disabled = products.every(({disabled}) => disabled); + + return ( + + + + + {color} + + + + + + + + + + {products.map( + ( + { + id, + size, + quantity, + price, + position, + disabled, + vendor, + channel, + paymentStatus, + fulfillmentStatus, + }, + rowIndex, + ) => { + return ( + + + + {size} + + + + + {price} + + + + + {quantity} + + + + + {vendor} + + + + + {channel} + + + + + {paymentStatus} + + + + + {fulfillmentStatus} + + + + ); + }, + )} + + ); + }); return ( - - + - - {`Last order placed: ${orderDate}`} - - - - - - {customers.map( - ( - {id, name, location, orders, amountSpent, position, disabled}, - rowIndex, - ) => { - return ( - - - - {name} - - - - - {location} - - - - - {orders} - - - - - {amountSpent} - - - - ); - }, - )} - + {rowMarkup} + + ); - }); + }, +}; - return ( - - string) => { + let position = -1; + const groups = rows.reduce((groups, product) => { + const groupVal = product[groupKey]; + + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + products: [], + id: resolveId(groupVal), + }; } - resourceName={resourceName} - itemCount={rows.length} - headings={columnHeadings as IndexTableProps['headings']} - selectable={false} - > - {rowMarkup} - - - ); -} - -export function WithNestedRows() { - const rows = [ - { - id: '3411', - quantity: 11, - price: '$2,400', - size: 'Small Lorem ipsum dolor sit amet', - color: 'Orange Lorem ipsum dolor sit amet', - }, - { - id: '2562', - quantity: 30, - price: '$975', - size: 'Medium', - color: 'Orange', - }, - { - id: '4102', - quantity: 27, - price: '$2885', - size: 'Large', - color: 'Orange', - }, - { - id: '2564', - quantity: 19, - price: '$1,209', - size: 'Small', - color: 'Red', - disabled: true, - }, - { - id: '2563', - quantity: 22, - price: '$1,400', - size: 'Small', - color: 'Green', - }, - ]; - - const columnHeadings = [ - {title: 'Name', id: 'column-header--name'}, - { - hidden: false, - id: 'column-header--price', - title: 'Price', - }, - { - alignment: 'end', - id: 'column-header--quantity', - title: 'Available', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, product) => { - const groupVal = product[groupKey]; - if (!groups[groupVal]) { - position += 1; - groups[groupVal] = { - position, - products: [], - id: resolveId(groupVal), - }; - } - groups[groupVal].products.push({ - ...product, - position: position + 1, - }); + groups[groupVal].products.push({ + ...product, + position: position + 1, + }); + + position += 1; + return groups; + }, {}); - position += 1; return groups; - }, {}); + }; + + const resourceName = { + singular: 'product', + plural: 'products', + }; - return groups; - }; + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - const resourceName = { - singular: 'product', - plural: 'products', - }; + const groupedProducts = groupRowsBy( + 'color', + (color) => `color--${color.toLowerCase()}`, + ); - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + const rowMarkup = Object.keys(groupedProducts).map((color, index) => { + const {products, position, id: subheaderId} = groupedProducts[color]; + let selected: IndexTableRowProps['selected'] = false; - const groupedProducts = groupRowsBy( - 'color', - (color) => `color--${color.toLowerCase()}`, - ); + const someProductsSelected = products.some(({id}) => + selectedResources.includes(id), + ); - const rowMarkup = Object.keys(groupedProducts).map((color, index) => { - const {products, position, id: subheaderId} = groupedProducts[color]; - let selected: IndexTableRowProps['selected'] = false; + const allProductsSelected = products.every(({id}) => + selectedResources.includes(id), + ); - const someProductsSelected = products.some(({id}) => - selectedResources.includes(id), - ); + if (allProductsSelected) { + selected = true; + } else if (someProductsSelected) { + selected = 'indeterminate'; + } + + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === products[0].id), + selectableRows.findIndex( + (row) => row.id === products[products.length - 1].id, + ), + ]; + + const disabled = products.every(({disabled}) => disabled); + + return ( + + + + + {color} + + + + + + {products.map( + ({id, size, quantity, price, position, disabled}, rowIndex) => { + return ( + + + + {size} + + + + + {price} + + + + + {quantity} + + + + ); + }, + )} + + ); + }); - const allProductsSelected = products.every(({id}) => - selectedResources.includes(id), + return ( + + + {rowMarkup} + + ); + }, +}; - if (allProductsSelected) { - selected = true; - } else if (someProductsSelected) { - selected = 'indeterminate'; - } - - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === products[0].id), - selectableRows.findIndex( - (row) => row.id === products[products.length - 1].id, - ), +export const WithNestedRowsWithThumbnails = { + render() { + const rows = [ + { + id: '3411', + quantity: 11, + price: '$2,400', + size: 'Small Lorem ipsum dolor sit amet', + color: 'Orange Lorem ipsum dolor sit amet', + }, + { + id: '2562', + quantity: 30, + price: '$975', + size: 'Medium', + color: 'Orange', + }, + { + id: '4102', + quantity: 27, + price: '$2885', + size: 'Large', + color: 'Orange', + }, + { + id: '2564', + quantity: 19, + price: '$1,209', + size: 'Small', + color: 'Red', + disabled: true, + }, + { + id: '2563', + quantity: 22, + price: '$1,400', + size: 'Small', + color: 'Green', + }, ]; - const disabled = products.every(({disabled}) => disabled); - - return ( - - - - - {color} - - - - - - {products.map( - ({id, size, quantity, price, position, disabled}, rowIndex) => { - return ( - - - - {size} - - - - - {price} - - - - - {quantity} - - - - ); - }, - )} - - ); - }); + const columnHeadings = [ + {title: 'Image', id: 'column-header--image'}, + {title: 'Name', id: 'column-header--size'}, + { + hidden: false, + id: 'column-header--price', + title: 'Price', + }, + { + alignment: 'end', + id: 'column-header--quantity', + title: 'Available', + }, + ]; - return ( - - string) => { + let position = -1; + const groups = rows.reduce((groups, product) => { + const groupVal = product[groupKey]; + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + products: [], + id: resolveId(groupVal), + }; } - resourceName={resourceName} - itemCount={rows.length} - headings={columnHeadings as IndexTableProps['headings']} - > - {rowMarkup} - - - ); -} - -export function WithNestedRowsStickyLastColumn() { - const rows = [ - { - id: '3411', - quantity: 11, - price: '$2,400', - size: 'Small Lorem ipsum dolor sit amet', - color: 'Orange Lorem ipsum dolor sit amet', - vendor: 'Fit Lines', - channel: 'Point of Sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - }, - { - id: '2562', - quantity: 30, - price: '$975', - size: 'Medium', - color: 'Orange', - vendor: 'Fit Lines', - channel: 'Point of Sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - }, - { - id: '4102', - quantity: 27, - price: '$2885', - size: 'Large', - color: 'Orange', - vendor: 'Fit Lines', - channel: 'Point of Sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - }, - { - id: '2564', - quantity: 19, - price: '$1,209', - size: 'Small', - color: 'Red', - disabled: true, - vendor: 'Fit Lines', - channel: 'Point of Sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - }, - { - id: '2563', - quantity: 22, - price: '$1,400', - size: 'Small', - color: 'Green', - vendor: 'Fit Lines', - channel: 'Point of Sale', - paymentStatus: 'Refunded', - fulfillmentStatus: 'Fulfilled', - }, - ]; - - const columnHeadings = [ - {title: 'Name', id: 'column-header--size'}, - { - hidden: false, - id: 'column-header--price', - title: 'Price', - }, - { - alignment: 'end', - id: 'column-header--quantity', - title: 'Available', - }, - { - alignment: 'end', - id: 'column-header--vendor', - title: 'Vendor', - }, - { - alignment: 'end', - id: 'column-header--channel', - title: 'Channel', - }, - { - alignment: 'end', - id: 'column-header--paymentStatus', - title: 'Status', - }, - { - alignment: 'end', - id: 'column-header--fulfillmentStatus', - title: 'Fulfillment Status', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, product) => { - const groupVal = product[groupKey]; - if (!groups[groupVal]) { - position += 1; + groups[groupVal].products.push({ + ...product, + position: position + 1, + }); - groups[groupVal] = { - position, - products: [], - id: resolveId(groupVal), - }; - } - groups[groupVal].products.push({ - ...product, - position: position + 1, - }); + position += 1; + return groups; + }, {}); - position += 1; return groups; - }, {}); - - return groups; - }; - - const resourceName = { - singular: 'product', - plural: 'products', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + }; - const groupedProducts = groupRowsBy( - 'color', - (color) => `color--${color.toLowerCase()}`, - ); + const resourceName = { + singular: 'product', + plural: 'products', + }; - const rowMarkup = Object.keys(groupedProducts).map((color, index) => { - const {products, position, id: subheaderId} = groupedProducts[color]; - let selected: IndexTableRowProps['selected'] = false; + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - const someProductsSelected = products.some(({id}) => - selectedResources.includes(id), + const groupedProducts = groupRowsBy( + 'color', + (color) => `color--${color.toLowerCase()}`, ); - const allProductsSelected = products.every(({id}) => - selectedResources.includes(id), - ); + const rowMarkup = Object.keys(groupedProducts).map((color, index) => { + const {products, position, id: subheaderId} = groupedProducts[color]; + let selected: IndexTableRowProps['selected'] = false; - if (allProductsSelected) { - selected = true; - } else if (someProductsSelected) { - selected = 'indeterminate'; - } + const someProductsSelected = products.some(({id}) => + selectedResources.includes(id), + ); - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === products[0].id), - selectableRows.findIndex( - (row) => row.id === products[products.length - 1].id, - ), - ]; + const allProductsSelected = products.every(({id}) => + selectedResources.includes(id), + ); + + if (allProductsSelected) { + selected = true; + } else if (someProductsSelected) { + selected = 'indeterminate'; + } - const disabled = products.every(({disabled}) => disabled); + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === products[0].id), + selectableRows.findIndex( + (row) => row.id === products[products.length - 1].id, + ), + ]; + + const disabled = products.every(({disabled}) => disabled); + + return ( + + + + + + + + {color} + + + + + + {products.map( + ({id, size, quantity, price, position, disabled}, rowIndex) => { + return ( + + + + + + + {size} + + + + + {price} + + + + + {quantity} + + + + ); + }, + )} + + ); + }); return ( - - + - - - {color} - - - - - - - - - - {products.map( - ( - { - id, - size, - quantity, - price, - position, - disabled, - vendor, - channel, - paymentStatus, - fulfillmentStatus, - }, - rowIndex, - ) => { - return ( - - - - {size} - - - - - {price} - - - - - {quantity} - - - - - {vendor} - - - - - {channel} - - - - - {paymentStatus} - - - - - {fulfillmentStatus} - - - - ); - }, - )} - + {rowMarkup} + + ); - }); + }, +}; - return ( - - string) => { + let position = -1; + const groups = rows.reduce((groups, product) => { + const groupVal = product[groupKey]; + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + products: [], + id: resolveId(groupVal), + }; } - resourceName={resourceName} - itemCount={rows.length} - headings={columnHeadings as IndexTableProps['headings']} - lastColumnSticky - > - {rowMarkup} - - - ); -} - -export function WithNestedRowsNonSelectable() { - const rows = [ - { - id: '3411', - quantity: 11, - price: '$2,400', - size: 'Small Lorem ipsum dolor sit amet', - color: 'Orange Lorem ipsum dolor sit amet', - }, - { - id: '2562', - quantity: 30, - price: '$975', - size: 'Medium', - color: 'Orange', - }, - { - id: '4102', - quantity: 27, - price: '$2885', - size: 'Large', - color: 'Orange', - }, - { - id: '2564', - quantity: 19, - price: '$1,209', - size: 'Small', - color: 'Red', - disabled: true, - }, - { - id: '2563', - quantity: 22, - price: '$1,400', - size: 'Small', - color: 'Green', - }, - ]; - - const columnHeadings = [ - {title: 'Name', id: 'column-header--size'}, - { - hidden: false, - id: 'column-header--price', - title: 'Price', - }, - { - alignment: 'end', - id: 'column-header--quantity', - title: 'Available', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, product) => { - const groupVal = product[groupKey]; - - if (!groups[groupVal]) { + groups[groupVal].products.push({ + ...product, + position: position + 1, + }); + position += 1; + return groups; + }, {}); - groups[groupVal] = { - position, - products: [], - id: resolveId(groupVal), - }; - } + return groups; + }; - groups[groupVal].products.push({ - ...product, - position: position + 1, - }); + const resourceName = { + singular: 'product', + plural: 'products', + }; - position += 1; - return groups; - }, {}); + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - return groups; - }; + const groupedProducts = groupRowsBy( + 'color', + (color) => `color--${color.toLowerCase()}`, + ); - const resourceName = { - singular: 'product', - plural: 'products', - }; + const rowMarkup = Object.keys(groupedProducts).map((color, index) => { + const {products, position, id: subheaderId} = groupedProducts[color]; + let selected: IndexTableRowProps['selected'] = false; - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + const someProductsSelected = products.some(({id}) => + selectedResources.includes(id), + ); - const groupedProducts = groupRowsBy( - 'color', - (color) => `color--${color.toLowerCase()}`, - ); + const allProductsSelected = products.every(({id}) => + selectedResources.includes(id), + ); - const rowMarkup = Object.keys(groupedProducts).map((color, index) => { - const {products, position, id: subheaderId} = groupedProducts[color]; - let selected: IndexTableRowProps['selected'] = false; + if (allProductsSelected) { + selected = true; + } else if (someProductsSelected) { + selected = 'indeterminate'; + } - const someProductsSelected = products.some(({id}) => - selectedResources.includes(id), - ); + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === products[0].id), + selectableRows.findIndex( + (row) => row.id === products[products.length - 1].id, + ), + ]; + + const disabled = products.every(({disabled}) => disabled); + + return ( + + + + + + + + {color} + + + + + + {products.map( + ({id, size, quantity, price, position, disabled}, rowIndex) => { + return ( + + + + + + + {size} + + + + + {price} + + + + + {quantity} + + + + ); + }, + )} + + ); + }); - const allProductsSelected = products.every(({id}) => - selectedResources.includes(id), + return ( + + + {rowMarkup} + + ); + }, +}; - if (allProductsSelected) { - selected = true; - } else if (someProductsSelected) { - selected = 'indeterminate'; - } +export const WithNestedRowsWithThumbnailsOneCellSelectable = { + render() { + const rows = [ + { + id: '3411', + quantity: 11, + price: '$2,400', + size: 'Small Lorem ipsum dolor sit amet', + color: 'Orange Lorem ipsum dolor sit amet', + }, + { + id: '2562', + quantity: 30, + price: '$975', + size: 'Medium', + color: 'Orange', + }, + { + id: '4102', + quantity: 27, + price: '$2885', + size: 'Large', + color: 'Orange', + }, + { + id: '2564', + quantity: 19, + price: '$1,209', + size: 'Small', + color: 'Red', + disabled: true, + }, + { + id: '2563', + quantity: 22, + price: '$1,400', + size: 'Small', + color: 'Green', + }, + ]; - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === products[0].id), - selectableRows.findIndex( - (row) => row.id === products[products.length - 1].id, - ), + const columnHeadings = [ + {title: 'Name', id: 'column-header--size'}, + { + hidden: false, + id: 'column-header--price', + title: 'Price', + }, + { + alignment: 'end', + id: 'column-header--quantity', + title: 'Available', + }, ]; - const disabled = products.every(({disabled}) => disabled); + const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { + let position = -1; + const groups = rows.reduce((groups, product) => { + const groupVal = product[groupKey]; - return ( - - - - - {color} - - - - - - {products.map( - ({id, size, quantity, price, position, disabled}, rowIndex) => { - return ( - - - - {size} - - - - - {price} - - - - - {quantity} - - - - ); - }, - )} - - ); - }); + if (!groups[groupVal]) { + position += 1; - return ( - - - {rowMarkup} - - - ); -} - -export function WithNestedRowsWithThumbnails() { - const rows = [ - { - id: '3411', - quantity: 11, - price: '$2,400', - size: 'Small Lorem ipsum dolor sit amet', - color: 'Orange Lorem ipsum dolor sit amet', - }, - { - id: '2562', - quantity: 30, - price: '$975', - size: 'Medium', - color: 'Orange', - }, - { - id: '4102', - quantity: 27, - price: '$2885', - size: 'Large', - color: 'Orange', - }, - { - id: '2564', - quantity: 19, - price: '$1,209', - size: 'Small', - color: 'Red', - disabled: true, - }, - { - id: '2563', - quantity: 22, - price: '$1,400', - size: 'Small', - color: 'Green', - }, - ]; - - const columnHeadings = [ - {title: 'Image', id: 'column-header--image'}, - {title: 'Name', id: 'column-header--size'}, - { - hidden: false, - id: 'column-header--price', - title: 'Price', - }, - { - alignment: 'end', - id: 'column-header--quantity', - title: 'Available', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, product) => { - const groupVal = product[groupKey]; - if (!groups[groupVal]) { - position += 1; - - groups[groupVal] = { - position, - products: [], - id: resolveId(groupVal), - }; - } - groups[groupVal].products.push({ - ...product, - position: position + 1, - }); - - position += 1; - return groups; - }, {}); - return groups; - }; + groups[groupVal].products.push({ + ...product, + position: position + 1, + }); - const resourceName = { - singular: 'product', - plural: 'products', - }; + position += 1; + return groups; + }, {}); - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + return groups; + }; - const groupedProducts = groupRowsBy( - 'color', - (color) => `color--${color.toLowerCase()}`, - ); + const resourceName = { + singular: 'product', + plural: 'products', + }; - const rowMarkup = Object.keys(groupedProducts).map((color, index) => { - const {products, position, id: subheaderId} = groupedProducts[color]; - let selected: IndexTableRowProps['selected'] = false; + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - const someProductsSelected = products.some(({id}) => - selectedResources.includes(id), + const groupedProducts = groupRowsBy( + 'color', + (color) => `color--${color.toLowerCase()}`, ); - const allProductsSelected = products.every(({id}) => - selectedResources.includes(id), - ); + const rowMarkup = Object.keys(groupedProducts).map((color, index) => { + const {products, position, id: subheaderId} = groupedProducts[color]; + let selected: IndexTableRowProps['selected'] = false; - if (allProductsSelected) { - selected = true; - } else if (someProductsSelected) { - selected = 'indeterminate'; - } + const someProductsSelected = products.some(({id}) => + selectedResources.includes(id), + ); - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === products[0].id), - selectableRows.findIndex( - (row) => row.id === products[products.length - 1].id, - ), - ]; + const allProductsSelected = products.every(({id}) => + selectedResources.includes(id), + ); + + if (allProductsSelected) { + selected = true; + } else if (someProductsSelected) { + selected = 'indeterminate'; + } - const disabled = products.every(({disabled}) => disabled); + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === products[0].id), + selectableRows.findIndex( + (row) => row.id === products[products.length - 1].id, + ), + ]; + + const disabled = products.every(({disabled}) => disabled); + + return ( + + + + + + + {color} + + + + + + + {products.map( + ({id, size, quantity, price, position, disabled}, rowIndex) => { + return ( + + + + + + + {size} + + + + + + + {price} + + + + + {quantity} + + + + ); + }, + )} + + ); + }); return ( - - + - - - - - - {color} - - - - - - {products.map( - ({id, size, quantity, price, position, disabled}, rowIndex) => { - return ( - - - - - - - {size} - - - - - {price} - - - - - {quantity} - - - - ); - }, - )} - + {rowMarkup} + + ); - }); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithNestedRowsWithThumbnailsNonSelectable() { - const rows = [ - { - id: '3411', - quantity: 11, - price: '$2,400', - size: 'Small Lorem ipsum dolor sit amet', - color: 'Orange Lorem ipsum dolor sit amet', - }, - { - id: '2562', - quantity: 30, - price: '$975', - size: 'Medium', - color: 'Orange', - }, - { - id: '4102', - quantity: 27, - price: '$2885', - size: 'Large', - color: 'Orange', - }, - { - id: '2564', - quantity: 19, - price: '$1,209', - size: 'Small', - color: 'Red', - disabled: true, - }, - { - id: '2563', - quantity: 22, - price: '$1,400', - size: 'Small', - color: 'Green', - }, - ]; - - const columnHeadings = [ - {title: 'Image', id: 'column-header--image'}, - {title: 'Name', id: 'column-header--size'}, - { - hidden: false, - id: 'column-header--price', - title: 'Price', - }, - { - alignment: 'end', - id: 'column-header--quantity', - title: 'Available', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, product) => { - const groupVal = product[groupKey]; - if (!groups[groupVal]) { - position += 1; + }, +}; - groups[groupVal] = { - position, - products: [], - id: resolveId(groupVal), - }; - } - groups[groupVal].products.push({ - ...product, - position: position + 1, - }); +export const WithNestedRowsWithThumbnailsOneCellNonSelectable = { + render() { + const rows = [ + { + id: '3411', + quantity: 11, + price: '$2,400', + size: 'Small Lorem ipsum dolor sit amet', + color: 'Orange Lorem ipsum dolor sit amet', + }, + { + id: '2562', + quantity: 30, + price: '$975', + size: 'Medium', + color: 'Orange', + }, + { + id: '4102', + quantity: 27, + price: '$2885', + size: 'Large', + color: 'Orange', + }, + { + id: '2564', + quantity: 19, + price: '$1,209', + size: 'Small', + color: 'Red', + disabled: true, + }, + { + id: '2563', + quantity: 22, + price: '$1,400', + size: 'Small', + color: 'Green', + }, + ]; - position += 1; - return groups; - }, {}); + const columnHeadings = [ + {title: 'Name', id: 'column-header--size'}, + { + hidden: false, + id: 'column-header--price', + title: 'Price', + }, + { + alignment: 'end', + id: 'column-header--quantity', + title: 'Available', + }, + ]; - return groups; - }; + const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { + let position = -1; + const groups = rows.reduce((groups, product) => { + const groupVal = product[groupKey]; + if (!groups[groupVal]) { + position += 1; + + groups[groupVal] = { + position, + products: [], + id: resolveId(groupVal), + }; + } + groups[groupVal].products.push({ + ...product, + position: position + 1, + }); - const resourceName = { - singular: 'product', - plural: 'products', - }; + position += 1; + return groups; + }, {}); - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + return groups; + }; - const groupedProducts = groupRowsBy( - 'color', - (color) => `color--${color.toLowerCase()}`, - ); + const resourceName = { + singular: 'product', + plural: 'products', + }; - const rowMarkup = Object.keys(groupedProducts).map((color, index) => { - const {products, position, id: subheaderId} = groupedProducts[color]; - let selected: IndexTableRowProps['selected'] = false; + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - const someProductsSelected = products.some(({id}) => - selectedResources.includes(id), + const groupedProducts = groupRowsBy( + 'color', + (color) => `color--${color.toLowerCase()}`, ); - const allProductsSelected = products.every(({id}) => - selectedResources.includes(id), - ); + const rowMarkup = Object.keys(groupedProducts).map((color, index) => { + const {products, position, id: subheaderId} = groupedProducts[color]; + let selected: IndexTableRowProps['selected'] = false; - if (allProductsSelected) { - selected = true; - } else if (someProductsSelected) { - selected = 'indeterminate'; - } + const someProductsSelected = products.some(({id}) => + selectedResources.includes(id), + ); - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === products[0].id), - selectableRows.findIndex( - (row) => row.id === products[products.length - 1].id, - ), - ]; + const allProductsSelected = products.every(({id}) => + selectedResources.includes(id), + ); + + if (allProductsSelected) { + selected = true; + } else if (someProductsSelected) { + selected = 'indeterminate'; + } - const disabled = products.every(({disabled}) => disabled); + const selectableRows = rows.filter(({disabled}) => !disabled); + const rowRange: IndexTableRowProps['selectionRange'] = [ + selectableRows.findIndex((row) => row.id === products[0].id), + selectableRows.findIndex( + (row) => row.id === products[products.length - 1].id, + ), + ]; + + const disabled = products.every(({disabled}) => disabled); + + return ( + + + + + + + {color} + + + + + + + {products.map( + ({id, size, quantity, price, position, disabled}, rowIndex) => { + return ( + + + + + + + {size} + + + + + + + {price} + + + + + {quantity} + + + + ); + }, + )} + + ); + }); return ( - - + + {rowMarkup} + + + ); + }, +}; + +export const WithLongDataSetNonSelectable = { + render() { + const orders = Array.from(Array(100).keys()).map((i) => ({ + id: `${i}`, + order: i, + date: 'Jul 20 at 4:34pm', + customer: 'Jaydon Stanton', + total: `$969.44${i}`, + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + })); + + const resourceName = { + singular: 'order', + plural: 'orders', + }; + + const rowMarkup = orders.map( + ( + {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + index, + ) => ( + - - - - - {color} + + {order} - - + {date} + {customer} + {total} + {paymentStatus} + {fulfillmentStatus} - {products.map( - ({id, size, quantity, price, position, disabled}, rowIndex) => { - return ( - - - - - - - {size} - - - - - {price} - - - - - {quantity} - - - - ); - }, - )} - - ); - }); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithNestedRowsWithThumbnailsOneCellSelectable() { - const rows = [ - { - id: '3411', - quantity: 11, - price: '$2,400', - size: 'Small Lorem ipsum dolor sit amet', - color: 'Orange Lorem ipsum dolor sit amet', - }, - { - id: '2562', - quantity: 30, - price: '$975', - size: 'Medium', - color: 'Orange', - }, - { - id: '4102', - quantity: 27, - price: '$2885', - size: 'Large', - color: 'Orange', - }, - { - id: '2564', - quantity: 19, - price: '$1,209', - size: 'Small', - color: 'Red', - disabled: true, - }, - { - id: '2563', - quantity: 22, - price: '$1,400', - size: 'Small', - color: 'Green', - }, - ]; - - const columnHeadings = [ - {title: 'Name', id: 'column-header--size'}, - { - hidden: false, - id: 'column-header--price', - title: 'Price', - }, - { - alignment: 'end', - id: 'column-header--quantity', - title: 'Available', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, product) => { - const groupVal = product[groupKey]; - - if (!groups[groupVal]) { - position += 1; - - groups[groupVal] = { - position, - products: [], - id: resolveId(groupVal), - }; - } - - groups[groupVal].products.push({ - ...product, - position: position + 1, - }); - - position += 1; - return groups; - }, {}); - - return groups; - }; - - const resourceName = { - singular: 'product', - plural: 'products', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); - - const groupedProducts = groupRowsBy( - 'color', - (color) => `color--${color.toLowerCase()}`, - ); - - const rowMarkup = Object.keys(groupedProducts).map((color, index) => { - const {products, position, id: subheaderId} = groupedProducts[color]; - let selected: IndexTableRowProps['selected'] = false; - - const someProductsSelected = products.some(({id}) => - selectedResources.includes(id), + ), ); - const allProductsSelected = products.every(({id}) => - selectedResources.includes(id), + return ( + + + {rowMarkup} + + ); + }, +}; + +export const WithLongDataSetSelectable = { + render() { + const orders = Array.from(Array(100).keys()).map((i) => ({ + id: `${i}`, + order: i, + date: 'Jul 20 at 4:34pm', + customer: 'Jaydon Stanton', + total: `$969.44${i}`, + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + })); - if (allProductsSelected) { - selected = true; - } else if (someProductsSelected) { - selected = 'indeterminate'; - } - - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === products[0].id), - selectableRows.findIndex( - (row) => row.id === products[products.length - 1].id, - ), - ]; + const resourceName = { + singular: 'order', + plural: 'orders', + }; - const disabled = products.every(({disabled}) => disabled); + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(orders); - return ( - + const rowMarkup = orders.map( + ( + {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + index, + ) => ( - - - - {color} - - + + {order} + - - + {date} + {customer} + {total} + {paymentStatus} + {fulfillmentStatus} - {products.map( - ({id, size, quantity, price, position, disabled}, rowIndex) => { - return ( - - - - - - - {size} - - - - - - - {price} - - - - - {quantity} - - - - ); - }, - )} - + ), ); - }); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithNestedRowsWithThumbnailsOneCellNonSelectable() { - const rows = [ - { - id: '3411', - quantity: 11, - price: '$2,400', - size: 'Small Lorem ipsum dolor sit amet', - color: 'Orange Lorem ipsum dolor sit amet', - }, - { - id: '2562', - quantity: 30, - price: '$975', - size: 'Medium', - color: 'Orange', - }, - { - id: '4102', - quantity: 27, - price: '$2885', - size: 'Large', - color: 'Orange', - }, - { - id: '2564', - quantity: 19, - price: '$1,209', - size: 'Small', - color: 'Red', - disabled: true, - }, - { - id: '2563', - quantity: 22, - price: '$1,400', - size: 'Small', - color: 'Green', - }, - ]; - - const columnHeadings = [ - {title: 'Name', id: 'column-header--size'}, - { - hidden: false, - id: 'column-header--price', - title: 'Price', - }, - { - alignment: 'end', - id: 'column-header--quantity', - title: 'Available', - }, - ]; - - const groupRowsBy = (groupKey: string, resolveId: (groupVal) => string) => { - let position = -1; - const groups = rows.reduce((groups, product) => { - const groupVal = product[groupKey]; - if (!groups[groupVal]) { - position += 1; - - groups[groupVal] = { - position, - products: [], - id: resolveId(groupVal), - }; - } - groups[groupVal].products.push({ - ...product, - position: position + 1, - }); - - position += 1; - return groups; - }, {}); - return groups; - }; - - const resourceName = { - singular: 'product', - plural: 'products', - }; + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(rows, {resourceFilter: ({disabled}) => !disabled}); + return ( + + + {rowMarkup} + + + ); + }, +}; - const groupedProducts = groupRowsBy( - 'color', - (color) => `color--${color.toLowerCase()}`, - ); +export const WithinAModal = { + render() { + const [active, setActive] = useState(true); + const [checked, setChecked] = useState(false); - const rowMarkup = Object.keys(groupedProducts).map((color, index) => { - const {products, position, id: subheaderId} = groupedProducts[color]; - let selected: IndexTableRowProps['selected'] = false; + const toggleActive = useCallback(() => setActive((active) => !active), []); - const someProductsSelected = products.some(({id}) => - selectedResources.includes(id), - ); + const handleCheckbox = useCallback((value) => setChecked(value), []); - const allProductsSelected = products.every(({id}) => - selectedResources.includes(id), - ); + const activator = ; - if (allProductsSelected) { - selected = true; - } else if (someProductsSelected) { - selected = 'indeterminate'; - } + const orders = Array.from(Array(100).keys()).map((i) => ({ + id: `${i}`, + order: i, + date: 'Jul 20 at 4:34pm', + customer: 'Jaydon Stanton', + total: `$969.44${i}`, + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + })); - const selectableRows = rows.filter(({disabled}) => !disabled); - const rowRange: IndexTableRowProps['selectionRange'] = [ - selectableRows.findIndex((row) => row.id === products[0].id), - selectableRows.findIndex( - (row) => row.id === products[products.length - 1].id, - ), - ]; + const resourceName = { + singular: 'order', + plural: 'orders', + }; - const disabled = products.every(({disabled}) => disabled); + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(orders); - return ( - + const rowMarkup = orders.map( + ( + {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + index, + ) => ( - - - - {color} - - + + {order} + - - + {date} + {customer} + {total} + {paymentStatus} + {fulfillmentStatus} - {products.map( - ({id, size, quantity, price, position, disabled}, rowIndex) => { - return ( - - - - - - - {size} - - - - - - - {price} - - - - - {quantity} - - - - ); - }, - )} - + ), ); - }); - return ( - - - {rowMarkup} - - - ); -} - -export function WithLongDataSetNonSelectable() { - const orders = Array.from(Array(100).keys()).map((i) => ({ - id: `${i}`, - order: i, - date: 'Jul 20 at 4:34pm', - customer: 'Jaydon Stanton', - total: `$969.44${i}`, - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - })); - - const resourceName = { - singular: 'order', - plural: 'orders', - }; - - const rowMarkup = orders.map( - ( - {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, - index, - ) => ( - - - - {order} - - - {date} - {customer} - {total} - {paymentStatus} - {fulfillmentStatus} - - ), - ); - - return ( - - - {rowMarkup} - - - ); -} - -export function WithLongDataSetSelectable() { - const orders = Array.from(Array(100).keys()).map((i) => ({ - id: `${i}`, - order: i, - date: 'Jul 20 at 4:34pm', - customer: 'Jaydon Stanton', - total: `$969.44${i}`, - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - })); - - const resourceName = { - singular: 'order', - plural: 'orders', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(orders); - - const rowMarkup = orders.map( - ( - {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, - index, - ) => ( - - - - {order} - - - {date} - {customer} - {total} - {paymentStatus} - {fulfillmentStatus} - - ), - ); - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - return ( - + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + const table = ( {rowMarkup} - - ); -} - -export function WithinAModal() { - const [active, setActive] = useState(true); - const [checked, setChecked] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const handleCheckbox = useCallback((value) => setChecked(value), []); - - const activator = ; - - const orders = Array.from(Array(100).keys()).map((i) => ({ - id: `${i}`, - order: i, - date: 'Jul 20 at 4:34pm', - customer: 'Jaydon Stanton', - total: `$969.44${i}`, - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - })); - - const resourceName = { - singular: 'order', - plural: 'orders', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(orders); - - const rowMarkup = orders.map( - ( - {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, - index, - ) => ( - - - - {order} - - - {date} - {customer} - {total} - {paymentStatus} - {fulfillmentStatus} - - ), - ); - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - const table = ( - - {rowMarkup} - - ); - - return ( - -
- +
+ - - {table} - - -
- - ); -} - -export function WithUnmountingTable() { - const [isShowing, setIsShowing] = useState(true); - const orders = [ - { - id: '1020', - order: '#1020', - date: 'Jul 20 at 4:34pm', - customer: 'Jaydon Stanton', - total: '$969.44', - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - }, - { - id: '1019', - order: '#1019', - date: 'Jul 20 at 3:46pm', - customer: 'Ruben Westerfelt', - total: '$701.19', - paymentStatus: Partially paid, - fulfillmentStatus: Unfulfilled, - }, - { - id: '1018', - order: '#1018', - date: 'Jul 20 at 3.44pm', - customer: 'Leo Carder', - total: '$798.24', - paymentStatus: Paid, - fulfillmentStatus: Unfulfilled, - }, - ]; - const resourceName = { - singular: 'order', - plural: 'orders', - }; - - const {selectedResources, allResourcesSelected, handleSelectionChange} = - useIndexResourceState(orders); - - const rowMarkup = orders.map( - ( - {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, - index, - ) => ( - - - - {order} - - - {date} - {customer} - - - {total} - - - {paymentStatus} - {fulfillmentStatus} - - ), - ); - - return ( - <> - {isShowing && ( - - - {rowMarkup} - - - )} - - - ); -} + + {table} + +
+
+ + ); + }, +}; + +export const WithUnmountingTable = { + render() { + const [isShowing, setIsShowing] = useState(true); + const orders = [ + { + id: '1020', + order: '#1020', + date: 'Jul 20 at 4:34pm', + customer: 'Jaydon Stanton', + total: '$969.44', + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + }, + { + id: '1019', + order: '#1019', + date: 'Jul 20 at 3:46pm', + customer: 'Ruben Westerfelt', + total: '$701.19', + paymentStatus: ( + Partially paid + ), + fulfillmentStatus: Unfulfilled, + }, + { + id: '1018', + order: '#1018', + date: 'Jul 20 at 3.44pm', + customer: 'Leo Carder', + total: '$798.24', + paymentStatus: Paid, + fulfillmentStatus: Unfulfilled, + }, + ]; + const resourceName = { + singular: 'order', + plural: 'orders', + }; + + const {selectedResources, allResourcesSelected, handleSelectionChange} = + useIndexResourceState(orders); + + const rowMarkup = orders.map( + ( + {id, order, date, customer, total, paymentStatus, fulfillmentStatus}, + index, + ) => ( + + + + {order} + + + {date} + {customer} + + + {total} + + + {paymentStatus} + {fulfillmentStatus} + + ), + ); + + return ( + <> + {isShowing && ( + + + {rowMarkup} + + + )} + + + ); + }, +}; diff --git a/polaris-react/src/components/InlineError/InlineError.stories.tsx b/polaris-react/src/components/InlineError/InlineError.stories.tsx index 879db4bfb38..7a15d064446 100644 --- a/polaris-react/src/components/InlineError/InlineError.stories.tsx +++ b/polaris-react/src/components/InlineError/InlineError.stories.tsx @@ -1,11 +1,13 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {InlineError} from '@shopify/polaris'; export default { component: InlineError, -} as ComponentMeta; +} as Meta; -export function Default() { - return ; -} +export const Default = { + render() { + return ; + }, +}; diff --git a/polaris-react/src/components/InlineGrid/InlineGrid.stories.tsx b/polaris-react/src/components/InlineGrid/InlineGrid.stories.tsx index ea6fa33a3b2..b354d0d7ab8 100644 --- a/polaris-react/src/components/InlineGrid/InlineGrid.stories.tsx +++ b/polaris-react/src/components/InlineGrid/InlineGrid.stories.tsx @@ -1,129 +1,145 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Button, InlineGrid, Page} from '@shopify/polaris'; import {ChevronLeftIcon, ChevronRightIcon} from '@shopify/polaris-icons'; export default { component: InlineGrid, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - -
one
-
two
-
three
-
four
-
five
-
six
-
-
- ); -} +export const Default = { + render() { + return ( + + +
one
+
two
+
three
+
four
+
five
+
six
+
+
+ ); + }, +}; -export function WithTemplateInlineGrid() { - return ( - - -
Column one
-
Column two
-
Column three
-
Column four
-
Column five
-
Column six
-
-
- ); -} +export const WithTemplateInlineGrid = { + render() { + return ( + + +
Column one
+
Column two
+
Column three
+
Column four
+
Column five
+
Column six
+
+
+ ); + }, +}; -export function WithMixedPropTypes() { - return ( - - -
one
-
two
-
three
-
four
-
five
-
six
-
-
- ); -} +export const WithMixedPropTypes = { + render() { + return ( + + +
one
+
two
+
three
+
four
+
five
+
six
+
+
+ ); + }, +}; -export function WithGap() { - return ( - - -
Column one
-
Column two
-
Column three
-
-
- ); -} +export const WithGap = { + render() { + return ( + + +
Column one
+
Column two
+
Column three
+
+
+ ); + }, +}; -export function WithResponsiveGap() { - return ( - - -
Column one
-
Column two
-
Column three
-
-
- ); -} +export const WithResponsiveGap = { + render() { + return ( + + +
Column one
+
Column two
+
Column three
+
+
+ ); + }, +}; -export function WithFreeAndFixedWidths() { - return ( - - -
Column one
-
-
-
-
-
-
- ); -} +export const WithFreeAndFixedWidths = { + render() { + return ( + + +
Column one
+
+
+
+
+
+
+ ); + }, +}; -export function WithResponsiveInlineGrid() { - return ( - - -
Column one
-
Column two
-
Column three
-
-
- ); -} +export const WithResponsiveInlineGrid = { + render() { + return ( + + +
Column one
+
Column two
+
Column three
+
+
+ ); + }, +}; -export function WithResponsiveColumnAlisases() { - return ( - - -
Column one
-
Column two
-
-
- ); -} +export const WithResponsiveColumnAlisases = { + render() { + return ( + + +
Column one
+
Column two
+
+
+ ); + }, +}; diff --git a/polaris-react/src/components/InlineStack/InlineStack.stories.tsx b/polaris-react/src/components/InlineStack/InlineStack.stories.tsx index 76b81ddf49b..113600a4698 100644 --- a/polaris-react/src/components/InlineStack/InlineStack.stories.tsx +++ b/polaris-react/src/components/InlineStack/InlineStack.stories.tsx @@ -1,203 +1,239 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Box, Badge, Icon, InlineStack, Thumbnail} from '@shopify/polaris'; import {FlowerIcon, ImageIcon} from '@shopify/polaris-icons'; export default { component: InlineStack, -} as ComponentMeta; - -export function Default() { - return ( - - One - Two - Three - - - - - ); -} - -export function WithAlignStart() { - return ( - - - One - Two - Three - - ); -} - -export function WithAlignCenter() { - return ( - - - One - Two - Three - - ); -} - -export function WithAlignEnd() { - return ( - - - One - Two - Three - - ); -} - -export function WithAlignSpaceAround() { - return ( - - One - Two - Three - - ); -} - -export function WithAlignSpaceBetween() { - return ( - - One - Two - Three - - ); -} - -export function WithAlignSpaceEvenly() { - return ( - - One - Two - Three - - ); -} - -export function WithBlockAlignStart() { - return ( - - - One - Two - Three - - ); -} - -export function WithBlockAlignCenter() { - return ( - - - One - Two - Three - - ); -} - -export function WithBlockAlignEnd() { - return ( - - - One - Two - Three - - ); -} - -export function WithBlockAlignBaseline() { - return ( - - - One - Two - Three - - ); -} - -export function WithBlockAlignStretch() { - return ( - - - One - Two - Three - - ); -} - -export function WithAlignCenterBlockAlignCenter() { - return ( - - - One - Two - Three - - ); -} - -export function WithNonWrapping() { - return ( - - Paid - Processing - Fulfilled - Completed - - ); -} - -export function WithGap() { - return ( - - Paid - Processing - Fulfilled - Completed - - ); -} - -export function WithResponsiveGap() { - return ( - - Paid - Processing - Fulfilled - Completed - - ); -} - -export function WithDirectionReversed() { - return ( - - One - Two - Three - - ); -} - -export function WithResponsiveDirectionReversed() { - return ( - - One - Two - Three - - ); -} +} as Meta; + +export const Default = { + render() { + return ( + + One + Two + Three + + + + + ); + }, +}; + +export const WithAlignStart = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithAlignCenter = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithAlignEnd = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithAlignSpaceAround = { + render() { + return ( + + One + Two + Three + + ); + }, +}; + +export const WithAlignSpaceBetween = { + render() { + return ( + + One + Two + Three + + ); + }, +}; + +export const WithAlignSpaceEvenly = { + render() { + return ( + + One + Two + Three + + ); + }, +}; + +export const WithBlockAlignStart = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithBlockAlignCenter = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithBlockAlignEnd = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithBlockAlignBaseline = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithBlockAlignStretch = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithAlignCenterBlockAlignCenter = { + render() { + return ( + + + One + Two + Three + + ); + }, +}; + +export const WithNonWrapping = { + render() { + return ( + + Paid + Processing + Fulfilled + Completed + + ); + }, +}; + +export const WithGap = { + render() { + return ( + + Paid + Processing + Fulfilled + Completed + + ); + }, +}; + +export const WithResponsiveGap = { + render() { + return ( + + Paid + Processing + Fulfilled + Completed + + ); + }, +}; + +export const WithDirectionReversed = { + render() { + return ( + + One + Two + Three + + ); + }, +}; + +export const WithResponsiveDirectionReversed = { + render() { + return ( + + One + Two + Three + + ); + }, +}; diff --git a/polaris-react/src/components/KeyboardKey/KeyboardKey.stories.tsx b/polaris-react/src/components/KeyboardKey/KeyboardKey.stories.tsx index e3b3f1b6499..ba745b20384 100644 --- a/polaris-react/src/components/KeyboardKey/KeyboardKey.stories.tsx +++ b/polaris-react/src/components/KeyboardKey/KeyboardKey.stories.tsx @@ -1,97 +1,103 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {KeyboardKey, Card, Text, BlockStack} from '@shopify/polaris'; export default { component: KeyboardKey, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - -
-
-
- - s -
-
- ctrl - s +export const Default = { + render() { + return ( + +
+
+
+ + s +
+
+ ctrl + s +
-
-
-
- - / -
-
- ctrl - / +
+
+ + / +
+
+ ctrl + / +
-
-
- ); -} + + ); + }, +}; -export function Small() { - return ( - -
-
-
- - d -
-
- - h -
-
- - -
-
-
-
- ctrl - d -
-
- ctrl - h +export const Small = { + render() { + return ( + +
+
+
+ + d +
+
+ + h +
+
+ + +
-
- ctrl - +
+
+ ctrl + d +
+
+ ctrl + h +
+
+ ctrl + +
-
-
- ); -} - -export function All() { - return ( - - - Default - - - ctrl - - h - - - Small - - - ctrl - - h - - ); -} + ); + }, +}; + +export const All = { + render() { + return ( + + + Default + + + ctrl + + h + + + Small + + + ctrl + + h + + + ); + }, +}; diff --git a/polaris-react/src/components/Layout/Layout.stories.tsx b/polaris-react/src/components/Layout/Layout.stories.tsx index e064c3d1051..574a2dec96d 100644 --- a/polaris-react/src/components/Layout/Layout.stories.tsx +++ b/polaris-react/src/components/Layout/Layout.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Banner, Box, @@ -16,483 +16,500 @@ import { export default { component: Layout, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - <> - - One column - - - +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + <> + + One column + + + - - Two columns with primary and secondary widths - - - + + Two columns with primary and secondary widths + + + - - Two columns with equal width - - - + + Two columns with equal width + + + - - Three columns with equal width - - - + + Three columns with equal width + + + - - Annotated - - - + + Annotated + + + - - Annotated with banner at the top - - - - - ); -} + + Annotated with banner at the top + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function OneColumn() { - return ( - - - - - - View a summary of your online store’s performance. - - - - - - ); -} - -export function TwoColumnsWithPrimaryAndSecondaryWidths() { - return ( - - - - - - Use to follow a normal section with a secondary section to create - a 2/3 + 1/3 layout on detail pages (such as individual product or - order pages). Can also be used on any page that needs to structure - a lot of content. This layout stacks the columns on small screens. - - - - - - - Add tags to your order. - - - - - - ); -} - -export function TwoColumnsWithEqualWidth() { - return ( - - - - - - - 455 units available +export const OneColumn = { + render() { + return ( + + + + + + View a summary of your online store’s performance. - - - - ), - }, - { - id: '256', - url: '#', - name: 'Tucan scarf', - sku: '9234194010', - quantity: '201', - media: ( - - ), - }, - ]} - renderItem={(item) => { - const {id, url, name, sku, media, quantity} = item; + + + + + ); + }, +}; - return ( - -

- - {name} - -

-
SKU: {sku}
-
{quantity} available
-
- ); - }} - /> - - - - - - - - 301 units available +export const TwoColumnsWithPrimaryAndSecondaryWidths = { + render() { + return ( + + + + + + Use to follow a normal section with a secondary section to + create a 2/3 + 1/3 layout on detail pages (such as individual + product or order pages). Can also be used on any page that needs + to structure a lot of content. This layout stacks the columns on + small screens. + + + + + + + Add tags to your order. - - - - ), - }, - { - id: '257', - url: '#', - name: 'Tucan scarf', - sku: '9234194010', - quantity: '201', - media: ( - - ), - }, - ]} - renderItem={(item) => { - const {id, url, name, sku, media, quantity} = item; + + + + + ); + }, +}; - return ( - -

- - {name} - -

-
SKU: {sku}
-
{quantity} available
-
- ); - }} - /> - - - - - - ); -} +export const TwoColumnsWithEqualWidth = { + render() { + return ( + + + + + + + 455 units available + + + + + ), + }, + { + id: '256', + url: '#', + name: 'Tucan scarf', + sku: '9234194010', + quantity: '201', + media: ( + + ), + }, + ]} + renderItem={(item) => { + const {id, url, name, sku, media, quantity} = item; -export function ThreeColumnsWithEqualWidth() { - return ( - - - - - - - 455 units available - - - - - ), - }, - { - id: '258', - url: '#', - name: 'Tucan scarf', - sku: '9234194010', - quantity: '201', - media: ( - - ), - }, - ]} - renderItem={(item) => { - const {id, url, name, sku, media, quantity} = item; + return ( + +

+ + {name} + +

+
SKU: {sku}
+
{quantity} available
+
+ ); + }} + /> +
+
+
+ + + + + 301 units available + + + + + ), + }, + { + id: '257', + url: '#', + name: 'Tucan scarf', + sku: '9234194010', + quantity: '201', + media: ( + + ), + }, + ]} + renderItem={(item) => { + const {id, url, name, sku, media, quantity} = item; - return ( - -

- - {name} - -

-
SKU: {sku}
-
{quantity} available
-
- ); - }} - /> -
-
-
- - - - - 301 units available - - - - - ), - }, - { - id: '259', - url: '#', - name: 'Tucan scarf', - sku: '9234194010', - quantity: '201', - media: ( - - ), - }, - ]} - renderItem={(item) => { - const {id, url, name, sku, media, quantity} = item; + return ( + +

+ + {name} + +

+
SKU: {sku}
+
{quantity} available
+
+ ); + }} + /> +
+
+
+
+
+ ); + }, +}; - return ( - -

- - {name} - -

-
SKU: {sku}
-
{quantity} available
-
- ); - }} - /> -
-
-
- - - - - 1931 units available - - - - - ), - }, - { - id: '260', - url: '#', - name: 'Tucan scarf', - sku: '9234194010', - quantity: '701', - media: ( - - ), - }, - ]} - renderItem={(item) => { - const {id, url, name, sku, media, quantity} = item; +export const ThreeColumnsWithEqualWidth = { + render() { + return ( + + + + + + + 455 units available + + + + + ), + }, + { + id: '258', + url: '#', + name: 'Tucan scarf', + sku: '9234194010', + quantity: '201', + media: ( + + ), + }, + ]} + renderItem={(item) => { + const {id, url, name, sku, media, quantity} = item; + + return ( + +

+ + {name} + +

+
SKU: {sku}
+
{quantity} available
+
+ ); + }} + /> +
+
+
+ + + + + 301 units available + + + + + ), + }, + { + id: '259', + url: '#', + name: 'Tucan scarf', + sku: '9234194010', + quantity: '201', + media: ( + + ), + }, + ]} + renderItem={(item) => { + const {id, url, name, sku, media, quantity} = item; - return ( - -

- - {name} - -

-
SKU: {sku}
-
{quantity} available
-
- ); - }} - /> -
-
-
-
-
- ); -} + return ( + +

+ + {name} + +

+
SKU: {sku}
+
{quantity} available
+
+ ); + }} + /> +
+
+
+ + + + + 1931 units available + + + + + ), + }, + { + id: '260', + url: '#', + name: 'Tucan scarf', + sku: '9234194010', + quantity: '701', + media: ( + + ), + }, + ]} + renderItem={(item) => { + const {id, url, name, sku, media, quantity} = item; -export function Annotated() { - return ( - - - - - - {}} - autoComplete="off" - /> - {}} - autoComplete="email" - /> - - - - - - ); -} + return ( + +

+ + {name} + +

+
SKU: {sku}
+
{quantity} available
+
+ ); + }} + /> +
+
+
+
+
+ ); + }, +}; -export function AnnotatedWithBannerAtTheTop() { - return ( - - - - {}}> - - This order was archived on March 7, 2017 at 3:12pm EDT. - - - - - - - {}} - autoComplete="off" - /> - {}} - autoComplete="email" - /> - - - - - - ); -} +export const Annotated = { + render() { + return ( + + + + + + {}} + autoComplete="off" + /> + {}} + autoComplete="email" + /> + + + + + + ); + }, +}; + +export const AnnotatedWithBannerAtTheTop = { + render() { + return ( + + + + {}}> + + This order was archived on March 7, 2017 at 3:12pm EDT. + + + + + + + {}} + autoComplete="off" + /> + {}} + autoComplete="email" + /> + + + + + + ); + }, +}; diff --git a/polaris-react/src/components/LegacyCard/LegacyCard.stories.tsx b/polaris-react/src/components/LegacyCard/LegacyCard.stories.tsx index d8ad4f4d2ad..12b3899ba02 100644 --- a/polaris-react/src/components/LegacyCard/LegacyCard.stories.tsx +++ b/polaris-react/src/components/LegacyCard/LegacyCard.stories.tsx @@ -1,6 +1,6 @@ import type {PropsWithChildren} from 'react'; import React, {useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { ActionList, Button, @@ -21,554 +21,596 @@ import {ProductIcon, XIcon} from '@shopify/polaris-icons'; export default { component: LegacyCard, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - - View a summary of your online store’s performance. - - - ); -} - -export function WithHeaderActions() { - return ( - - - Add variants if this product comes in multiple versions, like different - sizes or colors. - - - ); -} - -export function WithFooterActions() { - return ( - - - - 1 × Oasis Glass, 4-Pack - 1 × Anubis Cup, 2-Pack - - - - ); -} - -export function WithMultipleFooterActions() { - return ( - - - - 1 × Oasis Glass, 4-Pack - 1 × Anubis Cup, 2-Pack - - - - ); -} - -export function WithCustomFooterActions() { - return ( - - - - - Two-step authentication adds an extra layer of security when logging - in to your account. A special code will be required each time you - log in, ensuring only you can access your account. - - - - - - - - - - - ); -} - -export function WithDestructiveFooterAction() { - return ( - - - - 1 × Oasis Glass, 4-Pack - 1 × Anubis Cup, 2-Pack - - - - ); -} - -export function WithMultipleSections() { - return ( - - - - View a summary of your online store’s performance. - - - - - - View a summary of your online store’s performance, including sales, - visitors, top products, and referrals. - - - - ); -} - -export function WithMultipleTitledSections() { - return ( - - +export const Default = { + render() { + return ( + View a summary of your online store’s performance. - - - - - View a summary of your online store’s performance, including sales, - visitors, top products, and referrals. - - - - ); -} + + ); + }, +}; -export function WithSectionsAndActions() { - return ( - - - - John Smith - - - - john.smith@example.com - - - - ); -} - -export function WithSubsection() { - return ( - - - - John Smith + Add variants if this product comes in multiple versions, like + different sizes or colors. - - - - 123 First St -
- Somewhere -
- The Universe -
- - 123 Second St -
- Somewhere -
- The Universe -
-
- - - A single subsection without a sibling has no visual appearance - - -
- ); -} + + ); + }, +}; -export function WithDestructiveAction() { - return ( - - - - John Smith - - - - - john.smith@example.com - - - - ); -} - -export function WithASubduedSection() { - return ( - - - - Felix Crafford - Ezequiel Manno - - - - - - Felix Crafford - Ezequiel Manno - - - - ); -} - -export function WithSubduedForSecondaryContent() { - return ( - - - Felix Crafford - Ezequiel Manno - - - ); -} + + + 1 × Oasis Glass, 4-Pack + 1 × Anubis Cup, 2-Pack + + + + ); + }, +}; -export function WithSeparateHeader() { - return ( - - - - Add account - - } - onClose={() => {}} - > - - - - - - Felix Crafford - Ezequiel Manno - - - - ); -} + + + 1 × Oasis Glass, 4-Pack + 1 × Anubis Cup, 2-Pack + + + + ); + }, +}; -export function WithCustomReactNodeTitle() { - return ( - - - - - New Products +export const WithCustomFooterActions = { + render() { + return ( + + + + + Two-step authentication adds an extra layer of security when + logging in to your account. A special code will be required each + time you log in, ensuring only you can access your account. + + + + + + - } - > - - Socks - Super Shoes - - - - ); -} + + + ); + }, +}; -export function WithAllElements() { - return ( - - - - View Sales - - } - onClose={() => {}} - > - - - - - - You can use sales reports to see information about your customers’ - orders based on criteria such as sales over time, by channel, or by - staff. - - - - { - const {sales, amount, url} = item; - return ( - - - {sales} - {amount} - - - ); - }} - /> - - - - Payouts - Total Sales By Channel - - - - - The sales reports are available only if your store is on the Shopify - plan or higher. - - - - ); -} + + + 1 × Oasis Glass, 4-Pack + 1 × Anubis Cup, 2-Pack + + + + ); + }, +}; -export function WithFlushedSections() { - return ( - - - - - - - You can use sales reports to see information about your customers’ - orders based on criteria such as sales over time, by channel, or by - staff. - - - - ); -} +export const WithMultipleSections = { + render() { + return ( + + + + View a summary of your online store’s performance. + + -export function All() { - return ( - - - - Section 1 content + + + View a summary of your online store’s performance, including sales, + visitors, top products, and referrals. + + + + ); + }, +}; + +export const WithMultipleTitledSections = { + render() { + return ( + + + + View a summary of your online store’s performance. + - - Section 2 content + + + + View a summary of your online store’s performance, including sales, + visitors, top products, and referrals. + - + ); + }, +}; + +export const WithSectionsAndActions = { + render() { + return ( + - - Section 1 content - + + John Smith + - - Section 2 content + + + john.smith@example.com + - - No titles Section 1 content - No titles Section 2 content - - -
- - - Section 1 in div - - - Section 2 in div - -
-
- -
- - Section 1 in div - - - Section 2 in div - -
-
- -
-

Custom header in an h2

-
- Section 1 content - Section 2 content -
+ ); + }, +}; + +export const WithSubsection = { + render() { + return ( + + - Custom footer in a p + John Smith -
-
- -
- - Section 1 content wrapped in its own div - -
-
- - Section 2 content wrapped in its own div - -
+ + + + 123 First St +
+ Somewhere +
+ The Universe +
+ + 123 Second St +
+ Somewhere +
+ The Universe +
+
+ + + A single subsection without a sibling has no visual appearance + +
- -
Card content in div not in section
+ ); + }, +}; + +export const WithDestructiveAction = { + render() { + return ( + + + + John Smith + + + + + john.smith@example.com + + - - - Subdued Section 1 content + ); + }, +}; + +export const WithASubduedSection = { + render() { + return ( + + + + Felix Crafford + Ezequiel Manno + - Section 2 content + + + + Felix Crafford + Ezequiel Manno + + + + ); + }, +}; + +export const WithSubduedForSecondaryContent = { + render() { + return ( + + + Felix Crafford + Ezequiel Manno + + ); + }, +}; + +export const WithSeparateHeader = { + render() { + return ( - Section 1 content - - Subdued section 2 content + + + Add account + + } + onClose={() => {}} + > + + + + + + Felix Crafford + Ezequiel Manno + - - Section 1 content - - Subdued section 2 content + ); + }, +}; + +export const WithCustomReactNodeTitle = { + render() { + return ( + + + + + New Products + + + } + > + + Socks + Super Shoes + - Section 3 content - - - Section 1 content + ); + }, +}; + +export const WithAllElements = { + render() { + return ( + + + + View Sales + + } + onClose={() => {}} + > + + + + + + You can use sales reports to see information about your customers’ + orders based on criteria such as sales over time, by channel, or by + staff. + - - This should be flush + + { + const {sales, amount, url} = item; + return ( + + + {sales} + {amount} + + + ); + }} + /> - - - - - - - - - - - - First nested section - - - - - Second nested section - - - + + + Payouts + Total Sales By Channel + - - - - - First nested section - - - - - Second nested section - - - + + + The sales reports are available only if your store is on the Shopify + plan or higher. + + ); + }, +}; + +export const WithFlushedSections = { + render() { + return ( - - +
+ + } + items={[ + { + id: 341, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 256, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> + +
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} - -export function WithChildrenContent() { - const [taggedWith, setTaggedWith] = useState(null); - const [queryValue, setQueryValue] = useState(null); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - return ( -
- - -
- -
- - } - items={[ - { - id: 341, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 256, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - setTaggedWith(value), + [], + ); + const handleQueryValueChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + return ( +
+ + - - {name} - -
{location}
- - ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; +
+ +
+ + } + items={[ + { + id: 341, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 256, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} - -export function Disabled() { - const [taggedWith, setTaggedWith] = useState(null); - const [queryValue, setQueryValue] = useState(null); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - return ( -
- - -
- -
- - } - items={[ - { - id: 341, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 256, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - setTaggedWith(value), + [], + ); + const handleQueryValueChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleVendorChange = useCallback((value) => setVendor(value), []); + + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + const handleVendorRemove = useCallback(() => setVendor(null), []); + + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + handleVendorRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove, handleVendorRemove]); + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'vendor', + label: 'Vendor', + filter: ( + + ), + shortcut: true, + disabled: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + return ( +
+ + - - {name} - -
{location}
- - ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; +
+ +
+ + } + items={[ + { + id: 341, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 256, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} - -export function SomeDisabled() { - const [taggedWith, setTaggedWith] = useState(null); - const [vendor, setVendor] = useState(null); - const [queryValue, setQueryValue] = useState(null); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleVendorChange = useCallback((value) => setVendor(value), []); - - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - const handleVendorRemove = useCallback(() => setVendor(null), []); - - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - handleVendorRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove, handleVendorRemove]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'vendor', - label: 'Vendor', - filter: ( - - ), - shortcut: true, - disabled: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - return ( -
- - -
- -
- - } - items={[ - { - id: 341, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 256, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - setTaggedWith(value), + [], + ); + const handleQueryValueChange = useCallback( + (value) => setQueryValue(value), + [], + ); + + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + + const filters = [ + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + hideClearButton: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ + { + key: 'taggedWith', + label: disambiguateLabel('taggedWith', taggedWith), + onRemove: handleTaggedWithRemove, + }, + ] + : []; + + return ( +
+ + - - {name} - -
{location}
- - ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; +
+ +
+ + } + items={[ + { + id: 341, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 256, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith': + return `Tagged with ${value}`; + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} - -export function WithoutClearButton() { - const [taggedWith, setTaggedWith] = useState(null); - const [queryValue, setQueryValue] = useState(null); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const filters = [ - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - hideClearButton: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith', - label: disambiguateLabel('taggedWith', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - return ( -
- - -
- -
- - } - items={[ - { - id: 341, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 256, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith': - return `Tagged with ${value}`; - default: - return value; + + {name} + +
{location}
+ + ); + }} + /> + +
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} - -export function WithHelpText() { - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(null); - const [queryValue, setQueryValue] = useState(null); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - } - items={[ - { - id: 341, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 256, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; + }, +}; + +export const WithQueryFieldHidden = { + render() { + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(null); + const [queryValue, setQueryValue] = useState(null); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; + + const appliedFilters = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); } - } - - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); } - } -} - -export function WithQueryFieldHidden() { - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(null); - const [queryValue, setQueryValue] = useState(null); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - } - items={[ - { - id: 341, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 256, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + return ( +
+ + + } + items={[ + { + id: 341, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 256, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } } - } -} - -export function WithQueryFieldDisabled() { - const [accountStatus, setAccountStatus] = useState(null); - const [moneySpent, setMoneySpent] = useState(null); - const [taggedWith, setTaggedWith] = useState(null); - const [queryValue, setQueryValue] = useState(null); - - const handleAccountStatusChange = useCallback( - (value) => setAccountStatus(value), - [], - ); - const handleMoneySpentChange = useCallback( - (value) => setMoneySpent(value), - [], - ); - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleFiltersQueryChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleAccountStatusRemove = useCallback( - () => setAccountStatus(null), - [], - ); - const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - const handleFiltersClearAll = useCallback(() => { - handleAccountStatusRemove(); - handleMoneySpentRemove(); - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [ - handleAccountStatusRemove, - handleMoneySpentRemove, - handleQueryValueRemove, - handleTaggedWithRemove, - ]); - - const filters = [ - { - key: 'accountStatus', - label: 'Account status', - filter: ( - - ), - shortcut: true, - }, - { - key: 'taggedWith', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - { - key: 'moneySpent', - label: 'Money spent', - filter: ( - - ), - }, - ]; - - const appliedFilters = []; - if (!isEmpty(accountStatus)) { - const key = 'accountStatus'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, accountStatus), - onRemove: handleAccountStatusRemove, - }); - } - if (!isEmpty(moneySpent)) { - const key = 'moneySpent'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, moneySpent), - onRemove: handleMoneySpentRemove, - }); - } - if (!isEmpty(taggedWith)) { - const key = 'taggedWith'; - appliedFilters.push({ - key, - label: disambiguateLabel(key, taggedWith), - onRemove: handleTaggedWithRemove, - }); - } - - return ( -
- - - } - items={[ - { - id: 341, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 256, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; - - return ( - - - {name} - -
{location}
-
- ); - }} - /> -
-
- ); - - function disambiguateLabel(key, value) { - switch (key) { - case 'moneySpent': - return `Money spent is between $${value[0]} and $${value[1]}`; - case 'taggedWith': - return `Tagged with ${value}`; - case 'accountStatus': - return value.map((val) => `Customer ${val}`).join(', '); - default: - return value; + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithQueryFieldDisabled = { + render() { + const [accountStatus, setAccountStatus] = useState(null); + const [moneySpent, setMoneySpent] = useState(null); + const [taggedWith, setTaggedWith] = useState(null); + const [queryValue, setQueryValue] = useState(null); + + const handleAccountStatusChange = useCallback( + (value) => setAccountStatus(value), + [], + ); + const handleMoneySpentChange = useCallback( + (value) => setMoneySpent(value), + [], + ); + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleFiltersQueryChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleAccountStatusRemove = useCallback( + () => setAccountStatus(null), + [], + ); + const handleMoneySpentRemove = useCallback(() => setMoneySpent(null), []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + const handleFiltersClearAll = useCallback(() => { + handleAccountStatusRemove(); + handleMoneySpentRemove(); + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [ + handleAccountStatusRemove, + handleMoneySpentRemove, + handleQueryValueRemove, + handleTaggedWithRemove, + ]); + + const filters = [ + { + key: 'accountStatus', + label: 'Account status', + filter: ( + + ), + shortcut: true, + }, + { + key: 'taggedWith', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + { + key: 'moneySpent', + label: 'Money spent', + filter: ( + + ), + }, + ]; + + const appliedFilters = []; + if (!isEmpty(accountStatus)) { + const key = 'accountStatus'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, accountStatus), + onRemove: handleAccountStatusRemove, + }); + } + if (!isEmpty(moneySpent)) { + const key = 'moneySpent'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, moneySpent), + onRemove: handleMoneySpentRemove, + }); + } + if (!isEmpty(taggedWith)) { + const key = 'taggedWith'; + appliedFilters.push({ + key, + label: disambiguateLabel(key, taggedWith), + onRemove: handleTaggedWithRemove, + }); } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + return ( +
+ + + } + items={[ + { + id: 341, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 256, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + + + {name} + +
{location}
+
+ ); + }} + /> +
+
+ ); + + function disambiguateLabel(key, value) { + switch (key) { + case 'moneySpent': + return `Money spent is between $${value[0]} and $${value[1]}`; + case 'taggedWith': + return `Tagged with ${value}`; + case 'accountStatus': + return value.map((val) => `Customer ${val}`).join(', '); + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } } - } -} + }, +}; diff --git a/polaris-react/src/components/LegacyStack/LegacyStack.stories.tsx b/polaris-react/src/components/LegacyStack/LegacyStack.stories.tsx index f007841ac34..1b018908892 100644 --- a/polaris-react/src/components/LegacyStack/LegacyStack.stories.tsx +++ b/polaris-react/src/components/LegacyStack/LegacyStack.stories.tsx @@ -1,96 +1,110 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Badge, Text, LegacyStack} from '@shopify/polaris'; export default { component: LegacyStack, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - Paid - Processing - Fulfilled - Completed - - ); -} - -export function NonWrapping() { - return ( - - Paid - Processing - Fulfilled - Completed - - ); -} +export const Default = { + render() { + return ( + + Paid + Processing + Fulfilled + Completed + + ); + }, +}; -export function Spacing() { - return ( - - Paid - Fulfilled - - ); -} +export const NonWrapping = { + render() { + return ( + + Paid + Processing + Fulfilled + Completed + + ); + }, +}; -export function VerticalCentering() { - return ( - - - Order -
- #1136 -
- was paid -
- Paid - Fulfilled -
- ); -} +export const Spacing = { + render() { + return ( + + Paid + Fulfilled + + ); + }, +}; -export function FillAvailableSpaceProportionally() { - return ( - - - Order #1136 - - Paid - Fulfilled - - ); -} +export const VerticalCentering = { + render() { + return ( + + + Order +
+ #1136 +
+ was paid +
+ Paid + Fulfilled +
+ ); + }, +}; -export function WhereItemsFillSpaceEvenly() { - return ( - - - Order #1136 - - Paid - Fulfilled - - ); -} +export const FillAvailableSpaceProportionally = { + render() { + return ( + + + Order #1136 + + Paid + Fulfilled + + ); + }, +}; -export function WhereASingleItemFillsTheRemainingSpace() { - return ( - - +export const WhereItemsFillSpaceEvenly = { + render() { + return ( + Order #1136 - - Paid - - Fulfilled - - - ); -} + + ); + }, +}; + +export const WhereASingleItemFillsTheRemainingSpace = { + render() { + return ( + + + + Order #1136 + + + + Paid + + + Fulfilled + + + ); + }, +}; diff --git a/polaris-react/src/components/LegacyTabs/LegacyTabs.stories.tsx b/polaris-react/src/components/LegacyTabs/LegacyTabs.stories.tsx index 7f43f032455..cc755d85b22 100644 --- a/polaris-react/src/components/LegacyTabs/LegacyTabs.stories.tsx +++ b/polaris-react/src/components/LegacyTabs/LegacyTabs.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Badge, LegacyCard, @@ -10,273 +10,287 @@ import { export default { component: LegacyTabs, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - - - - Default - - - +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + Default + + + - - - With URL tabs - - - + + + With URL tabs + + + - - - Fitted - - - + + + Fitted + + + - - - With badge content - - - + + + With badge content + + + - - - With custom disclosure - - + + + With custom disclosure + + + - - ); -} - -export function Default() { - const [selected, setSelected] = useState(0); - - const handleTabChange = useCallback( - (selectedTabIndex) => setSelected(selectedTabIndex), - [], - ); - - const tabs = [ - { - id: 'all-customers-1', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-content-1', - }, - { - id: 'accepts-marketing-1', - content: 'Accepts marketing', - panelID: 'accepts-marketing-content-1', - }, - { - id: 'repeat-customers-1', - content: 'Repeat customers', - panelID: 'repeat-customers-content-1', - }, - { - id: 'prospects-1', - content: 'Prospects', - panelID: 'prospects-content-1', - }, - ]; - - return ( - - - - Tab {selected} selected - - - - ); -} - -export function WithUrlTabs() { - const [selected, setSelected] = useState(0); - - const handleTabChange = useCallback( - (selectedTabIndex) => setSelected(selectedTabIndex), - [], - ); - - const tabs = [ - { - id: 'all-customers-2', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-content-2', - url: '#', - }, - { - id: 'accepts-marketing-2', - content: 'Accepts marketing', - panelID: 'accepts-marketing-content-2', - url: '#', - }, - { - id: 'repeat-customers-2', - content: 'Repeat customers', - panelID: 'repeat-customers-content-2', - url: '#', - }, - { - id: 'prospects-2', - content: 'Prospects', - panelID: 'prospects-content-2', - url: '#', - }, - ]; + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; - return ( - - - - Tab {selected} selected - - - - ); -} +export const Default = { + render() { + const [selected, setSelected] = useState(0); -export function Fitted() { - const [selected, setSelected] = useState(0); + const handleTabChange = useCallback( + (selectedTabIndex) => setSelected(selectedTabIndex), + [], + ); - const handleTabChange = useCallback( - (selectedTabIndex) => setSelected(selectedTabIndex), - [], - ); + const tabs = [ + { + id: 'all-customers-1', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-content-1', + }, + { + id: 'accepts-marketing-1', + content: 'Accepts marketing', + panelID: 'accepts-marketing-content-1', + }, + { + id: 'repeat-customers-1', + content: 'Repeat customers', + panelID: 'repeat-customers-content-1', + }, + { + id: 'prospects-1', + content: 'Prospects', + panelID: 'prospects-content-1', + }, + ]; - const tabs = [ - { - id: 'all-customers-fitted-3', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-fitted-content-3', - }, - { - id: 'accepts-marketing-fitted-3', - content: 'Accepts marketing', - panelID: 'accepts-marketing-fitted-Ccontent-3', - }, - ]; - - return ( - - + return ( + Tab {selected} selected - - ); -} + ); + }, +}; -export function WithBadgeContent() { - const [selected, setSelected] = useState(0); +export const WithUrlTabs = { + render() { + const [selected, setSelected] = useState(0); - const handleTabChange = useCallback( - (selectedTabIndex) => setSelected(selectedTabIndex), - [], - ); + const handleTabChange = useCallback( + (selectedTabIndex) => setSelected(selectedTabIndex), + [], + ); - const tabs = [ - { - id: 'all-customers-fitted-4', - content: ( - - All 10+ - - ), - accessibilityLabel: 'All customers', - panelID: 'all-customers-fitted-content-4', - }, - { - id: 'accepts-marketing-fitted-4', - content: ( - - Accepts marketing 4 - - ), - panelID: 'accepts-marketing-fitted-content-4', - }, - ]; + const tabs = [ + { + id: 'all-customers-2', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-content-2', + url: '#', + }, + { + id: 'accepts-marketing-2', + content: 'Accepts marketing', + panelID: 'accepts-marketing-content-2', + url: '#', + }, + { + id: 'repeat-customers-2', + content: 'Repeat customers', + panelID: 'repeat-customers-content-2', + url: '#', + }, + { + id: 'prospects-2', + content: 'Prospects', + panelID: 'prospects-content-2', + url: '#', + }, + ]; - return ( - - + return ( + Tab {selected} selected - - ); -} + ); + }, +}; -export function WithCustomDisclosure() { - const [selected, setSelected] = useState(0); +export const Fitted = { + render() { + const [selected, setSelected] = useState(0); - const handleTabChange = useCallback( - (selectedTabIndex) => setSelected(selectedTabIndex), - [], - ); + const handleTabChange = useCallback( + (selectedTabIndex) => setSelected(selectedTabIndex), + [], + ); - const tabs = [ - { - id: 'all-customers-5', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-content-5', - }, - { - id: 'accepts-marketing-5', - content: 'Accepts marketing', - panelID: 'accepts-marketing-content-5', - }, - { - id: 'repeat-customers-5', - content: 'Repeat customers', - panelID: 'repeat-customers-content-5', - }, - { - id: 'prospects-5', - content: 'Prospects', - panelID: 'prospects-content-5', - }, - ]; + const tabs = [ + { + id: 'all-customers-fitted-3', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-fitted-content-3', + }, + { + id: 'accepts-marketing-fitted-3', + content: 'Accepts marketing', + panelID: 'accepts-marketing-fitted-Ccontent-3', + }, + ]; - return ( - - - - - Tab {selected} selected - - - - - ); -} + return ( + + + + + Tab {selected} selected + + + + + ); + }, +}; + +export const WithBadgeContent = { + render() { + const [selected, setSelected] = useState(0); + + const handleTabChange = useCallback( + (selectedTabIndex) => setSelected(selectedTabIndex), + [], + ); + + const tabs = [ + { + id: 'all-customers-fitted-4', + content: ( + + All 10+ + + ), + accessibilityLabel: 'All customers', + panelID: 'all-customers-fitted-content-4', + }, + { + id: 'accepts-marketing-fitted-4', + content: ( + + Accepts marketing 4 + + ), + panelID: 'accepts-marketing-fitted-content-4', + }, + ]; + + return ( + + + + + Tab {selected} selected + + + + + ); + }, +}; + +export const WithCustomDisclosure = { + render() { + const [selected, setSelected] = useState(0); + + const handleTabChange = useCallback( + (selectedTabIndex) => setSelected(selectedTabIndex), + [], + ); + + const tabs = [ + { + id: 'all-customers-5', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-content-5', + }, + { + id: 'accepts-marketing-5', + content: 'Accepts marketing', + panelID: 'accepts-marketing-content-5', + }, + { + id: 'repeat-customers-5', + content: 'Repeat customers', + panelID: 'repeat-customers-content-5', + }, + { + id: 'prospects-5', + content: 'Prospects', + panelID: 'prospects-content-5', + }, + ]; + + return ( + + + + + Tab {selected} selected + + + + + ); + }, +}; diff --git a/polaris-react/src/components/Link/Link.stories.tsx b/polaris-react/src/components/Link/Link.stories.tsx index 5201c129167..ea9371d11d1 100644 --- a/polaris-react/src/components/Link/Link.stories.tsx +++ b/polaris-react/src/components/Link/Link.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Banner, Link} from '@shopify/polaris'; export default { @@ -7,33 +7,41 @@ export default { parameters: { disableAnchorTargetOverride: true, }, -} as ComponentMeta; +} as Meta; -export function Default() { - return fulfilling orders; -} +export const Default = { + render() { + return fulfilling orders; + }, +}; -export function Monochrome() { - return ( - - fulfilling orders - - ); -} +export const Monochrome = { + render() { + return ( + + fulfilling orders + + ); + }, +}; -export function MonochromeInABanner() { - return ( - - Learn more about{' '} - fulfilling orders - - ); -} +export const MonochromeInABanner = { + render() { + return ( + + Learn more about{' '} + fulfilling orders + + ); + }, +}; -export function External() { - return ( - - Shopify Help Center - - ); -} +export const External = { + render() { + return ( + + Shopify Help Center + + ); + }, +}; diff --git a/polaris-react/src/components/List/List.stories.tsx b/polaris-react/src/components/List/List.stories.tsx index 71106572076..474e9d8dbc6 100644 --- a/polaris-react/src/components/List/List.stories.tsx +++ b/polaris-react/src/components/List/List.stories.tsx @@ -1,37 +1,43 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {List} from '@shopify/polaris'; export default { component: List, -} as ComponentMeta; +} as Meta; -export function Bulleted() { - return ( - - Yellow shirt - Red shirt - Green shirt - - ); -} +export const Bulleted = { + render() { + return ( + + Yellow shirt + Red shirt + Green shirt + + ); + }, +}; -export function Numbered() { - return ( - - First item - Second item - Third Item - - ); -} +export const Numbered = { + render() { + return ( + + First item + Second item + Third Item + + ); + }, +}; -export function ExtraTight() { - return ( - - Yellow shirt - Red shirt - Green shirt - - ); -} +export const ExtraTight = { + render() { + return ( + + Yellow shirt + Red shirt + Green shirt + + ); + }, +}; diff --git a/polaris-react/src/components/Listbox/Listbox.stories.tsx b/polaris-react/src/components/Listbox/Listbox.stories.tsx index d128dcb0b0a..0dc826bf473 100644 --- a/polaris-react/src/components/Listbox/Listbox.stories.tsx +++ b/polaris-react/src/components/Listbox/Listbox.stories.tsx @@ -1,5 +1,5 @@ import React, {useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { LegacyCard, EmptySearchResult, @@ -18,464 +18,482 @@ import {PlusCircleIcon, SearchIcon} from '@shopify/polaris-icons'; export default { component: Listbox, -} as ComponentMeta; - -export function All() { - return ( - - - - Default - - +} as Meta; + +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + Default + + + + + + + + With loading + + + + + + + + With action + + + + + + + + With custom element + + + + + + + + With search + + + + + + + + With disabled text option + + + - - - - With loading - - - - - - - - With action - - - - - - - - With custom element - - - - - - - - With search - - - - - - - - With disabled text option - - - - - - ); -} - -export function Default() { - return ( - - Item 1 - Item 2 - Item 3 - - ); -} - -export function WithLoading() { - return ( - - Item 1 - Item 2 - Item 3 - - - ); -} - -export function WithAction() { - return ( - - Item 1 - - Item 2 - - - - -
Add item
-
-
-
- ); -} - -export function WithCustomOptions() { - interface CustomerSegment { - id: string; - label: string; - value: string; - subscribers: number; - } - - const [selectedSegmentIndex, setSelectedSegmentIndex] = useState(0); - - const segments: CustomerSegment[] = [ - { - label: 'All customers', - id: 'gid://shopify/CustomerSegment/1', - value: '0', - subscribers: 23, - }, - { - label: 'VIP customers', - id: 'gid://shopify/CustomerSegment/2', - value: '1', - subscribers: 16, - }, - { - label: 'New customers', - id: 'gid://shopify/CustomerSegment/3', - value: '2', - subscribers: 2, - }, - { - label: 'Abandoned carts - last 30 days', - id: 'gid://shopify/CustomerSegment/4', - value: '3', - subscribers: 108, - }, - ]; - - const handleSegmentSelect = (segmentIndex: string) => { - setSelectedSegmentIndex(Number(segmentIndex)); - }; - - return ( - - {segments.map(({label, id, value, subscribers}) => { - const selected = segments[selectedSegmentIndex].value === value; - - return ( - - - - - {label} - - {`${subscribers} subscribers`} - - - - - - ); - })} - - ); -} - -export function WithSearch() { - interface CustomerSegment { - id: string; - label: string; - value: string; - } - - const actionValue = '__ACTION__'; - - const segments: CustomerSegment[] = [ - { - label: 'All customers', - id: 'gid://shopify/CustomerSegment/1', - value: '0', - }, - { - label: 'VIP customers', - id: 'gid://shopify/CustomerSegment/2', - value: '1', - }, - { - label: 'New customers', - id: 'gid://shopify/CustomerSegment/3', - value: '2', - }, - { - label: 'Abandoned carts - last 30 days', - id: 'gid://shopify/CustomerSegment/4', - value: '3', - }, - { - label: 'Wholesale customers', - id: 'gid://shopify/CustomerSegment/5', - value: '4', - }, - { - label: 'Email subscribers', - id: 'gid://shopify/CustomerSegment/6', - value: '5', - }, - { - label: 'From New York', - id: 'gid://shopify/CustomerSegment/7', - value: '6', - }, - { - label: 'Repeat buyers', - id: 'gid://shopify/CustomerSegment/8', - value: '7', - }, - { - label: 'First time buyers', - id: 'gid://shopify/CustomerSegment/9', - value: '8', - }, - { - label: 'From Canada', - id: 'gid://shopify/CustomerSegment/10', - value: '9', - }, - { - label: 'Bought in last 60 days', - id: 'gid://shopify/CustomerSegment/11', - value: '10', - }, - { - label: 'Bought last BFCM', - id: 'gid://shopify/CustomerSegment/12', - value: '11', - }, - ]; - - const lazyLoadSegments: CustomerSegment[] = Array.from(Array(100)).map( - (_, index) => ({ - label: `Other customers ${index + 13}`, - id: `gid://shopify/CustomerSegment/${index + 13}`, - value: `${index + 12}`, - }), - ); - - segments.push(...lazyLoadSegments); - - const interval = 25; - - const [showFooterAction, setShowFooterAction] = useState(true); - const [query, setQuery] = useState(''); - const [lazyLoading, setLazyLoading] = useState(false); - const [willLoadMoreResults, setWillLoadMoreResults] = useState(true); - const [visibleOptionIndex, setVisibleOptionIndex] = useState(6); - const [activeOptionId, setActiveOptionId] = useState(segments[0].id); - const [selectedSegmentIndex, setSelectedSegmentIndex] = useState(0); - const [filteredSegments, setFilteredSegments] = useState( - [], - ); - - const handleClickShowAll = () => { - setShowFooterAction(false); - setVisibleOptionIndex(segments.length); - }; - - const handleFilterSegments = (query: string) => { - const nextFilteredSegments = segments.filter((segment: CustomerSegment) => { - return segment.label - .toLocaleLowerCase() - .includes(query.toLocaleLowerCase().trim()); - }); - - setFilteredSegments(nextFilteredSegments); - }; - - const handleQueryChange = (query: string) => { - setQuery(query); - - if (query.length >= 2) handleFilterSegments(query); - }; - - const handleQueryClear = () => { - handleQueryChange(''); - }; - - const handleResetVisibleOptionIndex = () => { - setVisibleOptionIndex(interval); - }; - - const handleSegmentSelect = (segmentIndex: string) => { - if (segmentIndex === actionValue) { - return handleClickShowAll(); + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; + +export const Default = { + render() { + return ( + + Item 1 + Item 2 + Item 3 + + ); + }, +}; + +export const WithLoading = { + render() { + return ( + + Item 1 + Item 2 + Item 3 + + + ); + }, +}; + +export const WithAction = { + render() { + return ( + + Item 1 + + Item 2 + + + + +
Add item
+
+
+
+ ); + }, +}; + +export const WithCustomOptions = { + render() { + interface CustomerSegment { + id: string; + label: string; + value: string; + subscribers: number; } - setSelectedSegmentIndex(Number(segmentIndex)); - }; - - const handleActiveOptionChange = (_: string, domId: string) => { - setActiveOptionId(domId); - }; - - /* This is just to illustrate lazy loading state vs loading state. This is an example, so we aren't fetching from GraphQL. You'd use `pageInfo.hasNextPage` from your GraphQL query data instead of this fake "willLoadMoreResults" state along with setting `first` your GraphQL query's variables to your app's default max edges limit (e.g., 250). */ - - const handleLazyLoadSegments = () => { - if (willLoadMoreResults && !showFooterAction) { - setLazyLoading(true); - - const options = query ? filteredSegments : segments; - - setTimeout(() => { - const remainingOptionCount = options.length - visibleOptionIndex; - const nextVisibleOptionIndex = - remainingOptionCount >= interval - ? visibleOptionIndex + interval - : visibleOptionIndex + remainingOptionCount; + const [selectedSegmentIndex, setSelectedSegmentIndex] = useState(0); + + const segments: CustomerSegment[] = [ + { + label: 'All customers', + id: 'gid://shopify/CustomerSegment/1', + value: '0', + subscribers: 23, + }, + { + label: 'VIP customers', + id: 'gid://shopify/CustomerSegment/2', + value: '1', + subscribers: 16, + }, + { + label: 'New customers', + id: 'gid://shopify/CustomerSegment/3', + value: '2', + subscribers: 2, + }, + { + label: 'Abandoned carts - last 30 days', + id: 'gid://shopify/CustomerSegment/4', + value: '3', + subscribers: 108, + }, + ]; + + const handleSegmentSelect = (segmentIndex: string) => { + setSelectedSegmentIndex(Number(segmentIndex)); + }; + + return ( + + {segments.map(({label, id, value, subscribers}) => { + const selected = segments[selectedSegmentIndex].value === value; + + return ( + + + + + {label} + + {`${subscribers} subscribers`} + + + + + + ); + })} + + ); + }, +}; + +export const WithSearch = { + render() { + interface CustomerSegment { + id: string; + label: string; + value: string; + } - setLazyLoading(false); - setVisibleOptionIndex(nextVisibleOptionIndex); + const actionValue = '__ACTION__'; + + const segments: CustomerSegment[] = [ + { + label: 'All customers', + id: 'gid://shopify/CustomerSegment/1', + value: '0', + }, + { + label: 'VIP customers', + id: 'gid://shopify/CustomerSegment/2', + value: '1', + }, + { + label: 'New customers', + id: 'gid://shopify/CustomerSegment/3', + value: '2', + }, + { + label: 'Abandoned carts - last 30 days', + id: 'gid://shopify/CustomerSegment/4', + value: '3', + }, + { + label: 'Wholesale customers', + id: 'gid://shopify/CustomerSegment/5', + value: '4', + }, + { + label: 'Email subscribers', + id: 'gid://shopify/CustomerSegment/6', + value: '5', + }, + { + label: 'From New York', + id: 'gid://shopify/CustomerSegment/7', + value: '6', + }, + { + label: 'Repeat buyers', + id: 'gid://shopify/CustomerSegment/8', + value: '7', + }, + { + label: 'First time buyers', + id: 'gid://shopify/CustomerSegment/9', + value: '8', + }, + { + label: 'From Canada', + id: 'gid://shopify/CustomerSegment/10', + value: '9', + }, + { + label: 'Bought in last 60 days', + id: 'gid://shopify/CustomerSegment/11', + value: '10', + }, + { + label: 'Bought last BFCM', + id: 'gid://shopify/CustomerSegment/12', + value: '11', + }, + ]; + + const lazyLoadSegments: CustomerSegment[] = Array.from(Array(100)).map( + (_, index) => ({ + label: `Other customers ${index + 13}`, + id: `gid://shopify/CustomerSegment/${index + 13}`, + value: `${index + 12}`, + }), + ); + + segments.push(...lazyLoadSegments); + + const interval = 25; + + const [showFooterAction, setShowFooterAction] = useState(true); + const [query, setQuery] = useState(''); + const [lazyLoading, setLazyLoading] = useState(false); + const [willLoadMoreResults, setWillLoadMoreResults] = useState(true); + const [visibleOptionIndex, setVisibleOptionIndex] = useState(6); + const [activeOptionId, setActiveOptionId] = useState(segments[0].id); + const [selectedSegmentIndex, setSelectedSegmentIndex] = useState(0); + const [filteredSegments, setFilteredSegments] = useState( + [], + ); + + const handleClickShowAll = () => { + setShowFooterAction(false); + setVisibleOptionIndex(segments.length); + }; + + const handleFilterSegments = (query: string) => { + const nextFilteredSegments = segments.filter( + (segment: CustomerSegment) => { + return segment.label + .toLocaleLowerCase() + .includes(query.toLocaleLowerCase().trim()); + }, + ); + + setFilteredSegments(nextFilteredSegments); + }; + + const handleQueryChange = (query: string) => { + setQuery(query); + + if (query.length >= 2) handleFilterSegments(query); + }; + + const handleQueryClear = () => { + handleQueryChange(''); + }; + + const handleResetVisibleOptionIndex = () => { + setVisibleOptionIndex(interval); + }; + + const handleSegmentSelect = (segmentIndex: string) => { + if (segmentIndex === actionValue) { + return handleClickShowAll(); + } + + setSelectedSegmentIndex(Number(segmentIndex)); + }; + + const handleActiveOptionChange = (_: string, domId: string) => { + setActiveOptionId(domId); + }; + + /* This is just to illustrate lazy loading state vs loading state. This is an example, so we aren't fetching from GraphQL. You'd use `pageInfo.hasNextPage` from your GraphQL query data instead of this fake "willLoadMoreResults" state along with setting `first` your GraphQL query's variables to your app's default max edges limit (e.g., 250). */ + + const handleLazyLoadSegments = () => { + if (willLoadMoreResults && !showFooterAction) { + setLazyLoading(true); + + const options = query ? filteredSegments : segments; + + setTimeout(() => { + const remainingOptionCount = options.length - visibleOptionIndex; + const nextVisibleOptionIndex = + remainingOptionCount >= interval + ? visibleOptionIndex + interval + : visibleOptionIndex + remainingOptionCount; + + setLazyLoading(false); + setVisibleOptionIndex(nextVisibleOptionIndex); + + if (remainingOptionCount <= interval) { + setWillLoadMoreResults(false); + } + }, 1000); + } + }; + + const listboxId = 'SearchableListbox'; + + const textFieldMarkup = ( +
+ } + ariaActiveDescendant={activeOptionId} + ariaControls={listboxId} + onChange={handleQueryChange} + onClearButtonClick={handleQueryClear} + /> +
+ ); + + const segmentOptions = query ? filteredSegments : segments; + + const segmentList = + segmentOptions.length > 0 + ? segmentOptions + .slice(0, visibleOptionIndex) + .map(({label, id, value}) => { + const selected = segments[selectedSegmentIndex].value === value; + + return ( + + + {label} + + + ); + }) + : null; + + const showAllMarkup = showFooterAction ? ( + + + Show all 111 segments + + + ) : null; - if (remainingOptionCount <= interval) { - setWillLoadMoreResults(false); - } - }, 1000); - } - }; - - const listboxId = 'SearchableListbox'; - - const textFieldMarkup = ( -
- } - ariaActiveDescendant={activeOptionId} - ariaControls={listboxId} - onChange={handleQueryChange} - onClearButtonClick={handleQueryClear} - /> -
- ); - - const segmentOptions = query ? filteredSegments : segments; - - const segmentList = - segmentOptions.length > 0 - ? segmentOptions - .slice(0, visibleOptionIndex) - .map(({label, id, value}) => { - const selected = segments[selectedSegmentIndex].value === value; - - return ( - - - {label} - - - ); - }) - : null; - - const showAllMarkup = showFooterAction ? ( - - - Show all 111 segments - - - ) : null; - - const lazyLoadingMarkup = lazyLoading ? ( - - ) : null; - - const noResultsMarkup = - segmentOptions.length === 0 ? ( - ) : null; - const listboxMarkup = ( - - {segmentList} - {showAllMarkup} - {noResultsMarkup} - {lazyLoadingMarkup} - - ); - - return ( - -
+ ) : null; + + const listboxMarkup = ( + - {textFieldMarkup} - - + ); + + return ( + +
- {listboxMarkup} - -
-
- ); -} - -export function WithDisabledTextOption() { - return ( - - - - - Item 1 - - - Item 2 - - - Item 3 - - - - - ); -} + {textFieldMarkup} + + + {listboxMarkup} + +
+
+ ); + }, +}; + +export const WithDisabledTextOption = { + render() { + return ( + + + + + Item 1 + + + Item 2 + + + Item 3 + + + + + ); + }, +}; diff --git a/polaris-react/src/components/Loading/Loading.stories.tsx b/polaris-react/src/components/Loading/Loading.stories.tsx index c0b145e463e..54a9e3764c3 100644 --- a/polaris-react/src/components/Loading/Loading.stories.tsx +++ b/polaris-react/src/components/Loading/Loading.stories.tsx @@ -1,17 +1,19 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Frame, Loading} from '@shopify/polaris'; export default { component: Loading, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( -
- - - -
- ); -} +export const Default = { + render() { + return ( +
+ + + +
+ ); + }, +}; diff --git a/polaris-react/src/components/MediaCard/MediaCard.stories.tsx b/polaris-react/src/components/MediaCard/MediaCard.stories.tsx index d172ed372da..1a282f43156 100644 --- a/polaris-react/src/components/MediaCard/MediaCard.stories.tsx +++ b/polaris-react/src/components/MediaCard/MediaCard.stories.tsx @@ -1,182 +1,215 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {MediaCard, BlockStack, VideoThumbnail} from '@shopify/polaris'; export default { component: MediaCard, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - {}, - }} - description="Discover how Shopify can power up your entrepreneurial journey." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - > - {}, }} - src="https://burst.shopifycdn.com/photos/business-woman-smiling-in-office.jpg?width=1850" - /> - - ); -} + description="Discover how Shopify can power up your entrepreneurial journey." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + > + + + ); + }, +}; -export function WithSmallVisual() { - return ( - {}, - }} - description="Discover how Shopify can power up your entrepreneurial journey." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - size="small" - > - {}, }} - src="https://burst.shopifycdn.com/photos/business-woman-smiling-in-office.jpg?width=1850" - /> - - ); -} + description="Discover how Shopify can power up your entrepreneurial journey." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + size="small" + > + + + ); + }, +}; -export function WithSecondaryAction() { - return ( - {}, - }} - secondaryAction={{ - content: 'Learn more', - onAction: () => {}, - }} - description="Start your business with eye-catching inventory." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - > - - - ); -} +export const WithSecondaryAction = { + render() { + return ( + {}, + }} + secondaryAction={{ + content: 'Learn more', + onAction: () => {}, + }} + description="Start your business with eye-catching inventory." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + > + + + ); + }, +}; -export function WithNoActions() { - return ( - {}}]} - > - - - ); -} +export const WithNoActions = { + render() { + return ( + {}}]} + > + + + ); + }, +}; -export function VideoCard() { - return ( - {}, - }} - description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - > - - - ); -} +export const VideoCard = { + render() { + return ( + {}, + }} + description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + > + + + ); + }, +}; -export function PortraitVideoCard() { - return ( - {}, - }} - description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - > - - - ); -} +export const PortraitVideoCard = { + render() { + return ( + {}, + }} + description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + > + + + ); + }, +}; -export function WithDismissButton() { - return ( - {}, - }} - description="Discover how Shopify can power up your entrepreneurial journey." - onDismiss={() => console.log('clicked')} - > - {}, }} - src="https://burst.shopifycdn.com/photos/business-woman-smiling-in-office.jpg?width=1850" - /> - - ); -} + description="Discover how Shopify can power up your entrepreneurial journey." + onDismiss={() => console.log('clicked')} + > + + + ); + }, +}; + +export const WithDismissButtonAndPopoverActions = { + render() { + return ( + {}, + }} + description="Discover how Shopify can power up your entrepreneurial journey." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + onDismiss={() => console.log('clicked')} + > + + + ); + }, +}; -export function WithDismissButtonAndPopoverActions() { - return ( - {}, - }} - description="Discover how Shopify can power up your entrepreneurial journey." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - onDismiss={() => console.log('clicked')} - > +export const All = { + render() { + const image = ( - - ); -} + ); -export function All() { - const image = ( - - ); - - const MediaCardExample = (props) => ( - {}, - }} - secondaryAction={{ - content: 'Learn more', - onAction: () => {}, - }} - description="Discover how Shopify can power up your entrepreneurial journey." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - onDismiss={() => {}} - {...props} - > - {image} - - ); + const MediaCardExample = (props) => ( + {}, + }} + secondaryAction={{ + content: 'Learn more', + onAction: () => {}, + }} + description="Discover how Shopify can power up your entrepreneurial journey." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + onDismiss={() => {}} + {...props} + > + {image} + + ); - return ( - - - - - - - ); -} + return ( + + + + + + + ); + }, +}; diff --git a/polaris-react/src/components/Modal/Modal.stories.tsx b/polaris-react/src/components/Modal/Modal.stories.tsx index bb06b212fb8..cf12dd1f2e4 100644 --- a/polaris-react/src/components/Modal/Modal.stories.tsx +++ b/polaris-react/src/components/Modal/Modal.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useRef, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Banner, Button, @@ -18,616 +18,642 @@ import { export default { component: Modal, -} as ComponentMeta; - -export function Default() { - const [active, setActive] = useState(true); - - const handleChange = useCallback(() => setActive(!active), [active]); - - const activator = ; - - return ( - -
- ; + +export const Default = { + render() { + const [active, setActive] = useState(true); + + const handleChange = useCallback(() => setActive(!active), [active]); + + const activator = ; + + return ( + +
+ - - - Use Instagram posts to share your products with millions of - people. Let shoppers buy from your store without leaving - Instagram. - - - -
- - ); -} - -export function WithPrimaryAction() { - const discountLink = 'https://polaris.shopify.com/'; - - const [active, setActive] = useState(true); - const node = useRef(null); - - const handleClick = useCallback(() => { - node.current && node.current.input.focus(); - }, []); - - const handleFocus = useCallback(() => { - if (node.current == null) { - return; - } - node.current.input.select(); - document.execCommand('copy'); - }, []); - - const toggleModal = useCallback(() => setActive((active) => !active), []); - - const activator = ; - - return ( - -
- - - - - - You can share this discount link with your customers via email - or social media. Your discount will be automatically applied - at checkout. - - - - {}} - autoComplete="off" - connectedRight={ - - } - /> - - - - -
- - ); -} - -export function WithDestructivePrimaryAction() { - const [active, setActive] = useState(true); - - const toggleModal = useCallback(() => setActive((active) => !active), []); + }} + secondaryActions={[ + { + content: 'Learn more', + onAction: handleChange, + }, + ]} + > + + + Use Instagram posts to share your products with millions of + people. Let shoppers buy from your store without leaving + Instagram. + + +
+
+ + ); + }, +}; - const activator = ; +export const WithPrimaryAction = { + render() { + const discountLink = 'https://polaris.shopify.com/'; + + const [active, setActive] = useState(true); + const node = useRef(null); + + const handleClick = useCallback(() => { + node.current && node.current.input.focus(); + }, []); + + const handleFocus = useCallback(() => { + if (node.current == null) { + return; + } + node.current.input.select(); + document.execCommand('copy'); + }, []); + + const toggleModal = useCallback(() => setActive((active) => !active), []); + + const activator = ; + + return ( + +
+ + + + + + You can share this discount link with your customers via + email or social media. Your discount will be automatically + applied at checkout. + + + + {}} + autoComplete="off" + connectedRight={ + + } + /> + + + + +
+ + ); + }, +}; - return ( - -
- setActive((active) => !active), []); + + const activator = ; + + return ( + +
+ - - If you discard changes, you’ll delete any edits you made since you - last saved. - - -
- - ); -} - -export function WithPrimaryAndSecondaryActions() { - const currentPage = 'current_page'; - const allCustomers = 'all_customers'; - const selectedCustomers = 'selected_customers'; - const csvExcel = 'csv_excel'; - const csvPlain = 'csv_plain'; - - const [active, setActive] = useState(true); - const [selectedExport, setSelectedExport] = useState([]); - const [selectedExportAs, setSelectedExportAs] = useState([]); - - const handleModalChange = useCallback(() => setActive(!active), [active]); - - const handleClose = () => { - handleModalChange(); - handleSelectedExport([]); - handleSelectedExportAs([]); - }; - - const handleSelectedExport = useCallback( - (value) => setSelectedExport(value), - [], - ); - - const handleSelectedExportAs = useCallback( - (value) => setSelectedExportAs(value), - [], - ); - - const activator = ; - - return ( - -
- + + If you discard changes, you’ll delete any edits you made since you + last saved. + + +
+ + ); + }, +}; + +export const WithPrimaryAndSecondaryActions = { + render() { + const currentPage = 'current_page'; + const allCustomers = 'all_customers'; + const selectedCustomers = 'selected_customers'; + const csvExcel = 'csv_excel'; + const csvPlain = 'csv_plain'; + + const [active, setActive] = useState(true); + const [selectedExport, setSelectedExport] = useState([]); + const [selectedExportAs, setSelectedExportAs] = useState([]); + + const handleModalChange = useCallback(() => setActive(!active), [active]); + + const handleClose = () => { + handleModalChange(); + handleSelectedExport([]); + handleSelectedExportAs([]); + }; + + const handleSelectedExport = useCallback( + (value) => setSelectedExport(value), + [], + ); + + const handleSelectedExportAs = useCallback( + (value) => setSelectedExportAs(value), + [], + ); + + const activator = ; + + return ( + +
+ - - - - - - - - - - - -
- - ); -} + }} + secondaryActions={[ + { + content: 'Cancel', + onAction: handleClose, + }, + ]} + > + + + + + + + + + + +
+
+ + ); + }, +}; -export function Large() { - const [active, setActive] = useState(true); - const [checked, setChecked] = useState(false); +export const Large = { + render() { + const [active, setActive] = useState(true); + const [checked, setChecked] = useState(false); - const toggleActive = useCallback(() => setActive((active) => !active), []); + const toggleActive = useCallback(() => setActive((active) => !active), []); - const handleCheckbox = useCallback((value) => setChecked(value), []); + const handleCheckbox = useCallback((value) => setChecked(value), []); - const activator = ; + const activator = ; - return ( - -
- +
+ - - - {}} - > - - - - - - -
- - ); -} + }} + secondaryActions={[ + { + content: 'Cancel', + onAction: toggleActive, + }, + ]} + > + + + {}} + > + + + + + +
+
+ + ); + }, +}; -export function Small() { - const [active, setActive] = useState(true); - const [checked, setChecked] = useState(false); +export const Small = { + render() { + const [active, setActive] = useState(true); + const [checked, setChecked] = useState(false); - const toggleActive = useCallback(() => setActive((active) => !active), []); + const toggleActive = useCallback(() => setActive((active) => !active), []); - const handleCheckbox = useCallback((value) => setChecked(value), []); + const handleCheckbox = useCallback((value) => setChecked(value), []); - const activator = ; + const activator = ; - return ( - -
- +
+ - - - {}} - > - - - - - - -
- - ); -} - -export function WithoutATitle() { - const [active, setActive] = useState(true); - - const handleChange = useCallback(() => setActive(!active), [active]); - - const activator = ; + }} + secondaryActions={[ + { + content: 'Cancel', + onAction: toggleActive, + }, + ]} + > + + + {}} + > + + + + + +
+
+ + ); + }, +}; - return ( - -
- setActive(!active), [active]); + + const activator = ; + + return ( + +
+ - - - Use Instagram posts to share your products with millions of - people. Let shoppers buy from your store without leaving - Instagram. - - - -
- - ); -} + }} + secondaryActions={[ + { + content: 'Learn more', + onAction: handleChange, + }, + ]} + > + + + Use Instagram posts to share your products with millions of + people. Let shoppers buy from your store without leaving + Instagram. + + +
+
+ + ); + }, +}; -export function WithScrollListener() { - const [active, setActive] = useState(true); +export const WithScrollListener = { + render() { + const [active, setActive] = useState(true); + + const handleChange = useCallback(() => setActive(!active), [active]); + + const handleScrollBottom = useCallback( + () => console.log('Scrolled to bottom'), + [], + ); + + const activator = ; + + return ( + +
+ + {Array.from({length: 50}, (_, index) => ( + + + Item #{index} + + + ))} + +
+ + ); + }, +}; - const handleChange = useCallback(() => setActive(!active), [active]); +export const WithActivatorRef = { + render() { + const [active, setActive] = useState(true); - const handleScrollBottom = useCallback( - () => console.log('Scrolled to bottom'), - [], - ); + const buttonRef = useRef(null); - const activator = ; + const handleOpen = useCallback(() => setActive(true), []); - return ( - -
- - {Array.from({length: 50}, (_, index) => ( - + const handleClose = useCallback(() => { + setActive(false); + }, []); + + const activator = ( +
+ +
+ ); + + return ( + +
+ {activator} + + - Item #{index} + Use Instagram posts to share your products with millions of + people. Let shoppers buy from your store without leaving + Instagram. - ))} - -
- - ); -} - -export function WithActivatorRef() { - const [active, setActive] = useState(true); - - const buttonRef = useRef(null); - - const handleOpen = useCallback(() => setActive(true), []); - - const handleClose = useCallback(() => { - setActive(false); - }, []); +
+
+ + ); + }, +}; - const activator = ( -
- -
- ); +export const WithoutAnActivatorProp = { + render() { + const [active, setActive] = useState(true); + + const button = useRef(); + + const handleOpen = useCallback(() => setActive(true), []); + + const handleClose = useCallback(() => { + setActive(false); + requestAnimationFrame(() => + button.current.querySelector('button').focus(), + ); + }, []); + + return ( + +
+
+ +
+ + + + Use Instagram posts to share your products with millions of + people. Let shoppers buy from your store without leaving + Instagram. + + + +
+ + ); + }, +}; - return ( - -
- {activator} +export const WithLongContent = { + render() { + return ( + {}} + primaryAction={{content: 'Save'}} > - - Use Instagram posts to share your products with millions of - people. Let shoppers buy from your store without leaving - Instagram. - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
- - ); -} - -export function WithoutAnActivatorProp() { - const [active, setActive] = useState(true); - - const button = useRef(); - - const handleOpen = useCallback(() => setActive(true), []); - - const handleClose = useCallback(() => { - setActive(false); - requestAnimationFrame(() => button.current.querySelector('button').focus()); - }, []); + + ); + }, +}; - return ( - -
-
- -
+export const WithLongContentNoScroll = { + render() { + return ( + {}} + noScroll + primaryAction={{content: 'Save'}} > - - Use Instagram posts to share your products with millions of - people. Let shoppers buy from your store without leaving - Instagram. - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -
- - ); -} - -export function WithLongContent() { - return ( - - {}} - primaryAction={{content: 'Save'}} - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} - -export function WithLongContentNoScroll() { - return ( - - {}} - noScroll - primaryAction={{content: 'Save'}} - > - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} + + ); + }, +}; const context = { logo: undefined, @@ -639,97 +665,105 @@ const context = { setContextualSaveBar: () => {}, removeContextualSaveBar: () => {}, }; -export function EmbeddedIframe() { - return ( - -
- {}} - noScroll - primaryAction={{content: 'Save'}} - src={`data:text/html;charset=utf-8, - -
-

- Hello. -

-
`} - /> -
-
- ); -} - -export function SectionedProp() { - return ( - -
- {}} - sectioned - primaryAction={{content: 'Save'}} - > - First section - Second section - - Nested section - - Fourth section - -
- - ); -} - -export function Loading() { - return ( - -
- {}} - loading - primaryAction={{content: 'Save'}} - > - First section - Second section - Third section - -
- - ); -} - -export function Fullscreen() { - return ( - -
- {}} - sectioned - size="fullScreen" - primaryAction={{content: 'Save'}} - > - Fullscreen on small displays - - When (max-width: 47.9975em), the modal will be made{' '} - height: 100% - - -
- - ); -} +export const EmbeddedIframe = { + render() { + return ( + +
+ {}} + noScroll + primaryAction={{content: 'Save'}} + src={`data:text/html;charset=utf-8, + +
+

+ Hello. +

+
`} + /> +
+
+ ); + }, +}; + +export const SectionedProp = { + render() { + return ( + +
+ {}} + sectioned + primaryAction={{content: 'Save'}} + > + First section + Second section + + Nested section + + Fourth section + +
+ + ); + }, +}; + +export const Loading = { + render() { + return ( + +
+ {}} + loading + primaryAction={{content: 'Save'}} + > + First section + Second section + Third section + +
+ + ); + }, +}; + +export const Fullscreen = { + render() { + return ( + +
+ {}} + sectioned + size="fullScreen" + primaryAction={{content: 'Save'}} + > + Fullscreen on small displays + + When (max-width: 47.9975em), the modal will be made{' '} + height: 100% + + +
+ + ); + }, +}; diff --git a/polaris-react/src/components/Navigation/Navigation.stories.tsx b/polaris-react/src/components/Navigation/Navigation.stories.tsx index c9c8831ec89..39c937d790f 100644 --- a/polaris-react/src/components/Navigation/Navigation.stories.tsx +++ b/polaris-react/src/components/Navigation/Navigation.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Frame, Navigation, Text} from '@shopify/polaris'; import { MinusCircleIcon, @@ -24,1412 +24,1449 @@ import { export default { component: Navigation, parameters: {layout: 'fullscreen'}, -} as ComponentMeta; +} as Meta; -export function Default() { - const [selected, setSelected] = React.useState('home'); +export const Default = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - badge: '15', - matches: selected === 'orders', - onClick: () => setSelected('orders'), - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - matches: selected === 'products', - onClick: () => setSelected('products'), - }, - ]} - /> - - - ); -} + return ( + + + setSelected('home'), + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + badge: '15', + matches: selected === 'orders', + onClick: () => setSelected('orders'), + }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + matches: selected === 'products', + onClick: () => setSelected('products'), + }, + ]} + /> + + + ); + }, +}; -export function DisabledItemsWithoutUrls() { - return ( - - - - - - ); -} +export const DisabledItemsWithoutUrls = { + render() { + return ( + + + + + + ); + }, +}; -export function WithMultipleSecondaryNavigations() { - const [selected, setSelected] = React.useState('home'); +export const WithMultipleSecondaryNavigations = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - label: 'Orders', - icon: OrderFilledIcon, - matchedItemIcon: OrderIcon, - badge: '15', - onClick: () => setSelected('orders'), - matches: selected === 'orders', - subNavigationItems: [ - { - url: '#', - disabled: false, - label: 'Drafts', - onClick: () => setSelected('drafts'), - matches: selected === 'drafts', - }, - { - url: '#', - disabled: false, - label: 'Shipping Labels', - onClick: () => setSelected('shippinglabels'), - matches: selected === 'shippinglabels', - }, - ], - }, - { - url: '#', - label: 'Products', - icon: ProductFilledIcon, - matchedItemIcon: ProductIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Inventory', - onClick: () => setSelected('inventory'), - matches: selected === 'inventory', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Transfers', - onClick: () => setSelected('transfers'), - matches: selected === 'transfers', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Collections', - onClick: () => setSelected('collections'), - matches: selected === 'collections', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Gift cards', - onClick: () => setSelected('giftcards'), - matches: selected === 'giftcards', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Price lists', - onClick: () => setSelected('pricelists'), - matches: selected === 'pricelists', - }, - ], - }, - { - url: '#', - label: 'Marketing', - icon: TargetFilledIcon, - matchedItemIcon: TargetIcon, - onClick: () => setSelected('marketing'), - matches: selected === 'marketing', - subNavigationItems: [ - { - url: '#', - disabled: false, - label: 'Reports', - onClick: () => setSelected('reports'), - matches: selected === 'reports', - }, - { - url: '#', - disabled: false, - label: 'Live view', - onClick: () => setSelected('liveView'), - matches: selected === 'liveView', - }, - ], - }, - ]} - /> - - - ); -} - -export function WithAnActiveRootItemWithSecondaryNavigationItems() { - const [selected, setSelected] = React.useState('home'); - - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - badge: '15', - onClick: () => setSelected('orders'), - matches: selected === 'orders', - }, - { - url: '#', - label: 'Products', - icon: ProductIcon, - selected: true, - onClick: () => setSelected('products'), - matches: selected === 'products', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Inventory', - onClick: () => setSelected('inventory'), - matches: selected === 'inventory', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Transfers', - onClick: () => setSelected('transfers'), - matches: selected === 'transfers', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Collections', - onClick: () => setSelected('collections'), - matches: selected === 'collections', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Gift cards', - onClick: () => setSelected('giftcards'), - matches: selected === 'giftcards', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Price lists', - onClick: () => setSelected('pricelists'), - matches: selected === 'pricelists', - }, - ], - }, - ]} - /> - - - ); -} + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + label: 'Orders', + icon: OrderFilledIcon, + matchedItemIcon: OrderIcon, + badge: '15', + onClick: () => setSelected('orders'), + matches: selected === 'orders', + subNavigationItems: [ + { + url: '#', + disabled: false, + label: 'Drafts', + onClick: () => setSelected('drafts'), + matches: selected === 'drafts', + }, + { + url: '#', + disabled: false, + label: 'Shipping Labels', + onClick: () => setSelected('shippinglabels'), + matches: selected === 'shippinglabels', + }, + ], + }, + { + url: '#', + label: 'Products', + icon: ProductFilledIcon, + matchedItemIcon: ProductIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Inventory', + onClick: () => setSelected('inventory'), + matches: selected === 'inventory', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Transfers', + onClick: () => setSelected('transfers'), + matches: selected === 'transfers', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Collections', + onClick: () => setSelected('collections'), + matches: selected === 'collections', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Gift cards', + onClick: () => setSelected('giftcards'), + matches: selected === 'giftcards', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Price lists', + onClick: () => setSelected('pricelists'), + matches: selected === 'pricelists', + }, + ], + }, + { + url: '#', + label: 'Marketing', + icon: TargetFilledIcon, + matchedItemIcon: TargetIcon, + onClick: () => setSelected('marketing'), + matches: selected === 'marketing', + subNavigationItems: [ + { + url: '#', + disabled: false, + label: 'Reports', + onClick: () => setSelected('reports'), + matches: selected === 'reports', + }, + { + url: '#', + disabled: false, + label: 'Live view', + onClick: () => setSelected('liveView'), + matches: selected === 'liveView', + }, + ], + }, + ]} + /> + + + ); + }, +}; -export function WithASecondaryActionForASectionAndASectionTitle() { - const [selected, setSelected] = React.useState('home'); +export const WithAnActiveRootItemWithSecondaryNavigationItems = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - onClick: () => setSelected('orders'), - matches: selected === 'orders', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - }, - ]} - /> - {}, - }} - /> - - - ); -} + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + badge: '15', + onClick: () => setSelected('orders'), + matches: selected === 'orders', + }, + { + url: '#', + label: 'Products', + icon: ProductIcon, + selected: true, + onClick: () => setSelected('products'), + matches: selected === 'products', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Inventory', + onClick: () => setSelected('inventory'), + matches: selected === 'inventory', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Transfers', + onClick: () => setSelected('transfers'), + matches: selected === 'transfers', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Collections', + onClick: () => setSelected('collections'), + matches: selected === 'collections', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Gift cards', + onClick: () => setSelected('giftcards'), + matches: selected === 'giftcards', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Price lists', + onClick: () => setSelected('pricelists'), + matches: selected === 'pricelists', + }, + ], + }, + ]} + /> + + + ); + }, +}; -export function WithASecondaryActionForAnItem() { - const [selected, setSelected] = React.useState('home'); +export const WithASecondaryActionForASectionAndASectionTitle = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - onClick: () => setSelected('orders'), - matches: selected === 'orders', - secondaryAction: { - url: '#', - accessibilityLabel: 'Add an order', - icon: PlusCircleIcon, - tooltip: { - content: 'Add an order', - }, + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + onClick: () => setSelected('orders'), + matches: selected === 'orders', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', }, - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - }, - ]} - /> - - - ); -} + ]} + /> + {}, + }} + /> + + + ); + }, +}; -export function WithMultipleSecondaryActionsForAnItem() { - const [selected, setSelected] = React.useState('home'); +export const WithASecondaryActionForAnItem = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - badge: '123', - onClick: () => setSelected('orders'), - matches: selected === 'orders', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - badge: '2', - onClick: () => setSelected('products'), - matches: selected === 'products', - secondaryActions: [ - { + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + onClick: () => setSelected('orders'), + matches: selected === 'orders', + secondaryAction: { url: '#', - accessibilityLabel: 'Add a product', + accessibilityLabel: 'Add an order', icon: PlusCircleIcon, tooltip: { - content: 'Add a product', + content: 'Add an order', }, }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'Long multi-line label', - icon: PlusIcon, - badge: '125', - onClick: () => setSelected('longMultiLineLabel'), - matches: selected === 'longMultiLineLabel', - secondaryActions: [ - { - url: '#', - accessibilityLabel: 'Add a product', - icon: PlusCircleIcon, - tooltip: { - content: 'Add a product', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', + }, + ]} + /> + + + ); + }, +}; + +export const WithMultipleSecondaryActionsForAnItem = { + render() { + const [selected, setSelected] = React.useState('home'); + + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + badge: '123', + onClick: () => setSelected('orders'), + matches: selected === 'orders', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + badge: '2', + onClick: () => setSelected('products'), + matches: selected === 'products', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'Add a product', + icon: PlusCircleIcon, + tooltip: { + content: 'Add a product', + }, }, - }, - { - accessibilityLabel: 'Remove a product', - icon: MinusCircleIcon, - onClick: () => {}, - tooltip: { - content: 'Remove a product', + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'Long multi-line label', + icon: PlusIcon, + badge: '125', + onClick: () => setSelected('longMultiLineLabel'), + matches: selected === 'longMultiLineLabel', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'Add a product', + icon: PlusCircleIcon, + tooltip: { + content: 'Add a product', + }, }, - }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'Long truncated single-line text label', - icon: PlusIcon, - truncateText: true, - onClick: () => setSelected('longTruncatedSingleLineTextLabel'), - matches: selected === 'longTruncatedSingleLineTextLabel', - secondaryActions: [ - { - url: '#', - accessibilityLabel: 'Add a product', - icon: PlusCircleIcon, - tooltip: { - content: 'Add a product', + { + accessibilityLabel: 'Remove a product', + icon: MinusCircleIcon, + onClick: () => {}, + tooltip: { + content: 'Remove a product', + }, }, - }, - { - accessibilityLabel: 'Remove a product', - icon: MinusCircleIcon, - onClick: () => { - console.log('plus clicked'); + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'Long truncated single-line text label', + icon: PlusIcon, + truncateText: true, + onClick: () => setSelected('longTruncatedSingleLineTextLabel'), + matches: selected === 'longTruncatedSingleLineTextLabel', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'Add a product', + icon: PlusCircleIcon, + tooltip: { + content: 'Add a product', + }, }, - tooltip: { - content: 'Remove a product', + { + accessibilityLabel: 'Remove a product', + icon: MinusCircleIcon, + onClick: () => { + console.log('plus clicked'); + }, + tooltip: { + content: 'Remove a product', + }, }, - }, - ], - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'New item', - onClick: () => setSelected('newItem'), - matches: selected === 'newItem', - }, - ], - }, - { - url: '#', - label: 'Floating actions on multi-line text label', - icon: PlusIcon, - badge: '15', - displayActionsOnHover: true, - onClick: () => setSelected('floatingActionsOnMultiLineTextLabel'), - matches: selected === 'floatingActionsOnMultiLineTextLabel', - secondaryActions: [ - { - url: '#', - accessibilityLabel: 'Add a product', - icon: PlusCircleIcon, - tooltip: { - content: 'Add a product', + ], + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'New item', + onClick: () => setSelected('newItem'), + matches: selected === 'newItem', }, - }, - { - accessibilityLabel: 'Remove a product', - icon: MinusCircleIcon, - onClick: () => { - console.log('minor clicked'); + ], + }, + { + url: '#', + label: 'Floating actions on multi-line text label', + icon: PlusIcon, + badge: '15', + displayActionsOnHover: true, + onClick: () => + setSelected('floatingActionsOnMultiLineTextLabel'), + matches: selected === 'floatingActionsOnMultiLineTextLabel', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'Add a product', + icon: PlusCircleIcon, + tooltip: { + content: 'Add a product', + }, }, - tooltip: { - content: 'Remove a product', + { + accessibilityLabel: 'Remove a product', + icon: MinusCircleIcon, + onClick: () => { + console.log('minor clicked'); + }, + tooltip: { + content: 'Remove a product', + }, }, - }, - ], - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Collections', - onClick: () => setSelected('collections'), - matches: selected === 'collections', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Inventory', - onClick: () => setSelected('inventory'), - matches: selected === 'inventory', - }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'Floating actions on truncated single-line text label', - icon: PlusIcon, - badge: '15', - truncateText: true, - displayActionsOnHover: true, - onClick: () => - setSelected('floatingActionsOnTruncatedSingleLineTextLabel'), - matches: - selected === 'floatingActionsOnTruncatedSingleLineTextLabel', - secondaryActions: [ - { - url: '#', - accessibilityLabel: 'Add a product', - icon: PlusCircleIcon, - tooltip: { - content: 'Add a product', + ], + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Collections', + onClick: () => setSelected('collections'), + matches: selected === 'collections', }, - }, - { - url: '', - accessibilityLabel: 'Remove a product', - icon: MinusCircleIcon, - onClick: () => {}, - tooltip: { - content: 'Remove a product', + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Inventory', + onClick: () => setSelected('inventory'), + matches: selected === 'inventory', }, - }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'One floating action on multi-line text label', - icon: PlusIcon, - displayActionsOnHover: true, - onClick: () => - setSelected('oneFloatingActionOnMultiLineTextLabel'), - matches: selected === 'oneFloatingActionOnMultiLineTextLabel', - secondaryActions: [ - { + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'Floating actions on truncated single-line text label', + icon: PlusIcon, + badge: '15', + truncateText: true, + displayActionsOnHover: true, + onClick: () => + setSelected('floatingActionsOnTruncatedSingleLineTextLabel'), + matches: + selected === 'floatingActionsOnTruncatedSingleLineTextLabel', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'Add a product', + icon: PlusCircleIcon, + tooltip: { + content: 'Add a product', + }, + }, + { + url: '', + accessibilityLabel: 'Remove a product', + icon: MinusCircleIcon, + onClick: () => {}, + tooltip: { + content: 'Remove a product', + }, + }, + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'One floating action on multi-line text label', + icon: PlusIcon, + displayActionsOnHover: true, + onClick: () => + setSelected('oneFloatingActionOnMultiLineTextLabel'), + matches: selected === 'oneFloatingActionOnMultiLineTextLabel', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'Add a product', + icon: PlusCircleIcon, + tooltip: { + content: 'Add a product', + }, + }, + ], + }, + { + url: '#', + excludePaths: ['#'], + label: + 'One floating action on truncated single-line text label', + icon: PlusIcon, + badge: '15', + truncateText: true, + displayActionsOnHover: true, + onClick: () => + setSelected( + 'oneFloatingActionOnTruncatedSingleLineTextLabel', + ), + matches: + selected === + 'oneFloatingActionOnTruncatedSingleLineTextLabel', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'Add a product', + icon: PlusCircleIcon, + tooltip: { + content: 'Add a product', + }, + }, + ], + }, + { + url: '#', + label: 'Marketing', + icon: TargetIcon, + badge: '15', + selected: true, + onClick: () => setSelected('marketing'), + matches: selected === 'marketing', + secondaryActions: [ + { + url: '#', + accessibilityLabel: 'View campaign', + icon: ViewIcon, + tooltip: { + content: 'View campaign', + }, + }, + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'Logout', + icon: ExitIcon, + onClick: () => setSelected('logout'), + matches: selected === 'logout', + }, + ]} + /> + + + ); + }, +}; + +export const WithTruncationForVariousStates = { + render() { + const [selected, setSelected] = React.useState('longlabel'); + + return ( + + + setSelected('longlabel'), + matches: selected === 'longlabel', + }, + { + url: '#', + label: 'Not truncated', + icon: OrderIcon, + selected: false, + onClick: () => setSelected('nottruncated'), + matches: selected === 'nottruncated', + }, + { + url: '#', + label: 'Lengthy label with secondary action', + icon: OrderIcon, + selected: false, + truncateText: true, + onClick: () => setSelected('lengthylabelwithsecondaryaction'), + matches: selected === 'lengthylabelwithsecondaryaction', + secondaryAction: { url: '#', - accessibilityLabel: 'Add a product', + accessibilityLabel: 'Add an order', icon: PlusCircleIcon, tooltip: { - content: 'Add a product', + content: 'Add a lengthy order', }, }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'One floating action on truncated single-line text label', - icon: PlusIcon, - badge: '15', - truncateText: true, - displayActionsOnHover: true, - onClick: () => - setSelected('oneFloatingActionOnTruncatedSingleLineTextLabel'), - matches: - selected === 'oneFloatingActionOnTruncatedSingleLineTextLabel', - secondaryActions: [ - { + }, + { + url: '#', + label: 'Lengthy non-truncated label with secondary action', + icon: OrderIcon, + selected: false, + onClick: () => + setSelected('lengthynontruncatedlabelwithsecondaryaction'), + matches: + selected === 'lengthynontruncatedlabelwithsecondaryaction', + secondaryAction: { url: '#', - accessibilityLabel: 'Add a product', + accessibilityLabel: 'Add an order', icon: PlusCircleIcon, tooltip: { - content: 'Add a product', + content: 'Add a lengthy order', }, }, - ], - }, - { - url: '#', - label: 'Marketing', - icon: TargetIcon, - badge: '15', - selected: true, - onClick: () => setSelected('marketing'), - matches: selected === 'marketing', - secondaryActions: [ - { + }, + { + url: '#', + excludePaths: ['#'], + label: 'Lengthy label with badge', + truncateText: true, + badge: 'Old', + icon: HomeIcon, + onClick: () => setSelected('lengthylabelwithbadge'), + matches: selected === 'lengthylabelwithbadge', + }, + { + url: '#', + label: 'Lengthy label with secondary action', + icon: OrderIcon, + selected: false, + truncateText: true, + badge: 'Old', + onClick: () => setSelected('lengthylabelwithsecondaryaction'), + matches: selected === 'lengthylabelwithsecondaryaction', + secondaryAction: { url: '#', - accessibilityLabel: 'View campaign', - icon: ViewIcon, + accessibilityLabel: 'Add an order', + icon: PlusCircleIcon, tooltip: { - content: 'View campaign', + content: 'Add a lengthy order', }, }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'Logout', - icon: ExitIcon, - onClick: () => setSelected('logout'), - matches: selected === 'logout', - }, - ]} - /> - - - ); -} + }, + { + url: '#', + label: 'Truncated secondary navigation items', + icon: ProductIcon, + selected: true, + truncateText: true, + onClick: () => setSelected('truncatedsecondarynavigationitems'), + matches: selected === 'truncatedsecondarynavigationitems', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Something longer than collections', + onClick: () => setSelected('somethinglonger'), + matches: selected === 'somethinglonger', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Inventory', + onClick: () => setSelected('inventory'), + matches: selected === 'inventory', + }, + ], + }, + ]} + /> + + + ); + }, +}; -export function WithTruncationForVariousStates() { - const [selected, setSelected] = React.useState('longlabel'); +export const WithSectionRollup = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('longlabel'), - matches: selected === 'longlabel', - }, - { - url: '#', - label: 'Not truncated', - icon: OrderIcon, - selected: false, - onClick: () => setSelected('nottruncated'), - matches: selected === 'nottruncated', - }, - { - url: '#', - label: 'Lengthy label with secondary action', - icon: OrderIcon, - selected: false, - truncateText: true, - onClick: () => setSelected('lengthylabelwithsecondaryaction'), - matches: selected === 'lengthylabelwithsecondaryaction', - secondaryAction: { - url: '#', - accessibilityLabel: 'Add an order', - icon: PlusCircleIcon, - tooltip: { - content: 'Add a lengthy order', - }, + return ( + + + setSelected('home'), + matches: selected === 'home', }, - }, - { - url: '#', - label: 'Lengthy non-truncated label with secondary action', - icon: OrderIcon, - selected: false, - onClick: () => - setSelected('lengthynontruncatedlabelwithsecondaryaction'), - matches: - selected === 'lengthynontruncatedlabelwithsecondaryaction', - secondaryAction: { - url: '#', - accessibilityLabel: 'Add an order', - icon: PlusCircleIcon, - tooltip: { - content: 'Add a lengthy order', - }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + onClick: () => setSelected('orders'), + matches: selected === 'orders', }, - }, - { - url: '#', - excludePaths: ['#'], - label: 'Lengthy label with badge', - truncateText: true, - badge: 'Old', - icon: HomeIcon, - onClick: () => setSelected('lengthylabelwithbadge'), - matches: selected === 'lengthylabelwithbadge', - }, - { - url: '#', - label: 'Lengthy label with secondary action', - icon: OrderIcon, - selected: false, - truncateText: true, - badge: 'Old', - onClick: () => setSelected('lengthylabelwithsecondaryaction'), - matches: selected === 'lengthylabelwithsecondaryaction', - secondaryAction: { - url: '#', - accessibilityLabel: 'Add an order', - icon: PlusCircleIcon, - tooltip: { - content: 'Add a lengthy order', - }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', }, - }, - { - url: '#', - label: 'Truncated secondary navigation items', - icon: ProductIcon, - selected: true, - truncateText: true, - onClick: () => setSelected('truncatedsecondarynavigationitems'), - matches: selected === 'truncatedsecondarynavigationitems', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Something longer than collections', - onClick: () => setSelected('somethinglonger'), - matches: selected === 'somethinglonger', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Inventory', - onClick: () => setSelected('inventory'), - matches: selected === 'inventory', - }, - ], - }, - ]} - /> - - - ); -} + ]} + rollup={{ + after: 2, + view: 'view', + hide: 'hide', + activePath: '/', + }} + /> + + + ); + }, +}; -export function WithSectionRollup() { - const [selected, setSelected] = React.useState('home'); +export const WithSectionSeparator = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - onClick: () => setSelected('orders'), - matches: selected === 'orders', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - }, - ]} - rollup={{ - after: 2, - view: 'view', - hide: 'hide', - activePath: '/', - }} - /> - - - ); -} - -export function WithSectionSeparator() { - const [selected, setSelected] = React.useState('home'); - - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - onClick: () => setSelected('orders'), - matches: selected === 'orders', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - }, - ]} - /> - setSelected('onlinestore'), - matches: selected === 'onlinestore', - }, - ]} - separator - /> - - - ); -} + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + onClick: () => setSelected('orders'), + matches: selected === 'orders', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', + }, + ]} + /> + setSelected('onlinestore'), + matches: selected === 'onlinestore', + }, + ]} + separator + /> + + + ); + }, +}; -export function WithVariousStatesAndSecondaryElements() { - const [selected, setSelected] = React.useState('home'); +export const WithVariousStatesAndSecondaryElements = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Item with indicator', - icon: HomeIcon, - onClick: () => setSelected('itemwithindicator'), - matches: selected === 'itemwithindicator', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - new: true, - label: 'New item', - onClick: () => setSelected('newitem'), - matches: selected === 'newitem', - }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'New item', - new: true, - icon: HomeIcon, - onClick: () => setSelected('newitem2'), - matches: selected === 'newitem2', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Badged item', - badge: 'Old', - icon: HomeIcon, - onClick: () => setSelected('badgeditem'), - matches: selected === 'badgeditem', - }, - { - url: '#', - label: 'Active with secondary action', - icon: OrderIcon, - selected: true, - onClick: () => setSelected('activewithsecondaryaction'), - matches: selected === 'activewithsecondaryaction', - secondaryAction: { - url: '#', - accessibilityLabel: 'Add an order', - icon: PlusCircleIcon, - tooltip: { - content: 'Add an order', - }, + return ( + + + setSelected('home'), + matches: selected === 'home', }, - }, - { - url: window.location.href, - label: 'Active item with sub navigation', - icon: ProductIcon, - selected: true, - onClick: () => setSelected('activeitemwithsubnavigation'), - matches: selected === 'activeitemwithsubnavigation', - subNavigationItems: [ - { - url: window.location.href, - selected: true, - disabled: false, - label: 'Selected sub item', - onClick: () => setSelected('selectedsubitem'), - matches: selected === 'selectedsubitem', - }, - { + { + url: '#', + excludePaths: ['#'], + label: 'Item with indicator', + icon: HomeIcon, + onClick: () => setSelected('itemwithindicator'), + matches: selected === 'itemwithindicator', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + new: true, + label: 'New item', + onClick: () => setSelected('newitem'), + matches: selected === 'newitem', + }, + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'New item', + new: true, + icon: HomeIcon, + onClick: () => setSelected('newitem2'), + matches: selected === 'newitem2', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Badged item', + badge: 'Old', + icon: HomeIcon, + onClick: () => setSelected('badgeditem'), + matches: selected === 'badgeditem', + }, + { + url: '#', + label: 'Active with secondary action', + icon: OrderIcon, + selected: true, + onClick: () => setSelected('activewithsecondaryaction'), + matches: selected === 'activewithsecondaryaction', + secondaryAction: { url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Default sub item', - onClick: () => setSelected('defaultsubitem'), - matches: selected === 'defaultsubitem', + accessibilityLabel: 'Add an order', + icon: PlusCircleIcon, + tooltip: { + content: 'Add an order', + }, }, - { + }, + { + url: window.location.href, + label: 'Active item with sub navigation', + icon: ProductIcon, + selected: true, + onClick: () => setSelected('activeitemwithsubnavigation'), + matches: selected === 'activeitemwithsubnavigation', + subNavigationItems: [ + { + url: window.location.href, + selected: true, + disabled: false, + label: 'Selected sub item', + onClick: () => setSelected('selectedsubitem'), + matches: selected === 'selectedsubitem', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Default sub item', + onClick: () => setSelected('defaultsubitem'), + matches: selected === 'defaultsubitem', + }, + { + url: '#', + excludePaths: ['#'], + disabled: true, + label: 'Disabled sub item', + }, + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'Disabled item', + icon: PersonIcon, + disabled: true, + }, + { + url: '#', + label: 'Overflow item', + icon: TargetIcon, + onClick: () => setSelected('overflowitem'), + matches: selected === 'overflowitem', + }, + ]} + rollup={{ + after: 7, + view: 'view', + hide: 'hide', + activePath: '/', + }} + /> + ', + }, + { + url: '#', + label: 'Icon as img – Active', + icon: '', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Other secondary action', + icon: '', + secondaryAction: { url: '#', - excludePaths: ['#'], - disabled: true, - label: 'Disabled sub item', - }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'Disabled item', - icon: PersonIcon, - disabled: true, - }, - { - url: '#', - label: 'Overflow item', - icon: TargetIcon, - onClick: () => setSelected('overflowitem'), - matches: selected === 'overflowitem', - }, - ]} - rollup={{ - after: 7, - view: 'view', - hide: 'hide', - activePath: '/', - }} - /> - ', - }, - { - url: '#', - label: 'Icon as img – Active', - icon: '', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Other secondary action', - icon: '', - secondaryAction: { - url: '#', - accessibilityLabel: 'View your online store', - icon: ViewIcon, - tooltip: { - content: 'View your online store', + accessibilityLabel: 'View your online store', + icon: ViewIcon, + tooltip: { + content: 'View your online store', + }, }, }, - }, - { - url: '#', - excludePaths: ['#'], - label: 'Square app-like icon', - icon: '', - shouldResizeIcon: true, - secondaryAction: { - url: '#', - accessibilityLabel: 'View your online store', - icon: ViewIcon, - tooltip: { - content: 'View your online store', + { + url: '#', + excludePaths: ['#'], + label: 'Square app-like icon', + icon: '', + shouldResizeIcon: true, + secondaryAction: { + url: '#', + accessibilityLabel: 'View your online store', + icon: ViewIcon, + tooltip: { + content: 'View your online store', + }, }, }, - }, - ]} - action={{ - accessibilityLabel: 'Add sales channel', - icon: PlusCircleIcon, - onClick: () => {}, - }} - separator - /> - - - ); -} + ]} + action={{ + accessibilityLabel: 'Add sales channel', + icon: PlusCircleIcon, + onClick: () => {}, + }} + separator + /> + + + ); + }, +}; -export function WithAriaLabelledby() { - const [selected, setSelected] = React.useState('home'); +export const WithAriaLabelledby = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - - Hidden label - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - badge: '15', - onClick: () => setSelected('orders'), - matches: selected === 'orders', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - }, - ]} - /> - - - ); -} + return ( + + + + Hidden label + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + badge: '15', + onClick: () => setSelected('orders'), + matches: selected === 'orders', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', + }, + ]} + /> + + + ); + }, +}; -export function UsingIconIcons() { - const [selected, setSelected] = React.useState('home'); +export const UsingIconIcons = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - badge: '15', - onClick: () => setSelected('orders'), - matches: selected === 'orders', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Products', - icon: ProductIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Customers', - icon: PersonIcon, - onClick: () => setSelected('customers'), - matches: selected === 'customers', - }, - ]} - /> - - - ); -} + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + badge: '15', + onClick: () => setSelected('orders'), + matches: selected === 'orders', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Products', + icon: ProductIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Customers', + icon: PersonIcon, + onClick: () => setSelected('customers'), + matches: selected === 'customers', + }, + ]} + /> + + + ); + }, +}; -export function WithBadgeAndSecondaryAction() { - const [selected, setSelected] = React.useState('home'); +export const WithBadgeAndSecondaryAction = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - secondaryAction: { - url: '#', - accessibilityLabel: 'View your online store', - icon: ViewIcon, - tooltip: { - content: 'View your online store', - }, - }, - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: OrderIcon, - badge: '15', - onClick: () => setSelected('orders'), - matches: selected === 'orders', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Drafts', - onClick: () => setSelected('drafts'), - matches: selected === 'drafts', - }, - { + return ( + + + setSelected('home'), + matches: selected === 'home', + secondaryAction: { url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Shipping labels', - onClick: () => setSelected('shippinglabels'), - matches: selected === 'shippinglabels', - }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'Marketing', - icon: TargetIcon, - badge: '15', - onClick: () => setSelected('marketing'), - matches: selected === 'marketing', - secondaryAction: { - url: '#', - accessibilityLabel: 'View your online store', - icon: ViewIcon, - tooltip: { - content: 'View your online store', + accessibilityLabel: 'View your online store', + icon: ViewIcon, + tooltip: { + content: 'View your online store', + }, }, }, - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Reports', - onClick: () => setSelected('reports'), - matches: selected === 'reports', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Live view', - onClick: () => setSelected('liveView'), - matches: selected === 'liveView', - }, - ], - }, - { - url: '#', - label: 'Products', - icon: ProductIcon, - selected: true, - onClick: () => setSelected('products'), - matches: selected === 'products', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Collections', - onClick: () => setSelected('collections'), - matches: selected === 'collections', - }, - { + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: OrderIcon, + badge: '15', + onClick: () => setSelected('orders'), + matches: selected === 'orders', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Drafts', + onClick: () => setSelected('drafts'), + matches: selected === 'drafts', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Shipping labels', + onClick: () => setSelected('shippinglabels'), + matches: selected === 'shippinglabels', + }, + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'Marketing', + icon: TargetIcon, + badge: '15', + onClick: () => setSelected('marketing'), + matches: selected === 'marketing', + secondaryAction: { url: '#', - disabled: false, - label: 'Inventory', - onClick: () => setSelected('inventory'), - matches: selected === 'inventory', + accessibilityLabel: 'View your online store', + icon: ViewIcon, + tooltip: { + content: 'View your online store', + }, }, - ], - }, - ]} - /> - - - ); -} + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Reports', + onClick: () => setSelected('reports'), + matches: selected === 'reports', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Live view', + onClick: () => setSelected('liveView'), + matches: selected === 'liveView', + }, + ], + }, + { + url: '#', + label: 'Products', + icon: ProductIcon, + selected: true, + onClick: () => setSelected('products'), + matches: selected === 'products', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Collections', + onClick: () => setSelected('collections'), + matches: selected === 'collections', + }, + { + url: '#', + disabled: false, + label: 'Inventory', + onClick: () => setSelected('inventory'), + matches: selected === 'inventory', + }, + ], + }, + ]} + /> + + + ); + }, +}; -export function ItemWithMatchedIcon() { - const [selected, setSelected] = React.useState('home'); +export const ItemWithMatchedIcon = { + render() { + const [selected, setSelected] = React.useState('home'); - return ( - - - setSelected('home'), - matches: selected === 'home', - }, - { - url: '#', - excludePaths: ['#'], - label: 'Orders', - icon: StarFilledIcon, - matchedItemIcon: StarIcon, - badge: '15', - onClick: () => setSelected('orders'), - matches: selected === 'orders', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Drafts', - onClick: () => setSelected('drafts'), - matches: selected === 'drafts', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Shipping labels', - onClick: () => setSelected('shippinglabels'), - matches: selected === 'shippinglabels', - }, - ], - }, - { - url: '#', - excludePaths: ['#'], - label: 'Marketing', - icon: StarFilledIcon, - matchedItemIcon: StarIcon, - onClick: () => setSelected('marketing'), - matches: selected === 'marketing', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Reports', - onClick: () => setSelected('reports'), - matches: selected === 'reports', - }, - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Live view', - onClick: () => setSelected('liveView'), - matches: selected === 'liveView', - }, - ], - }, - { - url: '#', - label: 'Products', - icon: StarFilledIcon, - matchedItemIcon: StarIcon, - onClick: () => setSelected('products'), - matches: selected === 'products', - subNavigationItems: [ - { - url: '#', - excludePaths: ['#'], - disabled: false, - label: 'Collections', - onClick: () => setSelected('collections'), - matches: selected === 'collections', - }, - { - url: '#', - disabled: false, - label: 'Inventory', - onClick: () => setSelected('inventory'), - matches: selected === 'inventory', - }, - ], - }, - ]} - /> - - - ); -} + return ( + + + setSelected('home'), + matches: selected === 'home', + }, + { + url: '#', + excludePaths: ['#'], + label: 'Orders', + icon: StarFilledIcon, + matchedItemIcon: StarIcon, + badge: '15', + onClick: () => setSelected('orders'), + matches: selected === 'orders', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Drafts', + onClick: () => setSelected('drafts'), + matches: selected === 'drafts', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Shipping labels', + onClick: () => setSelected('shippinglabels'), + matches: selected === 'shippinglabels', + }, + ], + }, + { + url: '#', + excludePaths: ['#'], + label: 'Marketing', + icon: StarFilledIcon, + matchedItemIcon: StarIcon, + onClick: () => setSelected('marketing'), + matches: selected === 'marketing', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Reports', + onClick: () => setSelected('reports'), + matches: selected === 'reports', + }, + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Live view', + onClick: () => setSelected('liveView'), + matches: selected === 'liveView', + }, + ], + }, + { + url: '#', + label: 'Products', + icon: StarFilledIcon, + matchedItemIcon: StarIcon, + onClick: () => setSelected('products'), + matches: selected === 'products', + subNavigationItems: [ + { + url: '#', + excludePaths: ['#'], + disabled: false, + label: 'Collections', + onClick: () => setSelected('collections'), + matches: selected === 'collections', + }, + { + url: '#', + disabled: false, + label: 'Inventory', + onClick: () => setSelected('inventory'), + matches: selected === 'inventory', + }, + ], + }, + ]} + /> + + + ); + }, +}; -export function ItemsWithoutUrl() { - const [selected, setSelected] = React.useState('all'); +export const ItemsWithoutUrl = { + render() { + const [selected, setSelected] = React.useState('all'); - return ( - - - setSelected('all'), - }, - { - label: 'Announcements', - selected: selected === 'announcements', - onClick: () => setSelected('announcements'), - }, - { - label: 'Holidays and occasions', - selected: selected === 'holidays', - onClick: () => setSelected('holidays'), - }, - { - label: 'Newsletters', - selected: selected === 'newsletters', - onClick: () => setSelected('newsletters'), - }, - { - label: 'Product highlights', - selected: selected === 'productHighlights', - onClick: () => setSelected('productHighlights'), - }, - { - label: 'Promotions', - selected: selected === 'promotions', - onClick: () => setSelected('promotions'), - disabled: true, - }, - ]} - /> - setSelected('yourTemplates'), - }, - { - label: 'Recent emails', - selected: selected === 'recentEmails', - onClick: () => setSelected('recentEmails'), - }, - ]} - /> - - - ); -} + return ( + + + setSelected('all'), + }, + { + label: 'Announcements', + selected: selected === 'announcements', + onClick: () => setSelected('announcements'), + }, + { + label: 'Holidays and occasions', + selected: selected === 'holidays', + onClick: () => setSelected('holidays'), + }, + { + label: 'Newsletters', + selected: selected === 'newsletters', + onClick: () => setSelected('newsletters'), + }, + { + label: 'Product highlights', + selected: selected === 'productHighlights', + onClick: () => setSelected('productHighlights'), + }, + { + label: 'Promotions', + selected: selected === 'promotions', + onClick: () => setSelected('promotions'), + disabled: true, + }, + ]} + /> + setSelected('yourTemplates'), + }, + { + label: 'Recent emails', + selected: selected === 'recentEmails', + onClick: () => setSelected('recentEmails'), + }, + ]} + /> + + + ); + }, +}; diff --git a/polaris-react/src/components/OptionList/OptionList.stories.tsx b/polaris-react/src/components/OptionList/OptionList.stories.tsx index 100e7fb0353..7e8d23d74fb 100644 --- a/polaris-react/src/components/OptionList/OptionList.stories.tsx +++ b/polaris-react/src/components/OptionList/OptionList.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Avatar, Box, @@ -16,371 +16,97 @@ import {DiscountIcon} from '@shopify/polaris-icons'; export default { component: OptionList, -} as ComponentMeta; +} as Meta; -export function Default() { - const [selected, setSelected] = useState([]); +export const Default = { + render() { + const [selected, setSelected] = useState([]); - const handleChange = useCallback((value) => setSelected(value), []); + const handleChange = useCallback((value) => setSelected(value), []); - return ( - - - - ); -} - -export function Multiple() { - const [selected, setSelected] = useState([]); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - - - ); -} - -export function MultipleWithDisabledOption() { - const [selected, setSelected] = useState([]); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - - - ); -} - -export function WithSections() { - const [selected, setSelected] = useState([]); - - const handleChange = useCallback((value) => setSelected(value), []); - - return ( - - - - ); -} - -export function InAPopover() { - const [selected, setSelected] = useState([]); - const [popoverActive, setPopoverActive] = useState(true); - - const handleChange = useCallback((value) => setSelected(value), []); - - const togglePopoverActive = useCallback( - () => setPopoverActive((popoverActive) => !popoverActive), - [], - ); - - const activator = ( - - ); - - return ( -
- + return ( + - -
- ); -} - -export function WithDisabledOption() { - const [selected, setSelected] = useState([]); + + ); + }, +}; - const handleChange = useCallback((value) => setSelected(value), []); +export const Multiple = { + render() { + const [selected, setSelected] = useState([]); - return ( - - - - ); -} + const handleChange = useCallback((value) => setSelected(value), []); -export function All() { - return ( - - - {}} - options={[ - {value: 'byward_market', label: 'Byward Market'}, - {value: 'centretown', disabled: true, label: 'Centretown'}, - {value: 'hintonburg', label: 'Hintonburg'}, - {value: 'westboro', label: 'Westboro'}, - {value: 'downtown', label: 'Downtown'}, - ]} - selected={['byward_market']} - /> - - - {}} - options={[ - {value: 'byward_market', label: 'Byward Market'}, - {value: 'centretown', disabled: true, label: 'Centretown'}, - {value: 'hintonburg', disabled: true, label: 'Hintonburg'}, - {value: 'westboro', label: 'Westboro'}, - {value: 'downtown', label: 'Downtown'}, - ]} - selected={['byward_market', 'hintonburg']} - allowMultiple - /> - - - {}} - options={[ - {value: 'byward_market', label: 'No title'}, - {value: 'centretown', disabled: true, label: 'Centretown'}, - {value: 'hintonburg', label: 'Hintonburg'}, - {value: 'westboro', label: 'Westboro'}, - {value: 'downtown', label: 'Downtown'}, - ]} - selected={['byward_market']} - /> - - + return ( + {}} + title="Manage sales channels availability" + onChange={handleChange} options={[ - { - value: 'top', - label: 'Top', - media: ( - - ), - }, + {value: 'online_store', label: 'Online Store'}, + {value: 'messenger', label: 'Messenger'}, + {value: 'facebook', label: 'Facebook'}, + {value: 'wholesale', label: 'Wholesale'}, + {value: 'buzzfeed', label: 'BuzzFeed'}, ]} - selected={[]} - verticalAlign="top" - allowMultiple - /> - {}} - options={[ - { - value: 'center', - label: 'Center', - media: ( - - ), - }, - ]} - selected={['center']} - verticalAlign="center" + selected={selected} allowMultiple /> + + ); + }, +}; + +export const MultipleWithDisabledOption = { + render() { + const [selected, setSelected] = useState([]); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + {}} + title="Manage sales channels availability" + onChange={handleChange} options={[ - { - value: 'bottom', - label: 'Bottom', - media: ( - - ), - }, + {value: 'online_store', label: 'Online Store'}, + {value: 'messenger', label: 'Messenger', disabled: true}, + {value: 'facebook', label: 'Facebook'}, + {value: 'wholesale', label: 'Wholesale'}, + {value: 'buzzfeed', label: 'BuzzFeed'}, ]} - selected={[]} - verticalAlign="bottom" + selected={selected} allowMultiple /> - - - {}} - sections={[ - { - title: 'Icons', - options: [ - { - value: 'minor', - label: 'Icon', - media: , - }, - { - value: 'major', - label: 'Icon', - media: , - }, - ], - }, - { - title: 'Avatars', - options: [ - { - value: 'avatar_extra_small', - label: 'Avatar extra small', - media: , - }, - { - value: 'avatar_small', - label: 'Avatar small', - media: , - }, - ], - }, - { - title: 'Thumbnails', - options: [ - { - value: 'thumbnail_small', - label: 'Thumbnail small', - media: ( - - ), - }, - { - value: 'thumbnail_medium', - label: 'Thumbnail medium', - media: ( - - ), - }, - ], - }, - ]} - selected={['avatar_small']} - verticalAlign="center" - /> - - + + ); + }, +}; + +export const WithSections = { + render() { + const [selected, setSelected] = useState([]); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + {}} - title="Sectioned multiselect" + onChange={handleChange} sections={[ { - title: 'Type', options: [ {value: 'type', label: 'Sale item type'}, {value: 'kind', label: 'Sale kind'}, @@ -390,7 +116,7 @@ export function All() { title: 'Traffic', options: [ {value: 'source', label: 'Traffic referrer source'}, - {value: 'host', disabled: true, label: 'Traffic referrer host'}, + {value: 'host', label: 'Traffic referrer host'}, {value: 'path', label: 'Traffic referrer path'}, ], }, @@ -405,34 +131,326 @@ export function All() { ], }, ]} - selected={['source', 'host', 'westboro']} + selected={selected} allowMultiple /> - - + + ); + }, +}; + +export const InAPopover = { + render() { + const [selected, setSelected] = useState([]); + const [popoverActive, setPopoverActive] = useState(true); + + const handleChange = useCallback((value) => setSelected(value), []); + + const togglePopoverActive = useCallback( + () => setPopoverActive((popoverActive) => !popoverActive), + [], + ); + + const activator = ( + + ); + + return ( +
+ + + +
+ ); + }, +}; + +export const WithDisabledOption = { + render() { + const [selected, setSelected] = useState([]); + + const handleChange = useCallback((value) => setSelected(value), []); + + return ( + {}} - title="Sectioned single select" - sections={[ - { - title: 'Type', - options: [ - {value: 'type', disabled: true, label: 'Sale item type'}, - {value: 'kind', label: 'Sale kind'}, - ], - }, - { - title: 'Sectioned single select', - options: [ - {value: 'source', label: 'Traffic referrer source'}, - {value: 'host', label: 'Traffic referrer host'}, - {value: 'path', label: 'Traffic referrer path'}, - ], - }, + title="Inventory Location" + onChange={handleChange} + options={[ + {value: 'byward_market', label: 'Byward Market'}, + {value: 'centretown', disabled: true, label: 'Centretown'}, + {value: 'hintonburg', label: 'Hintonburg'}, + {value: 'westboro', label: 'Westboro'}, + {value: 'downtown', label: 'Downtown'}, ]} - selected={['source']} + selected={selected} /> -
-
- ); -} + + ); + }, +}; + +export const All = { + render() { + return ( + + + {}} + options={[ + {value: 'byward_market', label: 'Byward Market'}, + {value: 'centretown', disabled: true, label: 'Centretown'}, + {value: 'hintonburg', label: 'Hintonburg'}, + {value: 'westboro', label: 'Westboro'}, + {value: 'downtown', label: 'Downtown'}, + ]} + selected={['byward_market']} + /> + + + {}} + options={[ + {value: 'byward_market', label: 'Byward Market'}, + {value: 'centretown', disabled: true, label: 'Centretown'}, + {value: 'hintonburg', disabled: true, label: 'Hintonburg'}, + {value: 'westboro', label: 'Westboro'}, + {value: 'downtown', label: 'Downtown'}, + ]} + selected={['byward_market', 'hintonburg']} + allowMultiple + /> + + + {}} + options={[ + {value: 'byward_market', label: 'No title'}, + {value: 'centretown', disabled: true, label: 'Centretown'}, + {value: 'hintonburg', label: 'Hintonburg'}, + {value: 'westboro', label: 'Westboro'}, + {value: 'downtown', label: 'Downtown'}, + ]} + selected={['byward_market']} + /> + + + {}} + options={[ + { + value: 'top', + label: 'Top', + media: ( + + ), + }, + ]} + selected={[]} + verticalAlign="top" + allowMultiple + /> + {}} + options={[ + { + value: 'center', + label: 'Center', + media: ( + + ), + }, + ]} + selected={['center']} + verticalAlign="center" + allowMultiple + /> + {}} + options={[ + { + value: 'bottom', + label: 'Bottom', + media: ( + + ), + }, + ]} + selected={[]} + verticalAlign="bottom" + allowMultiple + /> + + + {}} + sections={[ + { + title: 'Icons', + options: [ + { + value: 'minor', + label: 'Icon', + media: , + }, + { + value: 'major', + label: 'Icon', + media: , + }, + ], + }, + { + title: 'Avatars', + options: [ + { + value: 'avatar_extra_small', + label: 'Avatar extra small', + media: , + }, + { + value: 'avatar_small', + label: 'Avatar small', + media: , + }, + ], + }, + { + title: 'Thumbnails', + options: [ + { + value: 'thumbnail_small', + label: 'Thumbnail small', + media: ( + + ), + }, + { + value: 'thumbnail_medium', + label: 'Thumbnail medium', + media: ( + + ), + }, + ], + }, + ]} + selected={['avatar_small']} + verticalAlign="center" + /> + + + {}} + title="Sectioned multiselect" + sections={[ + { + title: 'Type', + options: [ + {value: 'type', label: 'Sale item type'}, + {value: 'kind', label: 'Sale kind'}, + ], + }, + { + title: 'Traffic', + options: [ + {value: 'source', label: 'Traffic referrer source'}, + { + value: 'host', + disabled: true, + label: 'Traffic referrer host', + }, + {value: 'path', label: 'Traffic referrer path'}, + ], + }, + { + title: 'Inventory Location', + options: [ + {value: 'byward_market', label: 'Byward Market'}, + {value: 'centretown', label: 'Centretown'}, + {value: 'hintonburg', label: 'Hintonburg'}, + {value: 'westboro', label: 'Westboro'}, + {value: 'downtown', label: 'Downtown'}, + ], + }, + ]} + selected={['source', 'host', 'westboro']} + allowMultiple + /> + + + {}} + title="Sectioned single select" + sections={[ + { + title: 'Type', + options: [ + {value: 'type', disabled: true, label: 'Sale item type'}, + {value: 'kind', label: 'Sale kind'}, + ], + }, + { + title: 'Sectioned single select', + options: [ + {value: 'source', label: 'Traffic referrer source'}, + {value: 'host', label: 'Traffic referrer host'}, + {value: 'path', label: 'Traffic referrer path'}, + ], + }, + ]} + selected={['source']} + /> + + + ); + }, +}; diff --git a/polaris-react/src/components/Page/Page.stories.tsx b/polaris-react/src/components/Page/Page.stories.tsx index 6be3b21dcd0..7c3d3217667 100644 --- a/polaris-react/src/components/Page/Page.stories.tsx +++ b/polaris-react/src/components/Page/Page.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { DeleteIcon, PlusIcon, @@ -20,515 +20,553 @@ import { export default { component: Page, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - Paid} - subtitle="Perfect for any pet" - compactTitle - primaryAction={{content: 'Save', disabled: true}} - secondaryActions={[ - { - content: 'Delete', - destructive: true, - icon: DeleteIcon, - accessibilityLabel: 'Delete action label', - onAction: () => console.log('Delete action'), - }, - { - content: 'View on your store', - icon: ViewIcon, - onAction: () => console.log('View on your store action'), - }, - ]} - actionGroups={[ - { - title: 'Promote', - icon: MenuVerticalIcon, - actions: [ - { - content: 'Share on Facebook', - accessibilityLabel: 'Individual action label', - onAction: () => console.log('Share on Facebook action'), - }, - ], - }, - ]} - pagination={{ - hasPrevious: true, - hasNext: true, - }} - > - - - Credit card information - - - - ); -} - -export function WithCustomPrimaryAction() { - return ( - Save} - > - - - Credit card information - - - - ); -} - -export function WithoutPrimaryActionInHeader() { - return ( - - - - - - Buy postage and ship remaining 2 items - - - - - - - ); -} +export const Default = { + render() { + return ( + Paid} + subtitle="Perfect for any pet" + compactTitle + primaryAction={{content: 'Save', disabled: true}} + secondaryActions={[ + { + content: 'Delete', + destructive: true, + icon: DeleteIcon, + accessibilityLabel: 'Delete action label', + onAction: () => console.log('Delete action'), + }, + { + content: 'View on your store', + icon: ViewIcon, + onAction: () => console.log('View on your store action'), + }, + ]} + actionGroups={[ + { + title: 'Promote', + icon: MenuVerticalIcon, + actions: [ + { + content: 'Share on Facebook', + accessibilityLabel: 'Individual action label', + onAction: () => console.log('Share on Facebook action'), + }, + ], + }, + ]} + pagination={{ + hasPrevious: true, + hasNext: true, + }} + > + + + Credit card information + + + + ); + }, +}; -export function WithDestructiveSecondaryAction() { - return ( - - - Page content - - - ); -} +export const WithCustomPrimaryAction = { + render() { + return ( + Save} + > + + + Credit card information + + + + ); + }, +}; -export function WithCustomSecondaryAction() { - return ( - Save}> - - Page content - - - ); -} +export const WithoutPrimaryActionInHeader = { + render() { + return ( + + + + + + Buy postage and ship remaining 2 items + + + + + + + ); + }, +}; -export function WithToolTipAction() { - return ( - - +export const WithDestructiveSecondaryAction = { + render() { + return ( + - Product X information + Page content - - - ); -} + + ); + }, +}; -export function WithBackActionOnAction() { - return ( - { - // eslint-disable-next-line no-alert - alert('Clicked back button'); - }, - }} - title="General" - > - +export const WithCustomSecondaryAction = { + render() { + return ( + Save}> - Credit card information + Page content - - - ); -} + + ); + }, +}; -export function WithSubtitle() { - return ( - - - - Credit card information - - - - ); -} +export const WithToolTipAction = { + render() { + return ( + + + + Product X information + + + + ); + }, +}; -export function WithSubtitleAndAdditionalMetadata() { - return ( - - - - Credit card information - - - - ); -} +export const WithBackActionOnAction = { + render() { + return ( + { + // eslint-disable-next-line no-alert + alert('Clicked back button'); + }, + }} + title="General" + > + + + Credit card information + + + + ); + }, +}; -export function WithSubtitleAndAdditionalMetadataAndNoBackAction() { - return ( - - - - Credit card information - - - - ); -} +export const WithSubtitle = { + render() { + return ( + + + + Credit card information + + + + ); + }, +}; -export function WithExternalLink() { - return ( - - - - Credit card information - - - - ); -} +export const WithSubtitleAndAdditionalMetadata = { + render() { + return ( + + + + Credit card information + + + + ); + }, +}; -export function WithoutPagination() { - return ( - - - - Credit card information - - - - ); -} +export const WithSubtitleAndAdditionalMetadataAndNoBackAction = { + render() { + return ( + + + + Credit card information + + + + ); + }, +}; -export function FullWidth() { - return ( - - - - Credit card information - - - - ); -} +export const WithExternalLink = { + render() { + return ( + + + + Credit card information + + + + ); + }, +}; -export function NarrowWidth() { - return ( - - - - Credit card information - - - + + + Credit card information + + + + ); + }, +}; + +export const FullWidth = { + render() { + return ( + + + + Credit card information + + + + ); + }, +}; + +export const NarrowWidth = { + render() { + return ( + - - ); -} + > + + + Credit card information + + + + + ); + }, +}; -export function WithActionGroups() { - return ( - { - console.log('Copy action'); - openActions(); +export const WithActionGroups = { + render() { + return ( + { + console.log('Copy action'); + openActions(); + }, + actions: [{content: 'Copy to clipboard'}], }, - actions: [{content: 'Copy to clipboard'}], - }, - { - title: 'Promote', - disabled: true, - actions: [{content: 'Share on Facebook'}], - }, - { - title: 'More actions', - actions: [ - {content: 'Duplicate'}, - {content: 'Print'}, - {content: 'Unarchive'}, - {content: 'Cancel order'}, - ], - }, - ]} - > - - - Credit card information - - - - ); -} + { + title: 'Promote', + disabled: true, + actions: [{content: 'Share on Facebook'}], + }, + { + title: 'More actions', + actions: [ + {content: 'Duplicate'}, + {content: 'Print'}, + {content: 'Unarchive'}, + {content: 'Cancel order'}, + ], + }, + ]} + > + + + Credit card information + + + + ); + }, +}; -export function WithActionGroupsAndActions() { - return ( - {}, - }, - { - content: 'Confirm', - onAction: () => {}, - }, - { - content: 'Localize', - url: '/store/marcs-staffed-store/apps/translate-and-adapt/localize/email_template?id=10774151224&locale=fr', - }, - { - content: 'Manage payment reminders', - url: '/store/marcs-staffed-store/settings/notifications/payment_reminders', - }, - ]} - actionGroups={[ - { - title: 'Copy', - onClick: (openActions) => { - console.log('Copy action'); - openActions(); +export const WithActionGroupsAndActions = { + render() { + return ( + {}, }, - actions: [{content: 'Copy to clipboard'}], - }, - { - title: 'Promote', - disabled: true, - actions: [{content: 'Share on Facebook'}], - }, - { - title: 'Delete', - disabled: false, - actions: [{content: 'Delete or remove'}], - }, - { - title: 'Other actions', - actions: [ - {content: 'Duplicate'}, - {content: 'Print'}, - {content: 'Unarchive'}, - {content: 'Cancel order'}, - ], - }, - ]} - > - - - Credit card information - - - - ); -} + { + content: 'Confirm', + onAction: () => {}, + }, + { + content: 'Localize', + url: '/store/marcs-staffed-store/apps/translate-and-adapt/localize/email_template?id=10774151224&locale=fr', + }, + { + content: 'Manage payment reminders', + url: '/store/marcs-staffed-store/settings/notifications/payment_reminders', + }, + ]} + actionGroups={[ + { + title: 'Copy', + onClick: (openActions) => { + console.log('Copy action'); + openActions(); + }, + actions: [{content: 'Copy to clipboard'}], + }, + { + title: 'Promote', + disabled: true, + actions: [{content: 'Share on Facebook'}], + }, + { + title: 'Delete', + disabled: false, + actions: [{content: 'Delete or remove'}], + }, + { + title: 'Other actions', + actions: [ + {content: 'Duplicate'}, + {content: 'Print'}, + {content: 'Unarchive'}, + {content: 'Cancel order'}, + ], + }, + ]} + > + + + Credit card information + + + + ); + }, +}; -export function WithActionGroupsAndActionsAndLongTitle() { - return ( - {}, - }, - { - content: 'Confirm', - onAction: () => {}, - }, - { - content: 'Localize', - url: '/store/marcs-staffed-store/apps/translate-and-adapt/localize/email_template?id=10774151224&locale=fr', - }, - { - content: 'Manage payment reminders', - url: '/store/marcs-staffed-store/settings/notifications/payment_reminders', - }, - ]} - actionGroups={[ - { - title: 'Copy', - onClick: (openActions) => { - console.log('Copy action'); - openActions(); +export const WithActionGroupsAndActionsAndLongTitle = { + render() { + return ( + {}, }, - actions: [{content: 'Copy to clipboard'}], - }, - { - title: 'Promote', - disabled: true, - actions: [{content: 'Share on Facebook'}], - }, - { - title: 'Delete', - disabled: false, - actions: [{content: 'Delete or remove'}], - }, - { - title: 'Other actions', - actions: [ - {content: 'Duplicate'}, - {content: 'Print'}, - {content: 'Unarchive'}, - {content: 'Cancel order'}, - ], - }, - ]} - > - - - Credit card information - - - - ); -} + { + content: 'Confirm', + onAction: () => {}, + }, + { + content: 'Localize', + url: '/store/marcs-staffed-store/apps/translate-and-adapt/localize/email_template?id=10774151224&locale=fr', + }, + { + content: 'Manage payment reminders', + url: '/store/marcs-staffed-store/settings/notifications/payment_reminders', + }, + ]} + actionGroups={[ + { + title: 'Copy', + onClick: (openActions) => { + console.log('Copy action'); + openActions(); + }, + actions: [{content: 'Copy to clipboard'}], + }, + { + title: 'Promote', + disabled: true, + actions: [{content: 'Share on Facebook'}], + }, + { + title: 'Delete', + disabled: false, + actions: [{content: 'Delete or remove'}], + }, + { + title: 'Other actions', + actions: [ + {content: 'Duplicate'}, + {content: 'Print'}, + {content: 'Unarchive'}, + {content: 'Cancel order'}, + ], + }, + ]} + > + + + Credit card information + + + + ); + }, +}; -export function WithContentAfterTitle() { - return ( - Verified} - primaryAction={{content: 'Save', disabled: true}} - secondaryActions={[ - {content: 'Duplicate'}, - {content: 'View on your store'}, - ]} - pagination={{ - hasPrevious: true, - hasNext: true, - }} - > - - - Credit card information - - - - ); -} +export const WithContentAfterTitle = { + render() { + return ( + Verified} + primaryAction={{content: 'Save', disabled: true}} + secondaryActions={[ + {content: 'Duplicate'}, + {content: 'View on your store'}, + ]} + pagination={{ + hasPrevious: true, + hasNext: true, + }} + > + + + Credit card information + + + + ); + }, +}; -export function WithContentAfterTitleAndSubtitle() { - return ( - - All locations - - } - subtitle="Created: May 3, 2019 to June 2, 2019" - primaryAction={{content: 'Save', disabled: true}} - secondaryActions={[ - {content: 'Duplicate'}, - {content: 'View on your store'}, - ]} - pagination={{ - hasPrevious: true, - hasNext: true, - }} - > - - - Credit card information - - - - ); -} +export const WithContentAfterTitleAndSubtitle = { + render() { + return ( + + All locations + + } + subtitle="Created: May 3, 2019 to June 2, 2019" + primaryAction={{content: 'Save', disabled: true}} + secondaryActions={[ + {content: 'Duplicate'}, + {content: 'View on your store'}, + ]} + pagination={{ + hasPrevious: true, + hasNext: true, + }} + > + + + Credit card information + + + + ); + }, +}; diff --git a/polaris-react/src/components/PageActions/PageActions.stories.tsx b/polaris-react/src/components/PageActions/PageActions.stories.tsx index 4cf9301d2c9..b951c3d7087 100644 --- a/polaris-react/src/components/PageActions/PageActions.stories.tsx +++ b/polaris-react/src/components/PageActions/PageActions.stories.tsx @@ -1,58 +1,66 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Button, PageActions} from '@shopify/polaris'; export default { component: PageActions, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - ); -} +export const Default = { + render() { + return ( + + ); + }, +}; -export function PrimaryActionOnly() { - return ( - - ); -} +export const PrimaryActionOnly = { + render() { + return ( + + ); + }, +}; -export function WithCustomPrimaryAction() { - return ( - Save} - secondaryActions={[ - { - content: 'Delete', - destructive: true, - }, - ]} - /> - ); -} +export const WithCustomPrimaryAction = { + render() { + return ( + Save} + secondaryActions={[ + { + content: 'Delete', + destructive: true, + }, + ]} + /> + ); + }, +}; -export function WithCustomSecondaryAction() { - return ( - Save} - /> - ); -} +export const WithCustomSecondaryAction = { + render() { + return ( + Save} + /> + ); + }, +}; diff --git a/polaris-react/src/components/Pagination/Pagination.stories.tsx b/polaris-react/src/components/Pagination/Pagination.stories.tsx index 48c162c4601..3b07dd8d3d0 100644 --- a/polaris-react/src/components/Pagination/Pagination.stories.tsx +++ b/polaris-react/src/components/Pagination/Pagination.stories.tsx @@ -1,105 +1,115 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Pagination} from '@shopify/polaris'; export default { component: Pagination, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - { - console.log('Previous'); - }} - hasNext - onNext={() => { - console.log('Next'); - }} - /> - ); -} - -export function WithKeyboardNavigation() { - return ( -
+export const Default = { + render() { + return ( { console.log('Previous'); }} hasNext - nextKeys={[75]} - nextTooltip="Next (K)" onNext={() => { console.log('Next'); }} /> -
- ); -} + ); + }, +}; -export function WithLabel() { - return ( - { - console.log('Previous'); - }} - hasNext - onNext={() => { - console.log('Next'); - }} - /> - ); -} +export const WithKeyboardNavigation = { + render() { + return ( +
+ { + console.log('Previous'); + }} + hasNext + nextKeys={[75]} + nextTooltip="Next (K)" + onNext={() => { + console.log('Next'); + }} + /> +
+ ); + }, +}; -export function WithTableType() { - return ( -
+export const WithLabel = { + render() { + return ( { console.log('Previous'); }} + hasNext onNext={() => { console.log('Next'); }} - type="table" - hasNext - label="1-50 of 8,450 orders" /> -
- ); -} + ); + }, +}; -export function WithTableTypeAndNoLabel() { - return ( -
- { - console.log('Previous'); +export const WithTableType = { + render() { + return ( +
{ - console.log('Next'); + > + { + console.log('Previous'); + }} + onNext={() => { + console.log('Next'); + }} + type="table" + hasNext + label="1-50 of 8,450 orders" + /> +
+ ); + }, +}; + +export const WithTableTypeAndNoLabel = { + render() { + return ( +
-
- ); -} + > + { + console.log('Previous'); + }} + onNext={() => { + console.log('Next'); + }} + type="table" + hasNext + hasPrevious + /> +
+ ); + }, +}; diff --git a/polaris-react/src/components/Popover/Popover.stories.tsx b/polaris-react/src/components/Popover/Popover.stories.tsx index ed22387f37c..8b9ae3b42db 100644 --- a/polaris-react/src/components/Popover/Popover.stories.tsx +++ b/polaris-react/src/components/Popover/Popover.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { ActionList, Avatar, @@ -24,874 +24,901 @@ import {SearchIcon, SelectIcon} from '@shopify/polaris-icons'; export default { component: Popover, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - - - - With action list - - - - - - - With content and actions - - - - - - - With form components - - - - - - - With lazy loaded list - - - - - - - With scrollable lazy loaded list - - - - - - - With searchable listbox - - - - - - - With loading smaller content - - - - - - - With preferredPosition cover - - - - - ); -} - -export function WithActionList() { - const [activePopover, setActivePopover] = useState(null); - - const togglePopoverActive = useCallback((popover, isClosing) => { - const currentPopover = isClosing ? null : popover; - setActivePopover(currentPopover); - }, []); - - const activator = ( - - ); - const activator2 = ( - - ); - - return ( -
- - togglePopoverActive('popover1', true)} - > - - - togglePopoverActive('popover2', true)} - > - - +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + With action list + + + + + + + With content and actions + + + + + + + With form components + + + + + + + With lazy loaded list + + + + + + + With scrollable lazy loaded list + + + + + + + With searchable listbox + + + + + + + With loading smaller content + + + + + + + With preferredPosition cover + + + -
- ); -} - -export function WithContentAndActions() { - const [popoverActive, setPopoverActive] = useState(true); - - const togglePopoverActive = useCallback( - () => setPopoverActive((popoverActive) => !popoverActive), - [], - ); + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; - const textMarkup = ( - - Available sales channels - - ); +export const WithActionList = { + render() { + const [activePopover, setActivePopover] = useState(null); - const activator = ( - - ); + const togglePopoverActive = useCallback((popover, isClosing) => { + const currentPopover = isClosing ? null : popover; + setActivePopover(currentPopover); + }, []); - return ( -
- togglePopoverActive('popover1', false)} + disclosure > - - {textMarkup} - - - - - -
- ); -} - -export function WithFormComponents() { - const [popoverActive, setPopoverActive] = useState(true); - const [tagValue, setTagValue] = useState(''); - - const togglePopoverActive = useCallback( - () => setPopoverActive((popoverActive) => !popoverActive), - [], - ); - - const handleTagValueChange = useCallback((value) => setTagValue(value), []); - - const activator = ( - - ); - - return ( -
- + ); + const activator2 = ( + +
- - ); - - function renderItem({name, initials}) { - return ( - } - verticalAlignment="center" - onClick={handleResourceListItemClick} - > - {name} - - ); - } - - function getInitials(name) { - return name - .split(' ') - .map((surnameOrFamilyName) => { - return surnameOrFamilyName.slice(0, 1); - }) - .join(''); - } -} - -export function WithSearchableListbox() { - interface CustomerSegment { - id: string; - label: string; - value: string; - } - - const actionValue = '__ACTION__'; - - const segments: CustomerSegment[] = [ - { - label: 'All customers', - id: 'gid://shopify/CustomerSegment/1', - value: '0', - }, - { - label: 'VIP customers', - id: 'gid://shopify/CustomerSegment/2', - value: '1', - }, - { - label: 'New customers', - id: 'gid://shopify/CustomerSegment/3', - value: '2', - }, - { - label: 'Abandoned carts - last 30 days', - id: 'gid://shopify/CustomerSegment/4', - value: '3', - }, - { - label: 'Wholesale customers', - id: 'gid://shopify/CustomerSegment/5', - value: '4', - }, - { - label: 'Email subscribers', - id: 'gid://shopify/CustomerSegment/6', - value: '5', - }, - { - label: 'From New York', - id: 'gid://shopify/CustomerSegment/7', - value: '6', - }, - { - label: 'Repeat buyers', - id: 'gid://shopify/CustomerSegment/8', - value: '7', - }, - { - label: 'First time buyers', - id: 'gid://shopify/CustomerSegment/9', - value: '8', - }, - { - label: 'From Canada', - id: 'gid://shopify/CustomerSegment/10', - value: '9', - }, - { - label: 'Bought in last 60 days', - id: 'gid://shopify/CustomerSegment/11', - value: '10', - }, - { - label: 'Bought last BFCM', - id: 'gid://shopify/CustomerSegment/12', - value: '11', - }, - ]; - - const lazyLoadSegments: CustomerSegment[] = Array.from(Array(100)).map( - (_, index) => ({ - label: `Other customers ${index + 13}`, - id: `gid://shopify/CustomerSegment/${index + 13}`, - value: `${index + 12}`, - }), - ); + ); + }, +}; - segments.push(...lazyLoadSegments); +export const WithLazyLoadedList = { + render() { + const [popoverActive, setPopoverActive] = useState(true); + const [visibleStaffIndex, setVisibleStaffIndex] = useState(5); + const staff = [ + 'Abbey Mayert', + 'Abbi Senger', + 'Abdul Goodwin', + 'Abdullah Borer', + 'Abe Nader', + 'Abigayle Smith', + 'Abner Torphy', + 'Abraham Towne', + 'Abraham Vik', + 'Ada Fisher', + 'Adah Pouros', + 'Adam Waelchi', + 'Adan Zemlak', + 'Addie Wehner', + 'Addison Wexler', + 'Alex Hernandez', + ]; + + const togglePopoverActive = useCallback( + () => setPopoverActive((popoverActive) => !popoverActive), + [], + ); - const interval = 25; + const handleScrolledToBottom = useCallback(() => { + const totalIndexes = staff.length; + const interval = + visibleStaffIndex + 3 < totalIndexes + ? 3 + : totalIndexes - visibleStaffIndex; - const [pickerOpen, setPickerOpen] = useState(false); - const [showFooterAction, setShowFooterAction] = useState(true); - const [query, setQuery] = useState(''); - const [lazyLoading, setLazyLoading] = useState(false); - const [willLoadMoreResults, setWillLoadMoreResults] = useState(true); - const [visibleOptionIndex, setVisibleOptionIndex] = useState(6); - const [activeOptionId, setActiveOptionId] = useState(segments[0].id); - const [selectedSegmentIndex, setSelectedSegmentIndex] = useState(0); - const [filteredSegments, setFilteredSegments] = useState( - [], - ); + if (interval > 0) { + setVisibleStaffIndex(visibleStaffIndex + interval); + } + }, [staff.length, visibleStaffIndex]); - const handleClickShowAll = () => { - setShowFooterAction(false); - setVisibleOptionIndex(interval); - }; + const handleResourceListItemClick = useCallback(() => {}, []); - const handleFilterSegments = (query: string) => { - const nextFilteredSegments = segments.filter((segment: CustomerSegment) => { - return segment.label - .toLocaleLowerCase() - .includes(query.toLocaleLowerCase().trim()); - }); + const activator = ( + + ); - setFilteredSegments(nextFilteredSegments); - }; + const staffList = staff.slice(0, visibleStaffIndex).map((name) => ({ + name, + initials: getInitials(name), + })); - const handleQueryChange = (query: string) => { - setQuery(query); + return ( + +
+ + + + + +
+
+ ); - if (query.length >= 2) handleFilterSegments(query); - }; + function renderItem({name, initials}) { + return ( + } + verticalAlignment="center" + onClick={handleResourceListItemClick} + > + {name} + + ); + } - const handleQueryClear = () => { - handleQueryChange(''); - }; + function getInitials(name) { + return name + .split(' ') + .map((surnameOrFamilyName) => { + return surnameOrFamilyName.slice(0, 1); + }) + .join(''); + } + }, +}; - const handleOpenPicker = () => { - setPickerOpen(true); - }; +export const WithScrollableLazyLoadedList = { + render() { + const [popoverActive, setPopoverActive] = useState(true); + const [visibleStaffIndex, setVisibleStaffIndex] = useState(5); + const staff = [ + 'Abbey Mayert', + 'Abbi Senger', + 'Abdul Goodwin', + 'Abdullah Borer', + 'Abe Nader', + 'Abigayle Smith', + 'Abner Torphy', + 'Abraham Towne', + 'Abraham Vik', + 'Ada Fisher', + 'Adah Pouros', + 'Adam Waelchi', + 'Adan Zemlak', + 'Addie Wehner', + 'Addison Wexler', + 'Alex Hernandez', + ]; + + const togglePopoverActive = useCallback( + () => setPopoverActive((popoverActive) => !popoverActive), + [], + ); - const handleClosePicker = () => { - setPickerOpen(false); - handleQueryChange(''); - }; + const handleScrolledToBottom = useCallback(() => { + const totalIndexes = staff.length; + const interval = + visibleStaffIndex + 3 < totalIndexes + ? 3 + : totalIndexes - visibleStaffIndex; - const handleSegmentSelect = (segmentIndex: string) => { - if (segmentIndex === actionValue) { - return handleClickShowAll(); - } + console.log({interval}); - setSelectedSegmentIndex(Number(segmentIndex)); - handleClosePicker(); - }; + if (interval > 0) { + setVisibleStaffIndex(visibleStaffIndex + interval); + } + }, [staff.length, visibleStaffIndex]); - const handleActiveOptionChange = (_: string, domId: string) => { - setActiveOptionId(domId); - }; + const handleResourceListItemClick = useCallback(() => {}, []); - /* This is just to illustrate lazy loading state vs loading state. This is an example, so we aren't fetching from GraphQL. You'd use `pageInfo.hasNextPage` from your GraphQL query data instead of this fake "willLoadMoreResults" state along with setting `first` your GraphQL query's variables to your app's default max edges limit (e.g., 250). */ + const activator = ( + + ); - const handleLazyLoadSegments = () => { - if (willLoadMoreResults && !showFooterAction) { - setLazyLoading(true); + const staffList = staff.slice(0, visibleStaffIndex).map((name) => ({ + name, + initials: getInitials(name), + })); - const options = query ? filteredSegments : segments; + return ( + +
+ + + + + + + +
+
+ ); - setTimeout(() => { - const remainingOptionCount = options.length - visibleOptionIndex; - const nextVisibleOptionIndex = - remainingOptionCount >= interval - ? visibleOptionIndex + interval - : visibleOptionIndex + remainingOptionCount; + function renderItem({name, initials}) { + return ( + } + verticalAlignment="center" + onClick={handleResourceListItemClick} + > + {name} + + ); + } - setLazyLoading(false); - setVisibleOptionIndex(nextVisibleOptionIndex); + function getInitials(name) { + return name + .split(' ') + .map((surnameOrFamilyName) => { + return surnameOrFamilyName.slice(0, 1); + }) + .join(''); + } + }, +}; - if (remainingOptionCount <= interval) { - setWillLoadMoreResults(false); - } - }, 1000); +export const WithSearchableListbox = { + render() { + interface CustomerSegment { + id: string; + label: string; + value: string; } - }; - const listboxId = 'SearchableListboxInPopover'; - - /* Your app's feature/context specific activator here */ - const activator = ( -
- - - {segments[selectedSegmentIndex].label} - - -
- ); + const actionValue = '__ACTION__'; + + const segments: CustomerSegment[] = [ + { + label: 'All customers', + id: 'gid://shopify/CustomerSegment/1', + value: '0', + }, + { + label: 'VIP customers', + id: 'gid://shopify/CustomerSegment/2', + value: '1', + }, + { + label: 'New customers', + id: 'gid://shopify/CustomerSegment/3', + value: '2', + }, + { + label: 'Abandoned carts - last 30 days', + id: 'gid://shopify/CustomerSegment/4', + value: '3', + }, + { + label: 'Wholesale customers', + id: 'gid://shopify/CustomerSegment/5', + value: '4', + }, + { + label: 'Email subscribers', + id: 'gid://shopify/CustomerSegment/6', + value: '5', + }, + { + label: 'From New York', + id: 'gid://shopify/CustomerSegment/7', + value: '6', + }, + { + label: 'Repeat buyers', + id: 'gid://shopify/CustomerSegment/8', + value: '7', + }, + { + label: 'First time buyers', + id: 'gid://shopify/CustomerSegment/9', + value: '8', + }, + { + label: 'From Canada', + id: 'gid://shopify/CustomerSegment/10', + value: '9', + }, + { + label: 'Bought in last 60 days', + id: 'gid://shopify/CustomerSegment/11', + value: '10', + }, + { + label: 'Bought last BFCM', + id: 'gid://shopify/CustomerSegment/12', + value: '11', + }, + ]; + + const lazyLoadSegments: CustomerSegment[] = Array.from(Array(100)).map( + (_, index) => ({ + label: `Other customers ${index + 13}`, + id: `gid://shopify/CustomerSegment/${index + 13}`, + value: `${index + 12}`, + }), + ); - const textFieldMarkup = ( -
- - } - ariaActiveDescendant={activeOptionId} - ariaControls={listboxId} - onChange={handleQueryChange} - onClearButtonClick={handleQueryClear} - /> - -
- ); + segments.push(...lazyLoadSegments); + + const interval = 25; - const segmentOptions = query ? filteredSegments : segments; - - const segmentList = - segmentOptions.length > 0 - ? segmentOptions - .slice(0, visibleOptionIndex) - .map(({label, id, value}) => { - const selected = segments[selectedSegmentIndex].id === id; - - return ( - - - {label} - - - ); - }) - : null; - - const showAllMarkup = showFooterAction ? ( - - ( + [], + ); + + const handleClickShowAll = () => { + setShowFooterAction(false); + setVisibleOptionIndex(interval); + }; + + const handleFilterSegments = (query: string) => { + const nextFilteredSegments = segments.filter( + (segment: CustomerSegment) => { + return segment.label + .toLocaleLowerCase() + .includes(query.toLocaleLowerCase().trim()); + }, + ); + + setFilteredSegments(nextFilteredSegments); + }; + + const handleQueryChange = (query: string) => { + setQuery(query); + + if (query.length >= 2) handleFilterSegments(query); + }; + + const handleQueryClear = () => { + handleQueryChange(''); + }; + + const handleOpenPicker = () => { + setPickerOpen(true); + }; + + const handleClosePicker = () => { + setPickerOpen(false); + handleQueryChange(''); + }; + + const handleSegmentSelect = (segmentIndex: string) => { + if (segmentIndex === actionValue) { + return handleClickShowAll(); + } + + setSelectedSegmentIndex(Number(segmentIndex)); + handleClosePicker(); + }; + + const handleActiveOptionChange = (_: string, domId: string) => { + setActiveOptionId(domId); + }; + + /* This is just to illustrate lazy loading state vs loading state. This is an example, so we aren't fetching from GraphQL. You'd use `pageInfo.hasNextPage` from your GraphQL query data instead of this fake "willLoadMoreResults" state along with setting `first` your GraphQL query's variables to your app's default max edges limit (e.g., 250). */ + + const handleLazyLoadSegments = () => { + if (willLoadMoreResults && !showFooterAction) { + setLazyLoading(true); + + const options = query ? filteredSegments : segments; + + setTimeout(() => { + const remainingOptionCount = options.length - visibleOptionIndex; + const nextVisibleOptionIndex = + remainingOptionCount >= interval + ? visibleOptionIndex + interval + : visibleOptionIndex + remainingOptionCount; + + setLazyLoading(false); + setVisibleOptionIndex(nextVisibleOptionIndex); + + if (remainingOptionCount <= interval) { + setWillLoadMoreResults(false); + } + }, 1000); + } + }; + + const listboxId = 'SearchableListboxInPopover'; + + /* Your app's feature/context specific activator here */ + const activator = ( +
- Show all 111 segments - - - ) : null; - - const lazyLoadingMarkup = lazyLoading ? ( - - ) : null; - - const noResultsMarkup = - segmentOptions.length === 0 ? ( - + + + {segments[selectedSegmentIndex].label} + + +
+ ); + + const textFieldMarkup = ( +
+ + } + ariaActiveDescendant={activeOptionId} + ariaControls={listboxId} + onChange={handleQueryChange} + onClearButtonClick={handleQueryClear} + /> + +
+ ); + + const segmentOptions = query ? filteredSegments : segments; + + const segmentList = + segmentOptions.length > 0 + ? segmentOptions + .slice(0, visibleOptionIndex) + .map(({label, id, value}) => { + const selected = segments[selectedSegmentIndex].id === id; + + return ( + + + {label} + + + ); + }) + : null; + + const showAllMarkup = showFooterAction ? ( + + + Show all 111 segments + + ) : null; - const listboxMarkup = ( - - {segmentList} - {showAllMarkup} - {noResultsMarkup} - {lazyLoadingMarkup} - - ); + const lazyLoadingMarkup = lazyLoading ? ( + + ) : null; - return ( -
- + ) : null; + + const listboxMarkup = ( + - -
- {textFieldMarkup} + {segmentList} + {showAllMarkup} + {noResultsMarkup} + {lazyLoadingMarkup} + + ); - + + +
- {listboxMarkup} - -
-
-
-
- ); -} - -export function WithLoadingSmallerContent() { - const [popoverActive, setPopoverActive] = useState(true); - const [loading, setLoading] = useState(false); + {textFieldMarkup} + + + {listboxMarkup} + +
+ + +
+ ); + }, +}; - const togglePopoverActive = useCallback( - () => setPopoverActive((popoverActive) => !popoverActive), - [], - ); +export const WithLoadingSmallerContent = { + render() { + const [popoverActive, setPopoverActive] = useState(true); + const [loading, setLoading] = useState(false); - const activator = ( - - ); + const togglePopoverActive = useCallback( + () => setPopoverActive((popoverActive) => !popoverActive), + [], + ); - return ( -
- { + setLoading(true); + togglePopoverActive(); + window.setTimeout(() => { + setLoading(false); + }, 500); + }} + disclosure > - {loading ? ( -
- - Loading... - -
- ) : ( -
- - Small content from the server - -
- )} -
-
- ); -} + Show server data + + ); -export function WithSubduedPane() { - const [popoverActive, setPopoverActive] = useState(true); + return ( +
+ + {loading ? ( +
+ + Loading... + +
+ ) : ( +
+ + Small content from the server + +
+ )} +
+
+ ); + }, +}; - const togglePopoverActive = useCallback( - () => setPopoverActive((popoverActive) => !popoverActive), - [], - ); +export const WithSubduedPane = { + render() { + const [popoverActive, setPopoverActive] = useState(true); - const activator = ( - - ); + const togglePopoverActive = useCallback( + () => setPopoverActive((popoverActive) => !popoverActive), + [], + ); - return ( -
- { + togglePopoverActive(); + }} + disclosure > - - - Popover content - - - - - Subdued popover pane - - - -
- ); -} + Show popover + + ); -export function WithCoverPositioning() { - const [popoverActive, setPopoverActive] = useState(true); + return ( +
+ + + + Popover content + + + + + Subdued popover pane + + + +
+ ); + }, +}; - const togglePopoverActive = useCallback( - () => setPopoverActive((popoverActive) => !popoverActive), - [], - ); +export const WithCoverPositioning = { + render() { + const [popoverActive, setPopoverActive] = useState(true); - const activator = ( - - ); + const togglePopoverActive = useCallback( + () => setPopoverActive((popoverActive) => !popoverActive), + [], + ); - return ( -
- { + togglePopoverActive(); + }} + style={{ + display: 'flex', + alignItems: 'center', + gap: 'var(--p-space-200)', + padding: 'var(--p-space-200) var(--p-space-300)', + borderRadius: 'var(--p-border-radius-300)', + border: 'var(--p-border-width-025) solid var(--p-color-border)', + background: 'var(--p-color-bg-surface)', + }} > - - - Popover content - - - - Popover content - - - -
- ); -} + Show popover + + + ); + + return ( +
+ + + + Popover content + + + + Popover content + + + +
+ ); + }, +}; const StopPropagation = ({children}: React.PropsWithChildren) => { const stopEventPropagation = (event: React.MouseEvent | React.TouchEvent) => { diff --git a/polaris-react/src/components/ProgressBar/ProgressBar.stories.tsx b/polaris-react/src/components/ProgressBar/ProgressBar.stories.tsx index 097f83d92d6..5e414da1c64 100644 --- a/polaris-react/src/components/ProgressBar/ProgressBar.stories.tsx +++ b/polaris-react/src/components/ProgressBar/ProgressBar.stories.tsx @@ -1,33 +1,41 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {ProgressBar} from '@shopify/polaris'; export default { component: ProgressBar, -} as ComponentMeta; +} as Meta; -export function Default() { - return ; -} +export const Default = { + render() { + return ; + }, +}; -export function Small() { - return ; -} +export const Small = { + render() { + return ; + }, +}; -export function WithColors() { - return ( -
- -
- -
- -
- -
- ); -} +export const WithColors = { + render() { + return ( +
+ +
+ +
+ +
+ +
+ ); + }, +}; -export function WithNoAnimation() { - return ; -} +export const WithNoAnimation = { + render() { + return ; + }, +}; diff --git a/polaris-react/src/components/RadioButton/RadioButton.stories.tsx b/polaris-react/src/components/RadioButton/RadioButton.stories.tsx index 37e76022991..ec205c19fb1 100644 --- a/polaris-react/src/components/RadioButton/RadioButton.stories.tsx +++ b/polaris-react/src/components/RadioButton/RadioButton.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { RadioButton, LegacyStack, @@ -12,163 +12,171 @@ import { export default { component: RadioButton, -} as ComponentMeta; +} as Meta; -export function Default() { - const [value, setValue] = useState('disabled'); +export const Default = { + render() { + const [value, setValue] = useState('disabled'); - const handleChange = useCallback( - (_checked, newValue) => setValue(newValue), - [], - ); + const handleChange = useCallback( + (_checked, newValue) => setValue(newValue), + [], + ); - return ( - - - - - ); -} + return ( + + + + + ); + }, +}; -export function DisabledRadio() { - const handleChange = useCallback((_checked, newValue) => { - // eslint-disable-next-line no-alert - alert('This should never ever get called'); - }, []); - return ( - - - - - ); -} +export const DisabledRadio = { + render() { + const handleChange = useCallback((_checked, newValue) => { + // eslint-disable-next-line no-alert + alert('This should never ever get called'); + }, []); + return ( + + + + + ); + }, +}; -export function Magic() { - const [value, setValue] = useState('disabled'); +export const Magic = { + render() { + const [value, setValue] = useState('disabled'); - const handleChange = useCallback( - (_checked, newValue) => setValue(newValue), - [], - ); + const handleChange = useCallback( + (_checked, newValue) => setValue(newValue), + [], + ); - return ( - - - - - ); -} + return ( + + + + + ); + }, +}; -export function WithBleed() { - const [value1, setValue1] = useState('disabled'); - const [value2, setValue2] = useState('disabled2'); - const handleChange1 = useCallback( - (_checked, newValue) => setValue1(newValue), - [], - ); - const handleChange2 = useCallback( - (_checked, newValue) => setValue2(newValue), - [], - ); +export const WithBleed = { + render() { + const [value1, setValue1] = useState('disabled'); + const [value2, setValue2] = useState('disabled2'); + const handleChange1 = useCallback( + (_checked, newValue) => setValue1(newValue), + [], + ); + const handleChange2 = useCallback( + (_checked, newValue) => setValue2(newValue), + [], + ); - return ( - - - No Bleed - - - - - - + return ( + + + No Bleed + + + + + + + + + Bleed + +
+ +
+ +
+ +
+
+
- - Bleed - -
- -
- -
- -
-
-
-
- ); -} + ); + }, +}; diff --git a/polaris-react/src/components/RangeSlider/RangeSlider.stories.tsx b/polaris-react/src/components/RangeSlider/RangeSlider.stories.tsx index a55a76f7ffa..ca5eebc0ee5 100644 --- a/polaris-react/src/components/RangeSlider/RangeSlider.stories.tsx +++ b/polaris-react/src/components/RangeSlider/RangeSlider.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Box, LegacyCard, @@ -11,215 +11,225 @@ import { export default { component: RangeSlider, -} as ComponentMeta; - -export function Default() { - const [rangeValue, setRangeValue] = useState(32); - - const handleRangeSliderChange = useCallback( - (value) => setRangeValue(value), - [], - ); - - return ( - - - - ); -} - -export function WithMinAndMax() { - const [rangeValue, setRangeValue] = useState(0); - - const handleRangeSliderChange = useCallback( - (value) => setRangeValue(value), - [], - ); - - return ( - - - - ); -} - -export function WithSteps() { - const [rangeValue, setRangeValue] = useState(4); - - const handleRangeSliderChange = useCallback( - (value) => setRangeValue(value), - [], - ); - - return ( - - - - ); -} - -export function WithPrefixAndSuffix() { - const [rangeValue, setRangeValue] = useState(100); - - const handleRangeSliderChange = useCallback( - (value) => setRangeValue(value), - [], - ); - - return ( - - - Hue - - } - suffix={ - - - {rangeValue} - - - } - /> - - ); -} - -export function WithDualThumb() { - const initialValue = [900, 1000]; - const prefix = '$'; - const min = 0; - const max = 2000; - const step = 10; - - const [intermediateTextFieldValue, setIntermediateTextFieldValue] = - useState(initialValue); - const [rangeValue, setRangeValue] = useState(initialValue); - - const handleRangeSliderChange = useCallback((value) => { - setRangeValue(value); - setIntermediateTextFieldValue(value); - }, []); - - const handleLowerTextFieldChange = useCallback( - (value) => { - const upperValue = rangeValue[1]; - setIntermediateTextFieldValue([parseInt(value, 10), upperValue]); - }, - [rangeValue], - ); +} as Meta; - const handleUpperTextFieldChange = useCallback( - (value) => { - const lowerValue = rangeValue[0]; - setIntermediateTextFieldValue([lowerValue, parseInt(value, 10)]); - }, - [rangeValue], - ); - - const handleLowerTextFieldBlur = useCallback(() => { - const upperValue = rangeValue[1]; - const value = intermediateTextFieldValue[0]; - - setRangeValue([parseInt(value, 10), upperValue]); - }, [intermediateTextFieldValue, rangeValue]); - - const handleUpperTextFieldBlur = useCallback(() => { - const lowerValue = rangeValue[0]; - const value = intermediateTextFieldValue[1]; - - setRangeValue([lowerValue, parseInt(value, 10)]); - }, [intermediateTextFieldValue, rangeValue]); - - const handleEnterKeyPress = useCallback( - (event) => { - const newValue = intermediateTextFieldValue; - const oldValue = rangeValue; - - if (event.keyCode === Key.Enter && newValue !== oldValue) { - setRangeValue(newValue); - } - }, - [intermediateTextFieldValue, rangeValue], - ); - - const lowerTextFieldValue = - intermediateTextFieldValue[0] === rangeValue[0] - ? rangeValue[0] - : intermediateTextFieldValue[0]; - - const upperTextFieldValue = - intermediateTextFieldValue[1] === rangeValue[1] - ? rangeValue[1] - : intermediateTextFieldValue[1]; - - return ( - -
+export const Default = { + render() { + const [rangeValue, setRangeValue] = useState(32); + + const handleRangeSliderChange = useCallback( + (value) => setRangeValue(value), + [], + ); + + return ( + + + + ); + }, +}; + +export const WithMinAndMax = { + render() { + const [rangeValue, setRangeValue] = useState(0); + + const handleRangeSliderChange = useCallback( + (value) => setRangeValue(value), + [], + ); + + return ( + - - - + ); + }, +}; + +export const WithSteps = { + render() { + const [rangeValue, setRangeValue] = useState(4); + + const handleRangeSliderChange = useCallback( + (value) => setRangeValue(value), + [], + ); + + return ( + + + + ); + }, +}; + +export const WithPrefixAndSuffix = { + render() { + const [rangeValue, setRangeValue] = useState(100); + + const handleRangeSliderChange = useCallback( + (value) => setRangeValue(value), + [], + ); + + return ( + + + Hue + + } + suffix={ + + + {rangeValue} + + + } + /> + + ); + }, +}; + +export const WithDualThumb = { + render() { + const initialValue = [900, 1000]; + const prefix = '$'; + const min = 0; + const max = 2000; + const step = 10; + + const [intermediateTextFieldValue, setIntermediateTextFieldValue] = + useState(initialValue); + const [rangeValue, setRangeValue] = useState(initialValue); + + const handleRangeSliderChange = useCallback((value) => { + setRangeValue(value); + setIntermediateTextFieldValue(value); + }, []); + + const handleLowerTextFieldChange = useCallback( + (value) => { + const upperValue = rangeValue[1]; + setIntermediateTextFieldValue([parseInt(value, 10), upperValue]); + }, + [rangeValue], + ); + + const handleUpperTextFieldChange = useCallback( + (value) => { + const lowerValue = rangeValue[0]; + setIntermediateTextFieldValue([lowerValue, parseInt(value, 10)]); + }, + [rangeValue], + ); + + const handleLowerTextFieldBlur = useCallback(() => { + const upperValue = rangeValue[1]; + const value = intermediateTextFieldValue[0]; + + setRangeValue([parseInt(value, 10), upperValue]); + }, [intermediateTextFieldValue, rangeValue]); + + const handleUpperTextFieldBlur = useCallback(() => { + const lowerValue = rangeValue[0]; + const value = intermediateTextFieldValue[1]; + + setRangeValue([lowerValue, parseInt(value, 10)]); + }, [intermediateTextFieldValue, rangeValue]); + + const handleEnterKeyPress = useCallback( + (event) => { + const newValue = intermediateTextFieldValue; + const oldValue = rangeValue; + + if (event.keyCode === Key.Enter && newValue !== oldValue) { + setRangeValue(newValue); + } + }, + [intermediateTextFieldValue, rangeValue], + ); + + const lowerTextFieldValue = + intermediateTextFieldValue[0] === rangeValue[0] + ? rangeValue[0] + : intermediateTextFieldValue[0]; + + const upperTextFieldValue = + intermediateTextFieldValue[1] === rangeValue[1] + ? rangeValue[1] + : intermediateTextFieldValue[1]; + + return ( + +
+ - -
-
- ); -} + + + + +
+
+ ); + }, +}; diff --git a/polaris-react/src/components/ResourceItem/ResourceItem.stories.tsx b/polaris-react/src/components/ResourceItem/ResourceItem.stories.tsx index 7d2b6263d60..1444b2ed8f7 100644 --- a/polaris-react/src/components/ResourceItem/ResourceItem.stories.tsx +++ b/polaris-react/src/components/ResourceItem/ResourceItem.stories.tsx @@ -1,5 +1,5 @@ import React, {useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Avatar, LegacyCard, @@ -11,359 +11,405 @@ import type {ResourceListProps} from '@shopify/polaris'; export default { component: ResourceItem, -} as ComponentMeta; +} as Meta; -export function Default() { - const [selectedItems, setSelectedItems] = useState< - ResourceListProps['selectedItems'] - >([]); +export const Default = { + render() { + const [selectedItems, setSelectedItems] = useState< + ResourceListProps['selectedItems'] + >([]); - return ( - - { - const {id, url, title, author} = item; - const authorMarkup = author ?
by {author}
: null; - return ( - -

- - {title} - -

- {authorMarkup} -
- ); - }} - /> -
- ); -} + return ( + + { + const {id, url, title, author} = item; + const authorMarkup = author ?
by {author}
: null; + return ( + +

+ + {title} + +

+ {authorMarkup} +
+ ); + }} + /> +
+ ); + }, +}; -export function SelectableWithMedia() { - const [selectedItems, setSelectedItems] = useState< - ResourceListProps['selectedItems'] - >([]); +export const SelectableWithMedia = { + render() { + const [selectedItems, setSelectedItems] = useState< + ResourceListProps['selectedItems'] + >([]); - return ( - - { - const {id, url, avatarSource, name, location} = item; + return ( + + { + const {id, url, avatarSource, name, location} = item; - return ( - - } - accessibilityLabel={`View details for ${name}`} - name={name} - > -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} + return ( + + } + accessibilityLabel={`View details for ${name}`} + name={name} + > +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; -export function WithMedia() { - return ( - - { - const {id, url, avatarSource, name, location} = item; +export const WithMedia = { + render() { + return ( + + { + const {id, url, avatarSource, name, location} = item; - return ( - - } - accessibilityLabel={`View details for ${name}`} - name={name} - > -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} + return ( + + } + accessibilityLabel={`View details for ${name}`} + name={name} + > +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; -export function WithShortcutActions() { - return ( - - { - const {id, url, avatarSource, name, location, latestOrderUrl} = item; +export const WithShortcutActions = { + render() { + return ( + + { + const {id, url, avatarSource, name, location, latestOrderUrl} = + item; - return ( - - } - shortcutActions={[ - {content: 'View latest order', url: latestOrderUrl}, - ]} - accessibilityLabel={`View details for ${name}`} - name={name} - > -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} + return ( + + } + shortcutActions={[ + {content: 'View latest order', url: latestOrderUrl}, + ]} + accessibilityLabel={`View details for ${name}`} + name={name} + > +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; -export function WithPersistedShortcutActions() { - return ( - - { - const {id, url, avatarSource, name, location, latestOrderUrl} = item; - const shortcutActions = latestOrderUrl - ? [{content: 'View latest order', url: latestOrderUrl}] - : undefined; +export const WithPersistedShortcutActions = { + render() { + return ( + + { + const {id, url, avatarSource, name, location, latestOrderUrl} = + item; + const shortcutActions = latestOrderUrl + ? [{content: 'View latest order', url: latestOrderUrl}] + : undefined; - return ( - - } - persistActions - shortcutActions={shortcutActions} - accessibilityLabel={`View details for ${name}`} - name={name} - > -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} + return ( + + } + persistActions + shortcutActions={shortcutActions} + accessibilityLabel={`View details for ${name}`} + name={name} + > +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; -export function WithVerticalAlignment() { - return ( - - { - const {id, url, avatarSource, name, location, lastOrder} = item; - return ( - - } - accessibilityLabel={`View details for ${name}`} - name={name} - > -

- - {name} - -

-
{location}
-
{lastOrder}
-
- ); - }} - /> -
- ); -} +export const WithVerticalAlignment = { + render() { + return ( + + { + const {id, url, avatarSource, name, location, lastOrder} = item; + return ( + + } + accessibilityLabel={`View details for ${name}`} + name={name} + > +

+ + {name} + +

+
{location}
+
{lastOrder}
+
+ ); + }} + /> +
+ ); + }, +}; -export function WithDisabledState() { - const [selectedItems, setSelectedItems] = useState< - ResourceListProps['selectedItems'] - >([]); +export const WithDisabledState = { + render() { + const [selectedItems, setSelectedItems] = useState< + ResourceListProps['selectedItems'] + >([]); - return ( - - { - const {id, url, avatarSource, name, location} = item; + return ( + + { + const {id, url, avatarSource, name, location} = item; - return ( - - } - accessibilityLabel={`View details for ${name}`} - name={name} - > -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} + return ( + + } + accessibilityLabel={`View details for ${name}`} + name={name} + > +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; diff --git a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx index 506e41d3f6b..47775026b9c 100644 --- a/polaris-react/src/components/ResourceList/ResourceList.stories.tsx +++ b/polaris-react/src/components/ResourceList/ResourceList.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Avatar, Button, @@ -23,286 +23,213 @@ import {DeleteIcon} from '@shopify/polaris-icons'; export default { component: ResourceList, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - { - const {id, url, name, location} = item; - const media = ; - - return ( - -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} - -export function WithEmptyState() { - const items = []; - const appliedFilters = []; - const filters = []; - - const filterControl = ( - - ); - - const emptyStateMarkup = - !appliedFilters.length && !items.length ? ( - - - You can use the Files section to upload images, videos, and other - documents - - - ) : undefined; - - return ( - - - - - {}} - filterControl={filterControl} - resourceName={{singular: 'file', plural: 'files'}} - /> - - - - - ); -} - -export function WithSelectionAndNoBulkActions() { - const [selectedItems, setSelectedItems] = useState([]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = [ - { - id: 101, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 201, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]; - - return ( - - + { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; + +export const WithEmptyState = { + render() { + const items = []; + const appliedFilters = []; + const filters = []; + + const filterControl = ( + - - ); + ); - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; + const emptyStateMarkup = + !appliedFilters.length && !items.length ? ( + + + You can use the Files section to upload images, videos, and other + documents + + + ) : undefined; return ( - -

- - {name} - -

-
{location}
-
+ + + + + {}} + filterControl={filterControl} + resourceName={{singular: 'file', plural: 'files'}} + /> + + + + ); - } -} - -export function WithBulkActions() { - const [selectedItems, setSelectedItems] = useState([]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = [ - { - id: 103, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 203, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]; - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - return ( - - - - ); + }, +}; - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; +export const WithSelectionAndNoBulkActions = { + render() { + const [selectedItems, setSelectedItems] = useState([]); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const items = [ + { + id: 101, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 201, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]; return ( - -

- - {name} - -

-
{location}
-
+ + + ); - } -} - -export function WithBulkActionsAndManyItems() { - const [selectedItems, setSelectedItems] = useState([]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = Array.from({length: 50}, (_, num) => { - return { - id: `${num}`, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - orders: 20, - amountSpent: '$24,00', + + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + } + }, +}; + +export const WithBulkActions = { + render() { + const [selectedItems, setSelectedItems] = useState([]); + + const resourceName = { + singular: 'customer', + plural: 'customers', }; - }); - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - return ( - - + + const items = [ + { + id: 103, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 203, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]; + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + return ( + - - -
Total inventory at all locations
-
32069 available
-
-
- Content of another card -
- ); + ); - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; - return ( - -

- - {name} - -

-
{location}
-
- ); - } -} - -export function WithLoadingState() { - const [selectedItems, setSelectedItems] = useState([]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = [ - { - id: 104, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 204, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]; - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - return ( - - - - ); + return ( + +

+ + {name} + +

+
{location}
+
+ ); + } + }, +}; - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; +export const WithBulkActionsAndManyItems = { + render() { + const [selectedItems, setSelectedItems] = useState([]); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const items = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + orders: 20, + amountSpent: '$24,00', + }; + }); + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; return ( - -

- - {name} - -

-
{location}
-
+ + + + + +
Total inventory at all locations
+
32069 available
+
+
+
+ Content of another card +
); - } -} -export function WithTotalCount() { - return ( - - { - const {id, url, name, location} = item; - const media = ; + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; - return ( - -

- - {name} - -

-
{location}
-
- ); - }} - showHeader - totalItemsCount={50} - /> -
- ); -} + return ( + +

+ + {name} + +

+
{location}
+
+ ); + } + }, +}; -export function WithHeaderContent() { - return ( - - { - const {id, url, name, location} = item; - const media = ; +export const WithLoadingState = { + render() { + const [selectedItems, setSelectedItems] = useState([]); - return ( - -

- - {name} - -

-
{location}
-
- ); - }} - showHeader - /> -
- ); -} - -export function WithSorting() { - const [sortValue, setSortValue] = useState('DATE_MODIFIED_DESC'); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = [ - { - id: 106, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 206, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]; - - return ( - - { - setSortValue(selected); - console.log(`Sort option changed to ${selected}.`); - }} - /> - - ); + const resourceName = { + singular: 'customer', + plural: 'customers', + }; - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; + const items = [ + { + id: 104, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 204, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]; + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; return ( - -

- - {name} - -

-
{location}
-
+ + + ); - } -} - -export function WithAlternateTool() { - const resourceName = { - singular: 'Customer', - plural: 'Customers', - }; - - const items = [ - { - id: 107, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 207, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]; - - return ( - - Email customers} - /> - - ); - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; + return ( + +

+ + {name} + +

+
{location}
+
+ ); + } + }, +}; + +export const WithTotalCount = { + render() { return ( - -

- - {name} - -

-
{location}
-
+ + { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + }} + showHeader + totalItemsCount={50} + /> +
); - } -} - -export function WithFiltering() { - const [taggedWith, setTaggedWith] = useState('VIP'); - const [queryValue, setQueryValue] = useState(null); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = [ - { - id: 108, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 208, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - ]; - - const filters = [ - { - key: 'taggedWith1', - label: 'Tagged with', - filter: ( - + { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + }} + showHeader /> - ), - shortcut: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith1', - label: disambiguateLabel('taggedWith1', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - const filterControl = ( - -
- -
-
- ); - - return ( - - - - ); + + ); + }, +}; - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; +export const WithSorting = { + render() { + const [sortValue, setSortValue] = useState('DATE_MODIFIED_DESC'); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const items = [ + { + id: 106, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 206, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]; return ( - -

- - {name} - -

-
{location}
-
+ + { + setSortValue(selected); + console.log(`Sort option changed to ${selected}.`); + }} + /> + ); - } - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith1': - return `Tagged with ${value}`; - default: - return value; - } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); } - } -} - -export function WithACustomEmptySearchResultState() { - const [taggedWith, setTaggedWith] = useState('VIP'); - const [queryValue, setQueryValue] = useState(null); - const [items, setItems] = useState([]); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback((value) => { - setQueryValue(value); - setItems([]); - }, []); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const filters = [ - { - key: 'taggedWith2', - label: 'Tagged with', - filter: ( - - ), - shortcut: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith2', - label: disambiguateLabel('taggedWith2', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - const filterControl = ( - -
- -
-
- ); - - return ( - - This is a custom empty state
} - /> - - ); + }, +}; + +export const WithAlternateTool = { + render() { + const resourceName = { + singular: 'Customer', + plural: 'Customers', + }; - function renderItem(item) { - const {id, url, name, location} = item; - const media = ; + const items = [ + { + id: 107, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 207, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + ]; return ( - -

- - {name} - -

-
{location}
-
+ + Email customers} + /> + ); - } - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith2': - return `Tagged with ${value}`; - default: - return value; - } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); } - } -} + }, +}; -export function WithItemShortcutActions() { - return ( - - { - const {id, url, name, location, latestOrderUrl} = item; - const media = ; - const shortcutActions = latestOrderUrl - ? [ - { - content: 'View latest order', - accessibilityLabel: `View ${name}’s latest order`, - url: latestOrderUrl, - }, - ] - : null; +export const WithFiltering = { + render() { + const [taggedWith, setTaggedWith] = useState('VIP'); + const [queryValue, setQueryValue] = useState(null); - return ( - -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; -export function WithPersistentItemShortcutActions() { - return ( - - + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ { - id: 110, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - latestOrderUrl: '#', + key: 'taggedWith1', + label: disambiguateLabel('taggedWith1', taggedWith), + onRemove: handleTaggedWithRemove, }, + ] + : []; + + const filterControl = ( + +
+ +
+
+ ); + + return ( + + + + ); + + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + } + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith1': + return `Tagged with ${value}`; + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithACustomEmptySearchResultState = { + render() { + const [taggedWith, setTaggedWith] = useState('VIP'); + const [queryValue, setQueryValue] = useState(null); + const [items, setItems] = useState([]); + + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleQueryValueChange = useCallback((value) => { + setQueryValue(value); + setItems([]); + }, []); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const filters = [ + { + key: 'taggedWith2', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ { - id: 210, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - latestOrderUrl: '#', + key: 'taggedWith2', + label: disambiguateLabel('taggedWith2', taggedWith), + onRemove: handleTaggedWithRemove, }, - ]} - renderItem={(item) => { - const {id, url, name, location, latestOrderUrl} = item; - const media = ; - const shortcutActions = latestOrderUrl - ? [ - { - content: 'View latest order', - accessibilityLabel: `View ${name}’s latest order`, - url: latestOrderUrl, - }, - ] - : null; + ] + : []; + + const filterControl = ( + +
+ +
+
+ ); - return ( - -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} - -export function WithMultiselect() { - const [selectedItems, setSelectedItems] = useState([]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = [ - { - id: 111, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - }, - { - id: 211, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - }, - { - id: 311, - url: '#', - name: 'Joe Smith', - location: 'Arizona, USA', - }, - { - id: 411, - url: '#', - name: 'Haden Jerado', - location: 'Decatur, USA', - }, - { - id: 511, - url: '#', - name: 'Tom Thommas', - location: 'Florida, USA', - }, - { - id: 611, - url: '#', - name: 'Emily Amrak', - location: 'Texas, USA', - }, - ]; - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - return ( - - - - ); + return ( + + This is a custom empty state
} + /> +
+ ); - function renderItem(item, _, index) { - const {id, url, name, location} = item; - const media = ; + function renderItem(item) { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + } + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith2': + return `Tagged with ${value}`; + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithItemShortcutActions = { + render() { return ( - -

- - {name} - -

-
{location}
-
+ + { + const {id, url, name, location, latestOrderUrl} = item; + const media = ; + const shortcutActions = latestOrderUrl + ? [ + { + content: 'View latest order', + accessibilityLabel: `View ${name}’s latest order`, + url: latestOrderUrl, + }, + ] + : null; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
); - } - - function resolveItemIds({id}) { - return id; - } -} - -export function WithAllOfItsElements() { - const [selectedItems, setSelectedItems] = useState([]); - const [sortValue, setSortValue] = useState('DATE_MODIFIED_DESC'); - const [taggedWith, setTaggedWith] = useState('VIP'); - const [queryValue, setQueryValue] = useState(null); - - const handleTaggedWithChange = useCallback( - (value) => setTaggedWith(value), - [], - ); - const handleQueryValueChange = useCallback( - (value) => setQueryValue(value), - [], - ); - const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); - const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); - const handleClearAll = useCallback(() => { - handleTaggedWithRemove(); - handleQueryValueRemove(); - }, [handleQueryValueRemove, handleTaggedWithRemove]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = [ - { - id: 112, - url: '#', - name: 'Mae Jemison', - location: 'Decatur, USA', - latestOrderUrl: '#', - }, - { - id: 212, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', - latestOrderUrl: '#', - }, - ]; - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - const filters = [ - { - key: 'taggedWith3', - label: 'Tagged with', - filter: ( - + { + const {id, url, name, location, latestOrderUrl} = item; + const media = ; + const shortcutActions = latestOrderUrl + ? [ + { + content: 'View latest order', + accessibilityLabel: `View ${name}’s latest order`, + url: latestOrderUrl, + }, + ] + : null; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + }} /> - ), - shortcut: true, - }, - ]; - - const appliedFilters = !isEmpty(taggedWith) - ? [ - { - key: 'taggedWith3', - label: disambiguateLabel('taggedWith3', taggedWith), - onRemove: handleTaggedWithRemove, - }, - ] - : []; - - const filterControl = ( - -
- -
-
- ); - - return ( - - { - setSortValue(selected); - console.log(`Sort option changed to ${selected}.`); - }} - filterControl={filterControl} - /> - - ); - - function renderItem(item) { - const {id, url, name, location, latestOrderUrl} = item; - const media = ; - const shortcutActions = latestOrderUrl - ? [{content: 'View latest order', url: latestOrderUrl}] - : null; + + ); + }, +}; + +export const WithMultiselect = { + render() { + const [selectedItems, setSelectedItems] = useState([]); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const items = [ + { + id: 111, + url: '#', + name: 'Mae Jemison', + location: 'Decatur, USA', + }, + { + id: 211, + url: '#', + name: 'Ellen Ochoa', + location: 'Los Angeles, USA', + }, + { + id: 311, + url: '#', + name: 'Joe Smith', + location: 'Arizona, USA', + }, + { + id: 411, + url: '#', + name: 'Haden Jerado', + location: 'Decatur, USA', + }, + { + id: 511, + url: '#', + name: 'Tom Thommas', + location: 'Florida, USA', + }, + { + id: 611, + url: '#', + name: 'Emily Amrak', + location: 'Texas, USA', + }, + ]; + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + return ( - -

- - {name} - -

-
{location}
-
+ + + ); - } - - function disambiguateLabel(key, value) { - switch (key) { - case 'taggedWith3': - return `Tagged with ${value}`; - default: - return value; + + function renderItem(item, _, index) { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); } - } - function isEmpty(value) { - if (Array.isArray(value)) { - return value.length === 0; - } else { - return value === '' || value == null; + function resolveItemIds({id}) { + return id; } - } -} + }, +}; + +export const WithAllOfItsElements = { + render() { + const [selectedItems, setSelectedItems] = useState([]); + const [sortValue, setSortValue] = useState('DATE_MODIFIED_DESC'); + const [taggedWith, setTaggedWith] = useState('VIP'); + const [queryValue, setQueryValue] = useState(null); + + const handleTaggedWithChange = useCallback( + (value) => setTaggedWith(value), + [], + ); + const handleQueryValueChange = useCallback( + (value) => setQueryValue(value), + [], + ); + const handleTaggedWithRemove = useCallback(() => setTaggedWith(null), []); + const handleQueryValueRemove = useCallback(() => setQueryValue(null), []); + const handleClearAll = useCallback(() => { + handleTaggedWithRemove(); + handleQueryValueRemove(); + }, [handleQueryValueRemove, handleTaggedWithRemove]); + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; -export function WithPagination() { - return ( - - console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + const filters = [ + { + key: 'taggedWith3', + label: 'Tagged with', + filter: ( + + ), + shortcut: true, + }, + ]; + + const appliedFilters = !isEmpty(taggedWith) + ? [ { - id: 200, - url: '#', - name: 'Ellen Ochoa', - location: 'Los Angeles, USA', + key: 'taggedWith3', + label: disambiguateLabel('taggedWith3', taggedWith), + onRemove: handleTaggedWithRemove, }, - ]} - pagination={{ - hasNext: true, - onNext: () => {}, - }} - renderItem={(item) => { - const {id, url, name, location} = item; - const media = ; + ] + : []; + + const filterControl = ( + +
+ +
+
+ ); - return ( - -

- - {name} - -

-
{location}
-
- ); - }} - /> -
- ); -} - -export function WithBulkActionsAndPagination() { - const [selectedItems, setSelectedItems] = useState([]); - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = Array.from({length: 50}, (_, num) => { - return { - id: `${num}`, - url: '#', - name: `Mae Jemison ${num}`, - location: 'Decatur, USA', - orders: 20, - amountSpent: '$24,00', + return ( + + { + setSortValue(selected); + console.log(`Sort option changed to ${selected}.`); + }} + filterControl={filterControl} + /> + + ); + + function renderItem(item) { + const {id, url, name, location, latestOrderUrl} = item; + const media = ; + const shortcutActions = latestOrderUrl + ? [{content: 'View latest order', url: latestOrderUrl}] + : null; + return ( + +

+ + {name} + +

+
{location}
+
+ ); + } + + function disambiguateLabel(key, value) { + switch (key) { + case 'taggedWith3': + return `Tagged with ${value}`; + default: + return value; + } + } + + function isEmpty(value) { + if (Array.isArray(value)) { + return value.length === 0; + } else { + return value === '' || value == null; + } + } + }, +}; + +export const WithPagination = { + render() { + return ( + + {}, + }} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; + +export const WithBulkActionsAndPagination = { + render() { + const [selectedItems, setSelectedItems] = useState([]); + + const resourceName = { + singular: 'customer', + plural: 'customers', }; - }); - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - return ( - + + const items = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '#', + name: `Mae Jemison ${num}`, + location: 'Decatur, USA', + orders: 20, + amountSpent: '$24,00', + }; + }); + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + return ( + + {}, + }} + renderItem={(item) => { + const {id, url, name, location} = item; + const media = ; + + return ( + +

+ + {name} + +

+
{location}
+
+ ); + }} + /> +
+ ); + }, +}; + +export const WithinAModal = { + render() { + const [active, setActive] = useState(true); + const [checked, setChecked] = useState(false); + const [selectedItems, setSelectedItems] = useState([]); + + const toggleActive = () => setActive((active) => !active); + + const activator = ; + + const resourceName = { + singular: 'customer', + plural: 'customers', + }; + + const items = Array.from({length: 50}, (_, num) => { + return { + id: `${num}`, + url: '#', + name: `Mae Jemison ${num}`, + location: 'Decatur, USA', + orders: 20, + amountSpent: '$24,00', + }; + }); + + const promotedBulkActions = [ + { + content: 'Edit customers', + onAction: () => console.log('Todo: implement bulk edit'), + }, + ]; + + const bulkActions = [ + { + content: 'Add tags', + onAction: () => console.log('Todo: implement bulk add tags'), + }, + { + content: 'Remove tags', + onAction: () => console.log('Todo: implement bulk remove tags'), + }, + { + icon: DeleteIcon, + destructive: true, + content: 'Delete customers', + onAction: () => console.log('Todo: implement bulk delete'), + }, + ]; + + const listMarkup = ( {}, - }} renderItem={(item) => { const {id, url, name, location} = item; const media = ; @@ -1395,115 +1514,34 @@ export function WithBulkActionsAndPagination() { ); }} /> -
- ); -} - -export function WithinAModal() { - const [active, setActive] = useState(true); - const [checked, setChecked] = useState(false); - const [selectedItems, setSelectedItems] = useState([]); - - const toggleActive = () => setActive((active) => !active); - - const activator = ; - - const resourceName = { - singular: 'customer', - plural: 'customers', - }; - - const items = Array.from({length: 50}, (_, num) => { - return { - id: `${num}`, - url: '#', - name: `Mae Jemison ${num}`, - location: 'Decatur, USA', - orders: 20, - amountSpent: '$24,00', - }; - }); - - const promotedBulkActions = [ - { - content: 'Edit customers', - onAction: () => console.log('Todo: implement bulk edit'), - }, - ]; - - const bulkActions = [ - { - content: 'Add tags', - onAction: () => console.log('Todo: implement bulk add tags'), - }, - { - content: 'Remove tags', - onAction: () => console.log('Todo: implement bulk remove tags'), - }, - { - icon: DeleteIcon, - destructive: true, - content: 'Delete customers', - onAction: () => console.log('Todo: implement bulk delete'), - }, - ]; - - const listMarkup = ( - { - const {id, url, name, location} = item; - const media = ; - - return ( - -

- - {name} - -

-
{location}
-
- ); - }} - /> - ); - - return ( - -
- +
+ - - {listMarkup} - - -
- - ); -} + }} + secondaryActions={[ + { + content: 'Cancel', + onAction: toggleActive, + }, + ]} + > + + {listMarkup} + +
+
+ + ); + }, +}; diff --git a/polaris-react/src/components/Scrollable/Scrollable.stories.tsx b/polaris-react/src/components/Scrollable/Scrollable.stories.tsx index 891706076a1..e98697f25ae 100644 --- a/polaris-react/src/components/Scrollable/Scrollable.stories.tsx +++ b/polaris-react/src/components/Scrollable/Scrollable.stories.tsx @@ -1,5 +1,5 @@ import React, {ComponentRef, useRef} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Button, LegacyCard, @@ -15,1369 +15,97 @@ import type {ScrollableRef} from '@shopify/polaris'; export default { component: Scrollable, -} as ComponentMeta; - -export function Default() { - return ( - - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - - ); -} - -export function WithHorizonalScrollPrevention() { - return ( - -
- - Last updated on: September 6, 2022 - - - - Welcome to Shopify! By signing up for a Shopify Account (as defined in - Section 1) or by using any Shopify Services (as defined below), you - are agreeing to be bound by the following terms and conditions (the “ - Terms of Service”). - - - - As used in these Terms of Service, “we”, “ - us”, “our” and “ - Shopify” means the applicable Shopify Contracting - Party (as defined in Section 13 below), and “you” - means the Shopify User (if registering for or using a Shopify Service - as an individual), or the business employing the Shopify User (if - registering for or using a Shopify Service as a business) and any of - its affiliates. - - - - Shopify provides a complete commerce platform that enables merchants - to unify their commerce activities. Among other features, this - platform includes a range of tools for merchants to build and - customize online stores, sell in multiple places (including web, - mobile, social media, online marketplaces and other online locations - (“Online Services”) and in person (“ - POS Services”)), manage products, inventory, - payments, fulfillment, shipping, business operations, marketing and - advertising, and engage with existing and potential customers. Any - such service or services offered by Shopify are referred to in these - Terms of Services as the “Service(s)”. Any new - features or tools which are added to the current Services will also be - subject to the Terms of Service. You can review the current version of - the Terms of Service at any time at - - https://www.shopify.com/legal/terms - - . - - - - You must read, agree with and accept all of the terms and conditions - contained or expressly referenced in these Terms of Service, including - Shopify’s - Acceptable Use Policy - (“AUP”) and - Privacy Policy, - and, if applicable, the - - Supplementary Terms of Service for E.U. Merchants - - (“EU Terms”), the Shopify - - API License and Terms of Use - - (“API Terms”) and the Shopify - - Data Processing Addendum - - (“DPA”) before you may sign up for a Shopify Account - or use any Shopify Service. Additionally, if you offer goods or - services in relation to COVID-19, you must read, acknowledge and agree - to the - - Rules of Engagement for Sale of COVID-19 Related Products - - . - - - - - Everyday language summaries are provided for convenience only and - appear in bold near each section, but these summaries are not - legally binding. Please read the Terms of Service, including any - document referred to in these Terms of Service, for the complete - picture of your legal requirements. By using Shopify or any Shopify - services, you are agreeing to these terms. Be sure to occasionally - check back for updates. - - -
-
- ); -} - -export function WithGutterAndThinDragHandle() { - return ( - -
- - Last updated on: September 6, 2022 - - - - Welcome to Shopify! By signing up for a Shopify Account (as defined in - Section 1) or by using any Shopify Services (as defined below), you - are agreeing to be bound by the following terms and conditions (the “ - Terms of Service”). - - - - As used in these Terms of Service, “we”, “ - us”, “our” and “ - Shopify” means the applicable Shopify Contracting - Party (as defined in Section 13 below), and “you” - means the Shopify User (if registering for or using a Shopify Service - as an individual), or the business employing the Shopify User (if - registering for or using a Shopify Service as a business) and any of - its affiliates. - - - - Shopify provides a complete commerce platform that enables merchants - to unify their commerce activities. Among other features, this - platform includes a range of tools for merchants to build and - customize online stores, sell in multiple places (including web, - mobile, social media, online marketplaces and other online locations - (“Online Services”) and in person (“ - POS Services”)), manage products, inventory, - payments, fulfillment, shipping, business operations, marketing and - advertising, and engage with existing and potential customers. Any - such service or services offered by Shopify are referred to in these - Terms of Services as the “Service(s)”. Any new - features or tools which are added to the current Services will also be - subject to the Terms of Service. You can review the current version of - the Terms of Service at any time at - - https://www.shopify.com/legal/terms - - . - - - - You must read, agree with and accept all of the terms and conditions - contained or expressly referenced in these Terms of Service, including - Shopify’s - Acceptable Use Policy - (“AUP”) and - Privacy Policy, - and, if applicable, the - - Supplementary Terms of Service for E.U. Merchants - - (“EU Terms”), the Shopify - - API License and Terms of Use - - (“API Terms”) and the Shopify - - Data Processing Addendum - - (“DPA”) before you may sign up for a Shopify Account - or use any Shopify Service. Additionally, if you offer goods or - services in relation to COVID-19, you must read, acknowledge and agree - to the - - Rules of Engagement for Sale of COVID-19 Related Products - - . - - - - - Everyday language summaries are provided for convenience only and - appear in bold near each section, but these summaries are not - legally binding. Please read the Terms of Service, including any - document referred to in these Terms of Service, for the complete - picture of your legal requirements. By using Shopify or any Shopify - services, you are agreeing to these terms. Be sure to occasionally - check back for updates. - - -
-
- ); -} - -export function ScrollToChildComponent() { - return ( - - -
    -
  1. Account Terms
  2. -
- - You must be 18 years or older or at least the age of majority in the - jurisdiction where you reside or from which you use this Service. - - - To access and use the Services, you must register for a Shopify - account (“Account”) by providing your full legal name, current - address, phone number, a valid email address, and any other - information indicated as required. Shopify may reject your application - for an Account, or cancel an existing Account, for any reason, in our - sole discretion. - - - You acknowledge that Shopify will use the email address you provide as - the primary method for communication. - - - You are responsible for keeping your password secure. Shopify cannot - and will not be liable for any loss or damage from your failure to - maintain the security of your Account and password. - - - You are responsible for all activity and content such as photos, - images, videos, graphics, written content, audio files, code, - information, or data uploaded, collected, generated, stored, - displayed, distributed, transmitted or exhibited on or in connection - with your Account (“Materials”). - - - A breach or violation of any term in the Terms of Service, including - the AUP, as determined in the sole discretion of Shopify will result - in an immediate termination of your services. - - - Which means - - - You are responsible for your Account and any Materials you upload to - the Shopify Service. Remember that with any violation of these terms - we will cancel your service. - - - - If we need to reach you, we will send you an email. - - -
    -
  1. Account Activation
  2. -
- - - 2.1 Shopify Account - - - Subject to section 2.1.2, the person signing up for the Service will - be the contracting party (“Account Owner”) for the purposes of our - Terms of Service and will be the person who is authorized to use any - corresponding account we may provide to the Account Owner in - connection with the Service. - - - If you are signing up for the Service on behalf of your employer, your - employer shall be the Account Owner. If you are signing up for the - Service on behalf of your employer, then you represent and warrant - that you have the authority to bind your employer to our Terms of - Service. - - - 2.2 PayPal Express Checkout and Shopify Payments Accounts - - - - Upon completion of sign up for the Service, Shopify will create a - PayPal Express Checkout account on your behalf, using your email - address. Depending on your location, Shopify may also create a Shopify - Payments account on your behalf. - - - You acknowledge that PayPal Express Checkout and/or Shopify Payments - will be your default payments gateway(s) and that it is your sole - responsibility as the Account Owner to activate and maintain these - accounts. If you do not wish to keep either of the payment accounts - active, it is your responsibility to deactivate them. For the - avoidance of doubt, PayPal Express Checkout is a Third Party Service, - as defined in Section 15 of these Terms of Service. - - - 2.3 Apple Pay for Safari Account - - - - Upon completion of sign up for the Service, Shopify will create an - Apple Pay for Safari (“Apple Pay”) account on your behalf, using the - URL(s) and business name associated with your Account. Depending on - your location, Shopify may activate your Apple Pay account on your - behalf, otherwise you will be required to activate your Apple Pay - account within your Account admin. If you do not wish to keep your - Apple Pay account active, it is your responsibility to deactivate it. - For the avoidance of doubt, Apple Pay is a Third Party Service, as - defined in Section 15 of these Terms of Service. - - - If you use an Apple Pay supported payment gateway and your customers - have enabled Apple Pay on their device, customers may purchase goods - and services from your store using Apple Pay. - - - By using Apple Pay on your store, you are agreeing to be bound by the - Apple Pay Platform Web Merchant Terms and Conditions, as they may be - amended by Apple from time to time. If Apple amends the Apple Pay - Platform Web Merchant Terms and Conditions, the amended and restated - version will be posted here: - - https://www.shopify.com/legal/apple-pay - - . Such amendments to the Apple Pay Platform Web Merchant Terms are - effective as of the date of posting. Your continued use of Apple Pay - on your store after the amended Apple Pay Platform Web Merchant Terms - are posted constitutes your agreement to, and acceptance of, the - amended Apple Pay Platform Web Merchant Terms. If you do not agree to - any changes to the Apple Pay Platform Web Merchant Terms, de-activate - your Apple Pay account and do not continue to use Apple Pay on your - store. - - - 2.4 Google Payment - - - - Upon completion of sign up for the Service, if you have been enrolled - in Shopify Payments, Shopify will also create a Google Payment account - on your behalf. If you do not wish to keep your Google Payment account - active, it is your responsibility to deactivate it. For the avoidance - of doubt, Google Payment is a Third Party Service, as defined in - Section 15 of these Terms of Service. - - - - If you use a Google Payment supported payment gateway and your - customers have enabled Google Payment, customers may purchase goods - and services from your store using Google Payment. - - - - By using Google Payment on your store, you are agreeing to be bound by - the Google Payment API Terms of Service, as they may be amended by - Google from time to time. If Google amends the Google Payment API - Terms of Service, the amended and restated version will be posted - here: - - https://payments.developers.google.com/terms/sellertos - - . Such amendments to the Google Payment API Terms of Service are - effective as of the date of posting. Your continued use of Google - Payment on your store after the amended Google Payment API Terms of - Service are posted constitutes your agreement to, and acceptance of, - the amended Google Payment API Terms of Service. If you do not agree - to any changes to the Google Payment API Terms of Service, de-activate - your Google Payment account and do not continue to use Google Payment - on your store. - - - - 2.5 Domain Names - - - - Upon purchasing a domain name through Shopify, domain registration - will be preset to automatically renew each year so long as your - Shopify Account remains active. You acknowledge that it is your sole - responsibility to deactivate the auto-renewal function should you - choose to do so. - - - Which means - - - The person signing up for the Shopify Service is responsible for the - account and is bound by these Terms of Service. If you signup on - behalf of your employer, your employer owns the account and is also - bound by our Terms of Service. - - - - We automatically create accounts for you to accept payments. You are - responsible for activating and deactivating these accounts. - - - - Any domain you purchase through us will automatically renew unless you - opt out. - - -
    -
  1. General Conditions
  2. -
- - You must read, agree with and accept all of the terms and conditions - contained in these Terms of Service, including the AUP and the Privacy - Policy before you may become a member of Shopify. - - - - Technical support is only provided to paying Account holders and is - only available via email. - - - The Terms of Service shall be governed by and interpreted in - accordance with the laws of the Province of Ontario and the laws of - Canada applicable therein, without regard to principles of conflicts - of laws. The parties irrevocably and unconditionally submit to the - exclusive jurisdiction of the courts of the Province of Ontario with - respect to any dispute or claim arising out of or in connection with - the Terms of Service. The United Nations Convention on Contracts for - the International Sale of Goods will not apply to these Terms of - Service and is hereby expressly excluded. - - - You acknowledge and agree that Shopify may amend these Terms of - Service at any time by posting the relevant amended and restated Terms - of Service on Shopify’s website, available at - - https://www.shopify.com/legal/terms - - and such amendments to the Terms of Service are effective as of the - date of posting. Your continued use of the Services after the amended - Terms of Service are posted to Shopify’s website constitutes your - agreement to, and acceptance of, the amended Terms of Service. If you - do not agree to any changes to the Terms of Service, do not continue - to use the Service. - - - You may not use the Shopify service for any illegal or unauthorized - purpose nor may you, in the use of the Service, violate any laws in - your jurisdiction (including but not limited to copyright laws), the - laws applicable to you in your customer’s jurisdiction, or the laws of - Canada and the Province of Ontario. You will comply with all - applicable laws, rules and regulations in your use of the Service. - - - You agree not to reproduce, duplicate, copy, sell, resell or exploit - any portion of the Service, use of the Service, or access to the - Service without the express written permission by Shopify. - - - You shall not purchase search engine or other pay per click keywords - (such as Google AdWords), or domain names that use Shopify or Shopify - trademarks and/or variations and misspellings thereof. - - - Questions about the Terms of Service should be sent to - support@shopify.com. - - - You understand that your Materials (not including credit card - information), may be transferred unencrypted and involve (a) - transmissions over various networks; and (b) changes to conform and - adapt to technical requirements of connecting networks or devices. - Credit Card information is always encrypted during transfer over - networks. - - - You acknowledge and agree that your use of the Service, including - information transmitted to or stored by Shopify, is governed by its - privacy policy at - - https://www.shopify.com/legal/privacy - - - - The Terms of Service may be available in languages other than English. - To the extent of any inconsistencies or conflicts between these - English Terms of Service and Shopify’s Terms of Service available in - another language, the most current English version of the Terms of - Service at - - https://www.shopify.com/legal/terms - - will prevail. - - - Which means - - - The Shopify service belongs to us. You are not allowed to rip it off - or use it for any illegal or sketchy purpose. - - - - If a dispute arises the issue will be dealt with in the Province of - Ontario. - - - - Your Materials may be transferred unencrypted and may be altered, but - credit card information is always encrypted. - -
-
- ); -} - -export function WithScrollHint() { - return ( - - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - - ); -} - -export function OnScrolledToBottom() { - return ( - - console.log('scrolled to bottom')} - > - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - By signing up for the Shopify service (“Service”) or any of the - services of Shopify Inc. (“Shopify”) you are agreeing to be bound by - the following terms and conditions (“Terms of Service”). The Services - offered by Shopify under the Terms of Service include various products - and services to help you create and manage a retail store, whether an - online store (“Online Services”), a physical retail store (“POS - Services”), or both. Any new features or tools which are added to the - current Service shall be also subject to the Terms of Service. You can - review the current version of the Terms of Service at any time at - https://www.shopify.com/legal/terms. Shopify reserves the right to - update and change the Terms of Service by posting updates and changes - to the Shopify website. You are advised to check the Terms of Service - from time to time for any updates or changes that may impact you. - - - - ); -} - -export function UsingScrollToFromRef() { - const scrollRef = useRef(null); - - const handleOnClick = () => { - scrollRef.current?.scrollTo(0); - }; - - return ( - - -
    -
  1. Account Terms
  2. -
- - You must be 18 years or older or at least the age of majority in the - jurisdiction where you reside or from which you use this Service. - - - To access and use the Services, you must register for a Shopify - account (“Account”) by providing your full legal name, current - address, phone number, a valid email address, and any other - information indicated as required. Shopify may reject your application - for an Account, or cancel an existing Account, for any reason, in our - sole discretion. - - - You acknowledge that Shopify will use the email address you provide as - the primary method for communication. - - - You are responsible for keeping your password secure. Shopify cannot - and will not be liable for any loss or damage from your failure to - maintain the security of your Account and password. - - - You are responsible for all activity and content such as photos, - images, videos, graphics, written content, audio files, code, - information, or data uploaded, collected, generated, stored, - displayed, distributed, transmitted or exhibited on or in connection - with your Account (“Materials”). - - - A breach or violation of any term in the Terms of Service, including - the AUP, as determined in the sole discretion of Shopify will result - in an immediate termination of your services. - - - Which means - - - You are responsible for your Account and any Materials you upload to - the Shopify Service. Remember that with any violation of these terms - we will cancel your service. - - - - If we need to reach you, we will send you an email. - - -
    -
  1. Account Activation
  2. -
- - 2.1 Shopify Account - - - Subject to section 2.1.2, the person signing up for the Service will - be the contracting party (“Account Owner”) for the purposes of our - Terms of Service and will be the person who is authorized to use any - corresponding account we may provide to the Account Owner in - connection with the Service. - - - If you are signing up for the Service on behalf of your employer, your - employer shall be the Account Owner. If you are signing up for the - Service on behalf of your employer, then you represent and warrant - that you have the authority to bind your employer to our Terms of - Service. - - - 2.2 PayPal Express Checkout and Shopify Payments Accounts - - - - Upon completion of sign up for the Service, Shopify will create a - PayPal Express Checkout account on your behalf, using your email - address. Depending on your location, Shopify may also create a Shopify - Payments account on your behalf. - - - You acknowledge that PayPal Express Checkout and/or Shopify Payments - will be your default payments gateway(s) and that it is your sole - responsibility as the Account Owner to activate and maintain these - accounts. If you do not wish to keep either of the payment accounts - active, it is your responsibility to deactivate them. For the - avoidance of doubt, PayPal Express Checkout is a Third Party Service, - as defined in Section 15 of these Terms of Service. - - - 2.3 Apple Pay for Safari Account - - - - Upon completion of sign up for the Service, Shopify will create an - Apple Pay for Safari (“Apple Pay”) account on your behalf, using the - URL(s) and business name associated with your Account. Depending on - your location, Shopify may activate your Apple Pay account on your - behalf, otherwise you will be required to activate your Apple Pay - account within your Account admin. If you do not wish to keep your - Apple Pay account active, it is your responsibility to deactivate it. - For the avoidance of doubt, Apple Pay is a Third Party Service, as - defined in Section 15 of these Terms of Service. - - - If you use an Apple Pay supported payment gateway and your customers - have enabled Apple Pay on their device, customers may purchase goods - and services from your store using Apple Pay. - - - By using Apple Pay on your store, you are agreeing to be bound by the - Apple Pay Platform Web Merchant Terms and Conditions, as they may be - amended by Apple from time to time. If Apple amends the Apple Pay - Platform Web Merchant Terms and Conditions, the amended and restated - version will be posted here: - - https://www.shopify.com/legal/apple-pay - - . Such amendments to the Apple Pay Platform Web Merchant Terms are - effective as of the date of posting. Your continued use of Apple Pay - on your store after the amended Apple Pay Platform Web Merchant Terms - are posted constitutes your agreement to, and acceptance of, the - amended Apple Pay Platform Web Merchant Terms. If you do not agree to - any changes to the Apple Pay Platform Web Merchant Terms, de-activate - your Apple Pay account and do not continue to use Apple Pay on your - store. - - - 2.4 Google Payment - - - - Upon completion of sign up for the Service, if you have been enrolled - in Shopify Payments, Shopify will also create a Google Payment account - on your behalf. If you do not wish to keep your Google Payment account - active, it is your responsibility to deactivate it. For the avoidance - of doubt, Google Payment is a Third Party Service, as defined in - Section 15 of these Terms of Service. - - - - If you use a Google Payment supported payment gateway and your - customers have enabled Google Payment, customers may purchase goods - and services from your store using Google Payment. - - - - By using Google Payment on your store, you are agreeing to be bound by - the Google Payment API Terms of Service, as they may be amended by - Google from time to time. If Google amends the Google Payment API - Terms of Service, the amended and restated version will be posted - here: - - https://payments.developers.google.com/terms/sellertos - - . Such amendments to the Google Payment API Terms of Service are - effective as of the date of posting. Your continued use of Google - Payment on your store after the amended Google Payment API Terms of - Service are posted constitutes your agreement to, and acceptance of, - the amended Google Payment API Terms of Service. If you do not agree - to any changes to the Google Payment API Terms of Service, de-activate - your Google Payment account and do not continue to use Google Payment - on your store. - - - - 2.5 Domain Names - - - - Upon purchasing a domain name through Shopify, domain registration - will be preset to automatically renew each year so long as your - Shopify Account remains active. You acknowledge that it is your sole - responsibility to deactivate the auto-renewal function should you - choose to do so. - - - Which means - - - The person signing up for the Shopify Service is responsible for the - account and is bound by these Terms of Service. If you signup on - behalf of your employer, your employer owns the account and is also - bound by our Terms of Service. - - - - We automatically create accounts for you to accept payments. You are - responsible for activating and deactivating these accounts. - - - - Any domain you purchase through us will automatically renew unless you - opt out. - - -
    -
  1. General Conditions
  2. -
- - You must read, agree with and accept all of the terms and conditions - contained in these Terms of Service, including the AUP and the Privacy - Policy before you may become a member of Shopify. - - - - Technical support is only provided to paying Account holders and is - only available via email. - - - The Terms of Service shall be governed by and interpreted in - accordance with the laws of the Province of Ontario and the laws of - Canada applicable therein, without regard to principles of conflicts - of laws. The parties irrevocably and unconditionally submit to the - exclusive jurisdiction of the courts of the Province of Ontario with - respect to any dispute or claim arising out of or in connection with - the Terms of Service. The United Nations Convention on Contracts for - the International Sale of Goods will not apply to these Terms of - Service and is hereby expressly excluded. - - - You acknowledge and agree that Shopify may amend these Terms of - Service at any time by posting the relevant amended and restated Terms - of Service on Shopify’s website, available at - - https://www.shopify.com/legal/terms - - and such amendments to the Terms of Service are effective as of the - date of posting. Your continued use of the Services after the amended - Terms of Service are posted to Shopify’s website constitutes your - agreement to, and acceptance of, the amended Terms of Service. If you - do not agree to any changes to the Terms of Service, do not continue - to use the Service. - - - You may not use the Shopify service for any illegal or unauthorized - purpose nor may you, in the use of the Service, violate any laws in - your jurisdiction (including but not limited to copyright laws), the - laws applicable to you in your customer’s jurisdiction, or the laws of - Canada and the Province of Ontario. You will comply with all - applicable laws, rules and regulations in your use of the Service. - - - You agree not to reproduce, duplicate, copy, sell, resell or exploit - any portion of the Service, use of the Service, or access to the - Service without the express written permission by Shopify. - - - You shall not purchase search engine or other pay per click keywords - (such as Google AdWords), or domain names that use Shopify or Shopify - trademarks and/or variations and misspellings thereof. - - - Questions about the Terms of Service should be sent to - support@shopify.com. - - - You understand that your Materials (not including credit card - information), may be transferred unencrypted and involve (a) - transmissions over various networks; and (b) changes to conform and - adapt to technical requirements of connecting networks or devices. - Credit Card information is always encrypted during transfer over - networks. - - - You acknowledge and agree that your use of the Service, including - information transmitted to or stored by Shopify, is governed by its - privacy policy at - - https://www.shopify.com/legal/privacy - - - - The Terms of Service may be available in languages other than English. - To the extent of any inconsistencies or conflicts between these - English Terms of Service and Shopify’s Terms of Service available in - another language, the most current English version of the Terms of - Service at - - https://www.shopify.com/legal/terms - - will prevail. - - - Which means - - - The Shopify service belongs to us. You are not allowed to rip it off - or use it for any illegal or sketchy purpose. - - - - If a dispute arises the issue will be dealt with in the Province of - Ontario. - - - - Your Materials may be transferred unencrypted and may be altered, but - credit card information is always encrypted. - - -
-
- ); -} - -export function UsingInstantScrollToFromRef() { - const scrollRef = useRef(null); - - const handleOnClick = () => { - scrollRef.current?.scrollTo(0, {behavior: 'instant'}); - }; - - return ( - - -
    -
  1. Account Terms
  2. -
- - You must be 18 years or older or at least the age of majority in the - jurisdiction where you reside or from which you use this Service. - - - To access and use the Services, you must register for a Shopify - account (“Account”) by providing your full legal name, current - address, phone number, a valid email address, and any other - information indicated as required. Shopify may reject your application - for an Account, or cancel an existing Account, for any reason, in our - sole discretion. - - - You acknowledge that Shopify will use the email address you provide as - the primary method for communication. - - - You are responsible for keeping your password secure. Shopify cannot - and will not be liable for any loss or damage from your failure to - maintain the security of your Account and password. - - - You are responsible for all activity and content such as photos, - images, videos, graphics, written content, audio files, code, - information, or data uploaded, collected, generated, stored, - displayed, distributed, transmitted or exhibited on or in connection - with your Account (“Materials”). - - - A breach or violation of any term in the Terms of Service, including - the AUP, as determined in the sole discretion of Shopify will result - in an immediate termination of your services. - - - Which means - - - You are responsible for your Account and any Materials you upload to - the Shopify Service. Remember that with any violation of these terms - we will cancel your service. - - - - If we need to reach you, we will send you an email. - - -
    -
  1. Account Activation
  2. -
- - 2.1 Shopify Account - - - Subject to section 2.1.2, the person signing up for the Service will - be the contracting party (“Account Owner”) for the purposes of our - Terms of Service and will be the person who is authorized to use any - corresponding account we may provide to the Account Owner in - connection with the Service. - - - If you are signing up for the Service on behalf of your employer, your - employer shall be the Account Owner. If you are signing up for the - Service on behalf of your employer, then you represent and warrant - that you have the authority to bind your employer to our Terms of - Service. - - - 2.2 PayPal Express Checkout and Shopify Payments Accounts - - - - Upon completion of sign up for the Service, Shopify will create a - PayPal Express Checkout account on your behalf, using your email - address. Depending on your location, Shopify may also create a Shopify - Payments account on your behalf. - - - You acknowledge that PayPal Express Checkout and/or Shopify Payments - will be your default payments gateway(s) and that it is your sole - responsibility as the Account Owner to activate and maintain these - accounts. If you do not wish to keep either of the payment accounts - active, it is your responsibility to deactivate them. For the - avoidance of doubt, PayPal Express Checkout is a Third Party Service, - as defined in Section 15 of these Terms of Service. - - - 2.3 Apple Pay for Safari Account - - - - Upon completion of sign up for the Service, Shopify will create an - Apple Pay for Safari (“Apple Pay”) account on your behalf, using the - URL(s) and business name associated with your Account. Depending on - your location, Shopify may activate your Apple Pay account on your - behalf, otherwise you will be required to activate your Apple Pay - account within your Account admin. If you do not wish to keep your - Apple Pay account active, it is your responsibility to deactivate it. - For the avoidance of doubt, Apple Pay is a Third Party Service, as - defined in Section 15 of these Terms of Service. - - - If you use an Apple Pay supported payment gateway and your customers - have enabled Apple Pay on their device, customers may purchase goods - and services from your store using Apple Pay. - - - By using Apple Pay on your store, you are agreeing to be bound by the - Apple Pay Platform Web Merchant Terms and Conditions, as they may be - amended by Apple from time to time. If Apple amends the Apple Pay - Platform Web Merchant Terms and Conditions, the amended and restated - version will be posted here: - - https://www.shopify.com/legal/apple-pay - - . Such amendments to the Apple Pay Platform Web Merchant Terms are - effective as of the date of posting. Your continued use of Apple Pay - on your store after the amended Apple Pay Platform Web Merchant Terms - are posted constitutes your agreement to, and acceptance of, the - amended Apple Pay Platform Web Merchant Terms. If you do not agree to - any changes to the Apple Pay Platform Web Merchant Terms, de-activate - your Apple Pay account and do not continue to use Apple Pay on your - store. - - - 2.4 Google Payment - - - - Upon completion of sign up for the Service, if you have been enrolled - in Shopify Payments, Shopify will also create a Google Payment account - on your behalf. If you do not wish to keep your Google Payment account - active, it is your responsibility to deactivate it. For the avoidance - of doubt, Google Payment is a Third Party Service, as defined in - Section 15 of these Terms of Service. - - - - If you use a Google Payment supported payment gateway and your - customers have enabled Google Payment, customers may purchase goods - and services from your store using Google Payment. - - - - By using Google Payment on your store, you are agreeing to be bound by - the Google Payment API Terms of Service, as they may be amended by - Google from time to time. If Google amends the Google Payment API - Terms of Service, the amended and restated version will be posted - here: - - https://payments.developers.google.com/terms/sellertos - - . Such amendments to the Google Payment API Terms of Service are - effective as of the date of posting. Your continued use of Google - Payment on your store after the amended Google Payment API Terms of - Service are posted constitutes your agreement to, and acceptance of, - the amended Google Payment API Terms of Service. If you do not agree - to any changes to the Google Payment API Terms of Service, de-activate - your Google Payment account and do not continue to use Google Payment - on your store. - - - - 2.5 Domain Names - +} as Meta; - - Upon purchasing a domain name through Shopify, domain registration - will be preset to automatically renew each year so long as your - Shopify Account remains active. You acknowledge that it is your sole - responsibility to deactivate the auto-renewal function should you - choose to do so. - - - Which means - - - The person signing up for the Shopify Service is responsible for the - account and is bound by these Terms of Service. If you signup on - behalf of your employer, your employer owns the account and is also - bound by our Terms of Service. - - - - We automatically create accounts for you to accept payments. You are - responsible for activating and deactivating these accounts. - - - - Any domain you purchase through us will automatically renew unless you - opt out. - - -
    -
  1. General Conditions
  2. -
- - You must read, agree with and accept all of the terms and conditions - contained in these Terms of Service, including the AUP and the Privacy - Policy before you may become a member of Shopify. - - - - Technical support is only provided to paying Account holders and is - only available via email. - - - The Terms of Service shall be governed by and interpreted in - accordance with the laws of the Province of Ontario and the laws of - Canada applicable therein, without regard to principles of conflicts - of laws. The parties irrevocably and unconditionally submit to the - exclusive jurisdiction of the courts of the Province of Ontario with - respect to any dispute or claim arising out of or in connection with - the Terms of Service. The United Nations Convention on Contracts for - the International Sale of Goods will not apply to these Terms of - Service and is hereby expressly excluded. - - - You acknowledge and agree that Shopify may amend these Terms of - Service at any time by posting the relevant amended and restated Terms - of Service on Shopify’s website, available at - - https://www.shopify.com/legal/terms - - and such amendments to the Terms of Service are effective as of the - date of posting. Your continued use of the Services after the amended - Terms of Service are posted to Shopify’s website constitutes your - agreement to, and acceptance of, the amended Terms of Service. If you - do not agree to any changes to the Terms of Service, do not continue - to use the Service. - - - You may not use the Shopify service for any illegal or unauthorized - purpose nor may you, in the use of the Service, violate any laws in - your jurisdiction (including but not limited to copyright laws), the - laws applicable to you in your customer’s jurisdiction, or the laws of - Canada and the Province of Ontario. You will comply with all - applicable laws, rules and regulations in your use of the Service. - - - You agree not to reproduce, duplicate, copy, sell, resell or exploit - any portion of the Service, use of the Service, or access to the - Service without the express written permission by Shopify. - - - You shall not purchase search engine or other pay per click keywords - (such as Google AdWords), or domain names that use Shopify or Shopify - trademarks and/or variations and misspellings thereof. - - - Questions about the Terms of Service should be sent to - support@shopify.com. - - - You understand that your Materials (not including credit card - information), may be transferred unencrypted and involve (a) - transmissions over various networks; and (b) changes to conform and - adapt to technical requirements of connecting networks or devices. - Credit Card information is always encrypted during transfer over - networks. - - - You acknowledge and agree that your use of the Service, including - information transmitted to or stored by Shopify, is governed by its - privacy policy at - - https://www.shopify.com/legal/privacy - - - - The Terms of Service may be available in languages other than English. - To the extent of any inconsistencies or conflicts between these - English Terms of Service and Shopify’s Terms of Service available in - another language, the most current English version of the Terms of - Service at - - https://www.shopify.com/legal/terms - - will prevail. - - - Which means - - - The Shopify service belongs to us. You are not allowed to rip it off - or use it for any illegal or sketchy purpose. - - - - If a dispute arises the issue will be dealt with in the Province of - Ontario. - - - - Your Materials may be transferred unencrypted and may be altered, but - credit card information is always encrypted. - - -
-
- ); -} - -export function WithShadowOverComplexChildren() { - return ( - - - NOTE: Red shadow is for demo/debug purposes only. -
- DO NOT do this in production. -
+export const Default = { + render() { + return ( + + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + + ); + }, +}; + +export const WithHorizonalScrollPrevention = { + render() { + return ( - - - - Last updated on: September 6, 2022 - - - - Welcome to Shopify! By signing up for a Shopify Account (as - defined in Section 1) or by using any Shopify Services (as defined - below), you are agreeing to be bound by the following terms and - conditions (the “Terms of Service”). - - - - As used in these Terms of Service, “we”, “ - us”, “our” and “ - Shopify” means the applicable Shopify Contracting - Party (as defined in Section 13 below), and “you” - means the Shopify User (if registering for or using a Shopify - Service as an individual), or the business employing the Shopify - User (if registering for or using a Shopify Service as a business) - and any of its affiliates. - - - - - - - - +
+ + Last updated on: September 6, 2022 + - - - - + + Welcome to Shopify! By signing up for a Shopify Account (as defined + in Section 1) or by using any Shopify Services (as defined below), + you are agreeing to be bound by the following terms and conditions + (the “Terms of Service”). + - - - - - - + + As used in these Terms of Service, “we”, “ + us”, “our” and “ + Shopify” means the applicable Shopify Contracting + Party (as defined in Section 13 below), and “you” + means the Shopify User (if registering for or using a Shopify + Service as an individual), or the business employing the Shopify + User (if registering for or using a Shopify Service as a business) + and any of its affiliates. + Shopify provides a complete commerce platform that enables merchants @@ -1399,6 +127,7 @@ export function WithShadowOverComplexChildren() { . + You must read, agree with and accept all of the terms and conditions contained or expressly referenced in these Terms of Service, @@ -1441,8 +170,1311 @@ export function WithShadowOverComplexChildren() { occasionally check back for updates. - +
-
- ); -} + ); + }, +}; + +export const WithGutterAndThinDragHandle = { + render() { + return ( + +
+ + Last updated on: September 6, 2022 + + + + Welcome to Shopify! By signing up for a Shopify Account (as defined + in Section 1) or by using any Shopify Services (as defined below), + you are agreeing to be bound by the following terms and conditions + (the “Terms of Service”). + + + + As used in these Terms of Service, “we”, “ + us”, “our” and “ + Shopify” means the applicable Shopify Contracting + Party (as defined in Section 13 below), and “you” + means the Shopify User (if registering for or using a Shopify + Service as an individual), or the business employing the Shopify + User (if registering for or using a Shopify Service as a business) + and any of its affiliates. + + + + Shopify provides a complete commerce platform that enables merchants + to unify their commerce activities. Among other features, this + platform includes a range of tools for merchants to build and + customize online stores, sell in multiple places (including web, + mobile, social media, online marketplaces and other online locations + (“Online Services”) and in person (“ + POS Services”)), manage products, inventory, + payments, fulfillment, shipping, business operations, marketing and + advertising, and engage with existing and potential customers. Any + such service or services offered by Shopify are referred to in these + Terms of Services as the “Service(s)”. Any new + features or tools which are added to the current Services will also + be subject to the Terms of Service. You can review the current + version of the Terms of Service at any time at + + https://www.shopify.com/legal/terms + + . + + + + You must read, agree with and accept all of the terms and conditions + contained or expressly referenced in these Terms of Service, + including Shopify’s + + Acceptable Use Policy + + (“AUP”) and + Privacy Policy, + and, if applicable, the + + Supplementary Terms of Service for E.U. Merchants + + (“EU Terms”), the Shopify + + API License and Terms of Use + + (“API Terms”) and the Shopify + + Data Processing Addendum + + (“DPA”) before you may sign up for a Shopify + Account or use any Shopify Service. Additionally, if you offer goods + or services in relation to COVID-19, you must read, acknowledge and + agree to the + + Rules of Engagement for Sale of COVID-19 Related Products + + . + + + + + Everyday language summaries are provided for convenience only and + appear in bold near each section, but these summaries are not + legally binding. Please read the Terms of Service, including any + document referred to in these Terms of Service, for the complete + picture of your legal requirements. By using Shopify or any + Shopify services, you are agreeing to these terms. Be sure to + occasionally check back for updates. + + +
+
+ ); + }, +}; + +export const ScrollToChildComponent = { + render() { + return ( + + +
    +
  1. Account Terms
  2. +
+ + You must be 18 years or older or at least the age of majority in the + jurisdiction where you reside or from which you use this Service. + + + To access and use the Services, you must register for a Shopify + account (“Account”) by providing your full legal name, current + address, phone number, a valid email address, and any other + information indicated as required. Shopify may reject your + application for an Account, or cancel an existing Account, for any + reason, in our sole discretion. + + + You acknowledge that Shopify will use the email address you provide + as the primary method for communication. + + + You are responsible for keeping your password secure. Shopify cannot + and will not be liable for any loss or damage from your failure to + maintain the security of your Account and password. + + + You are responsible for all activity and content such as photos, + images, videos, graphics, written content, audio files, code, + information, or data uploaded, collected, generated, stored, + displayed, distributed, transmitted or exhibited on or in connection + with your Account (“Materials”). + + + A breach or violation of any term in the Terms of Service, including + the AUP, as determined in the sole discretion of Shopify will result + in an immediate termination of your services. + + + Which means + + + You are responsible for your Account and any Materials you upload to + the Shopify Service. Remember that with any violation of these terms + we will cancel your service. + + + + If we need to reach you, we will send you an email. + + +
    +
  1. Account Activation
  2. +
+ + + 2.1 Shopify Account + + + Subject to section 2.1.2, the person signing up for the Service will + be the contracting party (“Account Owner”) for the purposes of our + Terms of Service and will be the person who is authorized to use any + corresponding account we may provide to the Account Owner in + connection with the Service. + + + If you are signing up for the Service on behalf of your employer, + your employer shall be the Account Owner. If you are signing up for + the Service on behalf of your employer, then you represent and + warrant that you have the authority to bind your employer to our + Terms of Service. + + + 2.2 PayPal Express Checkout and Shopify Payments Accounts + + + + Upon completion of sign up for the Service, Shopify will create a + PayPal Express Checkout account on your behalf, using your email + address. Depending on your location, Shopify may also create a + Shopify Payments account on your behalf. + + + You acknowledge that PayPal Express Checkout and/or Shopify Payments + will be your default payments gateway(s) and that it is your sole + responsibility as the Account Owner to activate and maintain these + accounts. If you do not wish to keep either of the payment accounts + active, it is your responsibility to deactivate them. For the + avoidance of doubt, PayPal Express Checkout is a Third Party + Service, as defined in Section 15 of these Terms of Service. + + + 2.3 Apple Pay for Safari Account + + + + Upon completion of sign up for the Service, Shopify will create an + Apple Pay for Safari (“Apple Pay”) account on your behalf, using the + URL(s) and business name associated with your Account. Depending on + your location, Shopify may activate your Apple Pay account on your + behalf, otherwise you will be required to activate your Apple Pay + account within your Account admin. If you do not wish to keep your + Apple Pay account active, it is your responsibility to deactivate + it. For the avoidance of doubt, Apple Pay is a Third Party Service, + as defined in Section 15 of these Terms of Service. + + + If you use an Apple Pay supported payment gateway and your customers + have enabled Apple Pay on their device, customers may purchase goods + and services from your store using Apple Pay. + + + By using Apple Pay on your store, you are agreeing to be bound by + the Apple Pay Platform Web Merchant Terms and Conditions, as they + may be amended by Apple from time to time. If Apple amends the Apple + Pay Platform Web Merchant Terms and Conditions, the amended and + restated version will be posted here: + + https://www.shopify.com/legal/apple-pay + + . Such amendments to the Apple Pay Platform Web Merchant Terms are + effective as of the date of posting. Your continued use of Apple Pay + on your store after the amended Apple Pay Platform Web Merchant + Terms are posted constitutes your agreement to, and acceptance of, + the amended Apple Pay Platform Web Merchant Terms. If you do not + agree to any changes to the Apple Pay Platform Web Merchant Terms, + de-activate your Apple Pay account and do not continue to use Apple + Pay on your store. + + + 2.4 Google Payment + + + + Upon completion of sign up for the Service, if you have been + enrolled in Shopify Payments, Shopify will also create a Google + Payment account on your behalf. If you do not wish to keep your + Google Payment account active, it is your responsibility to + deactivate it. For the avoidance of doubt, Google Payment is a Third + Party Service, as defined in Section 15 of these Terms of Service. + + + + If you use a Google Payment supported payment gateway and your + customers have enabled Google Payment, customers may purchase goods + and services from your store using Google Payment. + + + + By using Google Payment on your store, you are agreeing to be bound + by the Google Payment API Terms of Service, as they may be amended + by Google from time to time. If Google amends the Google Payment API + Terms of Service, the amended and restated version will be posted + here: + + https://payments.developers.google.com/terms/sellertos + + . Such amendments to the Google Payment API Terms of Service are + effective as of the date of posting. Your continued use of Google + Payment on your store after the amended Google Payment API Terms of + Service are posted constitutes your agreement to, and acceptance of, + the amended Google Payment API Terms of Service. If you do not agree + to any changes to the Google Payment API Terms of Service, + de-activate your Google Payment account and do not continue to use + Google Payment on your store. + + + + 2.5 Domain Names + + + + Upon purchasing a domain name through Shopify, domain registration + will be preset to automatically renew each year so long as your + Shopify Account remains active. You acknowledge that it is your sole + responsibility to deactivate the auto-renewal function should you + choose to do so. + + + Which means + + + The person signing up for the Shopify Service is responsible for the + account and is bound by these Terms of Service. If you signup on + behalf of your employer, your employer owns the account and is also + bound by our Terms of Service. + + + + We automatically create accounts for you to accept payments. You are + responsible for activating and deactivating these accounts. + + + + Any domain you purchase through us will automatically renew unless + you opt out. + + +
    +
  1. General Conditions
  2. +
+ + You must read, agree with and accept all of the terms and conditions + contained in these Terms of Service, including the AUP and the + Privacy Policy before you may become a member of Shopify. + + + + Technical support is only provided to paying Account holders and is + only available via email. + + + The Terms of Service shall be governed by and interpreted in + accordance with the laws of the Province of Ontario and the laws of + Canada applicable therein, without regard to principles of conflicts + of laws. The parties irrevocably and unconditionally submit to the + exclusive jurisdiction of the courts of the Province of Ontario with + respect to any dispute or claim arising out of or in connection with + the Terms of Service. The United Nations Convention on Contracts for + the International Sale of Goods will not apply to these Terms of + Service and is hereby expressly excluded. + + + You acknowledge and agree that Shopify may amend these Terms of + Service at any time by posting the relevant amended and restated + Terms of Service on Shopify’s website, available at + + https://www.shopify.com/legal/terms + + and such amendments to the Terms of Service are effective as of the + date of posting. Your continued use of the Services after the + amended Terms of Service are posted to Shopify’s website constitutes + your agreement to, and acceptance of, the amended Terms of Service. + If you do not agree to any changes to the Terms of Service, do not + continue to use the Service. + + + You may not use the Shopify service for any illegal or unauthorized + purpose nor may you, in the use of the Service, violate any laws in + your jurisdiction (including but not limited to copyright laws), the + laws applicable to you in your customer’s jurisdiction, or the laws + of Canada and the Province of Ontario. You will comply with all + applicable laws, rules and regulations in your use of the Service. + + + You agree not to reproduce, duplicate, copy, sell, resell or exploit + any portion of the Service, use of the Service, or access to the + Service without the express written permission by Shopify. + + + You shall not purchase search engine or other pay per click keywords + (such as Google AdWords), or domain names that use Shopify or + Shopify trademarks and/or variations and misspellings thereof. + + + Questions about the Terms of Service should be sent to + support@shopify.com. + + + You understand that your Materials (not including credit card + information), may be transferred unencrypted and involve (a) + transmissions over various networks; and (b) changes to conform and + adapt to technical requirements of connecting networks or devices. + Credit Card information is always encrypted during transfer over + networks. + + + You acknowledge and agree that your use of the Service, including + information transmitted to or stored by Shopify, is governed by its + privacy policy at + + https://www.shopify.com/legal/privacy + + + + The Terms of Service may be available in languages other than + English. To the extent of any inconsistencies or conflicts between + these English Terms of Service and Shopify’s Terms of Service + available in another language, the most current English version of + the Terms of Service at + + https://www.shopify.com/legal/terms + + will prevail. + + + Which means + + + The Shopify service belongs to us. You are not allowed to rip it off + or use it for any illegal or sketchy purpose. + + + + If a dispute arises the issue will be dealt with in the Province of + Ontario. + + + + Your Materials may be transferred unencrypted and may be altered, + but credit card information is always encrypted. + +
+
+ ); + }, +}; + +export const WithScrollHint = { + render() { + return ( + + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + + ); + }, +}; + +export const OnScrolledToBottom = { + render() { + return ( + + console.log('scrolled to bottom')} + > + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + By signing up for the Shopify service (“Service”) or any of the + services of Shopify Inc. (“Shopify”) you are agreeing to be bound by + the following terms and conditions (“Terms of Service”). The + Services offered by Shopify under the Terms of Service include + various products and services to help you create and manage a retail + store, whether an online store (“Online Services”), a physical + retail store (“POS Services”), or both. Any new features or tools + which are added to the current Service shall be also subject to the + Terms of Service. You can review the current version of the Terms of + Service at any time at https://www.shopify.com/legal/terms. Shopify + reserves the right to update and change the Terms of Service by + posting updates and changes to the Shopify website. You are advised + to check the Terms of Service from time to time for any updates or + changes that may impact you. + + + + ); + }, +}; + +export const UsingScrollToFromRef = { + render() { + const scrollRef = useRef(null); + + const handleOnClick = () => { + scrollRef.current?.scrollTo(0); + }; + + return ( + + +
    +
  1. Account Terms
  2. +
+ + You must be 18 years or older or at least the age of majority in the + jurisdiction where you reside or from which you use this Service. + + + To access and use the Services, you must register for a Shopify + account (“Account”) by providing your full legal name, current + address, phone number, a valid email address, and any other + information indicated as required. Shopify may reject your + application for an Account, or cancel an existing Account, for any + reason, in our sole discretion. + + + You acknowledge that Shopify will use the email address you provide + as the primary method for communication. + + + You are responsible for keeping your password secure. Shopify cannot + and will not be liable for any loss or damage from your failure to + maintain the security of your Account and password. + + + You are responsible for all activity and content such as photos, + images, videos, graphics, written content, audio files, code, + information, or data uploaded, collected, generated, stored, + displayed, distributed, transmitted or exhibited on or in connection + with your Account (“Materials”). + + + A breach or violation of any term in the Terms of Service, including + the AUP, as determined in the sole discretion of Shopify will result + in an immediate termination of your services. + + + Which means + + + You are responsible for your Account and any Materials you upload to + the Shopify Service. Remember that with any violation of these terms + we will cancel your service. + + + + If we need to reach you, we will send you an email. + + +
    +
  1. Account Activation
  2. +
+ + 2.1 Shopify Account + + + Subject to section 2.1.2, the person signing up for the Service will + be the contracting party (“Account Owner”) for the purposes of our + Terms of Service and will be the person who is authorized to use any + corresponding account we may provide to the Account Owner in + connection with the Service. + + + If you are signing up for the Service on behalf of your employer, + your employer shall be the Account Owner. If you are signing up for + the Service on behalf of your employer, then you represent and + warrant that you have the authority to bind your employer to our + Terms of Service. + + + 2.2 PayPal Express Checkout and Shopify Payments Accounts + + + + Upon completion of sign up for the Service, Shopify will create a + PayPal Express Checkout account on your behalf, using your email + address. Depending on your location, Shopify may also create a + Shopify Payments account on your behalf. + + + You acknowledge that PayPal Express Checkout and/or Shopify Payments + will be your default payments gateway(s) and that it is your sole + responsibility as the Account Owner to activate and maintain these + accounts. If you do not wish to keep either of the payment accounts + active, it is your responsibility to deactivate them. For the + avoidance of doubt, PayPal Express Checkout is a Third Party + Service, as defined in Section 15 of these Terms of Service. + + + 2.3 Apple Pay for Safari Account + + + + Upon completion of sign up for the Service, Shopify will create an + Apple Pay for Safari (“Apple Pay”) account on your behalf, using the + URL(s) and business name associated with your Account. Depending on + your location, Shopify may activate your Apple Pay account on your + behalf, otherwise you will be required to activate your Apple Pay + account within your Account admin. If you do not wish to keep your + Apple Pay account active, it is your responsibility to deactivate + it. For the avoidance of doubt, Apple Pay is a Third Party Service, + as defined in Section 15 of these Terms of Service. + + + If you use an Apple Pay supported payment gateway and your customers + have enabled Apple Pay on their device, customers may purchase goods + and services from your store using Apple Pay. + + + By using Apple Pay on your store, you are agreeing to be bound by + the Apple Pay Platform Web Merchant Terms and Conditions, as they + may be amended by Apple from time to time. If Apple amends the Apple + Pay Platform Web Merchant Terms and Conditions, the amended and + restated version will be posted here: + + https://www.shopify.com/legal/apple-pay + + . Such amendments to the Apple Pay Platform Web Merchant Terms are + effective as of the date of posting. Your continued use of Apple Pay + on your store after the amended Apple Pay Platform Web Merchant + Terms are posted constitutes your agreement to, and acceptance of, + the amended Apple Pay Platform Web Merchant Terms. If you do not + agree to any changes to the Apple Pay Platform Web Merchant Terms, + de-activate your Apple Pay account and do not continue to use Apple + Pay on your store. + + + 2.4 Google Payment + + + + Upon completion of sign up for the Service, if you have been + enrolled in Shopify Payments, Shopify will also create a Google + Payment account on your behalf. If you do not wish to keep your + Google Payment account active, it is your responsibility to + deactivate it. For the avoidance of doubt, Google Payment is a Third + Party Service, as defined in Section 15 of these Terms of Service. + + + + If you use a Google Payment supported payment gateway and your + customers have enabled Google Payment, customers may purchase goods + and services from your store using Google Payment. + + + + By using Google Payment on your store, you are agreeing to be bound + by the Google Payment API Terms of Service, as they may be amended + by Google from time to time. If Google amends the Google Payment API + Terms of Service, the amended and restated version will be posted + here: + + https://payments.developers.google.com/terms/sellertos + + . Such amendments to the Google Payment API Terms of Service are + effective as of the date of posting. Your continued use of Google + Payment on your store after the amended Google Payment API Terms of + Service are posted constitutes your agreement to, and acceptance of, + the amended Google Payment API Terms of Service. If you do not agree + to any changes to the Google Payment API Terms of Service, + de-activate your Google Payment account and do not continue to use + Google Payment on your store. + + + + 2.5 Domain Names + + + + Upon purchasing a domain name through Shopify, domain registration + will be preset to automatically renew each year so long as your + Shopify Account remains active. You acknowledge that it is your sole + responsibility to deactivate the auto-renewal function should you + choose to do so. + + + Which means + + + The person signing up for the Shopify Service is responsible for the + account and is bound by these Terms of Service. If you signup on + behalf of your employer, your employer owns the account and is also + bound by our Terms of Service. + + + + We automatically create accounts for you to accept payments. You are + responsible for activating and deactivating these accounts. + + + + Any domain you purchase through us will automatically renew unless + you opt out. + + +
    +
  1. General Conditions
  2. +
+ + You must read, agree with and accept all of the terms and conditions + contained in these Terms of Service, including the AUP and the + Privacy Policy before you may become a member of Shopify. + + + + Technical support is only provided to paying Account holders and is + only available via email. + + + The Terms of Service shall be governed by and interpreted in + accordance with the laws of the Province of Ontario and the laws of + Canada applicable therein, without regard to principles of conflicts + of laws. The parties irrevocably and unconditionally submit to the + exclusive jurisdiction of the courts of the Province of Ontario with + respect to any dispute or claim arising out of or in connection with + the Terms of Service. The United Nations Convention on Contracts for + the International Sale of Goods will not apply to these Terms of + Service and is hereby expressly excluded. + + + You acknowledge and agree that Shopify may amend these Terms of + Service at any time by posting the relevant amended and restated + Terms of Service on Shopify’s website, available at + + https://www.shopify.com/legal/terms + + and such amendments to the Terms of Service are effective as of the + date of posting. Your continued use of the Services after the + amended Terms of Service are posted to Shopify’s website constitutes + your agreement to, and acceptance of, the amended Terms of Service. + If you do not agree to any changes to the Terms of Service, do not + continue to use the Service. + + + You may not use the Shopify service for any illegal or unauthorized + purpose nor may you, in the use of the Service, violate any laws in + your jurisdiction (including but not limited to copyright laws), the + laws applicable to you in your customer’s jurisdiction, or the laws + of Canada and the Province of Ontario. You will comply with all + applicable laws, rules and regulations in your use of the Service. + + + You agree not to reproduce, duplicate, copy, sell, resell or exploit + any portion of the Service, use of the Service, or access to the + Service without the express written permission by Shopify. + + + You shall not purchase search engine or other pay per click keywords + (such as Google AdWords), or domain names that use Shopify or + Shopify trademarks and/or variations and misspellings thereof. + + + Questions about the Terms of Service should be sent to + support@shopify.com. + + + You understand that your Materials (not including credit card + information), may be transferred unencrypted and involve (a) + transmissions over various networks; and (b) changes to conform and + adapt to technical requirements of connecting networks or devices. + Credit Card information is always encrypted during transfer over + networks. + + + You acknowledge and agree that your use of the Service, including + information transmitted to or stored by Shopify, is governed by its + privacy policy at + + https://www.shopify.com/legal/privacy + + + + The Terms of Service may be available in languages other than + English. To the extent of any inconsistencies or conflicts between + these English Terms of Service and Shopify’s Terms of Service + available in another language, the most current English version of + the Terms of Service at + + https://www.shopify.com/legal/terms + + will prevail. + + + Which means + + + The Shopify service belongs to us. You are not allowed to rip it off + or use it for any illegal or sketchy purpose. + + + + If a dispute arises the issue will be dealt with in the Province of + Ontario. + + + + Your Materials may be transferred unencrypted and may be altered, + but credit card information is always encrypted. + + +
+
+ ); + }, +}; + +export const UsingInstantScrollToFromRef = { + render() { + const scrollRef = useRef(null); + + const handleOnClick = () => { + scrollRef.current?.scrollTo(0, {behavior: 'instant'}); + }; + + return ( + + +
    +
  1. Account Terms
  2. +
+ + You must be 18 years or older or at least the age of majority in the + jurisdiction where you reside or from which you use this Service. + + + To access and use the Services, you must register for a Shopify + account (“Account”) by providing your full legal name, current + address, phone number, a valid email address, and any other + information indicated as required. Shopify may reject your + application for an Account, or cancel an existing Account, for any + reason, in our sole discretion. + + + You acknowledge that Shopify will use the email address you provide + as the primary method for communication. + + + You are responsible for keeping your password secure. Shopify cannot + and will not be liable for any loss or damage from your failure to + maintain the security of your Account and password. + + + You are responsible for all activity and content such as photos, + images, videos, graphics, written content, audio files, code, + information, or data uploaded, collected, generated, stored, + displayed, distributed, transmitted or exhibited on or in connection + with your Account (“Materials”). + + + A breach or violation of any term in the Terms of Service, including + the AUP, as determined in the sole discretion of Shopify will result + in an immediate termination of your services. + + + Which means + + + You are responsible for your Account and any Materials you upload to + the Shopify Service. Remember that with any violation of these terms + we will cancel your service. + + + + If we need to reach you, we will send you an email. + + +
    +
  1. Account Activation
  2. +
+ + 2.1 Shopify Account + + + Subject to section 2.1.2, the person signing up for the Service will + be the contracting party (“Account Owner”) for the purposes of our + Terms of Service and will be the person who is authorized to use any + corresponding account we may provide to the Account Owner in + connection with the Service. + + + If you are signing up for the Service on behalf of your employer, + your employer shall be the Account Owner. If you are signing up for + the Service on behalf of your employer, then you represent and + warrant that you have the authority to bind your employer to our + Terms of Service. + + + 2.2 PayPal Express Checkout and Shopify Payments Accounts + + + + Upon completion of sign up for the Service, Shopify will create a + PayPal Express Checkout account on your behalf, using your email + address. Depending on your location, Shopify may also create a + Shopify Payments account on your behalf. + + + You acknowledge that PayPal Express Checkout and/or Shopify Payments + will be your default payments gateway(s) and that it is your sole + responsibility as the Account Owner to activate and maintain these + accounts. If you do not wish to keep either of the payment accounts + active, it is your responsibility to deactivate them. For the + avoidance of doubt, PayPal Express Checkout is a Third Party + Service, as defined in Section 15 of these Terms of Service. + + + 2.3 Apple Pay for Safari Account + + + + Upon completion of sign up for the Service, Shopify will create an + Apple Pay for Safari (“Apple Pay”) account on your behalf, using the + URL(s) and business name associated with your Account. Depending on + your location, Shopify may activate your Apple Pay account on your + behalf, otherwise you will be required to activate your Apple Pay + account within your Account admin. If you do not wish to keep your + Apple Pay account active, it is your responsibility to deactivate + it. For the avoidance of doubt, Apple Pay is a Third Party Service, + as defined in Section 15 of these Terms of Service. + + + If you use an Apple Pay supported payment gateway and your customers + have enabled Apple Pay on their device, customers may purchase goods + and services from your store using Apple Pay. + + + By using Apple Pay on your store, you are agreeing to be bound by + the Apple Pay Platform Web Merchant Terms and Conditions, as they + may be amended by Apple from time to time. If Apple amends the Apple + Pay Platform Web Merchant Terms and Conditions, the amended and + restated version will be posted here: + + https://www.shopify.com/legal/apple-pay + + . Such amendments to the Apple Pay Platform Web Merchant Terms are + effective as of the date of posting. Your continued use of Apple Pay + on your store after the amended Apple Pay Platform Web Merchant + Terms are posted constitutes your agreement to, and acceptance of, + the amended Apple Pay Platform Web Merchant Terms. If you do not + agree to any changes to the Apple Pay Platform Web Merchant Terms, + de-activate your Apple Pay account and do not continue to use Apple + Pay on your store. + + + 2.4 Google Payment + + + + Upon completion of sign up for the Service, if you have been + enrolled in Shopify Payments, Shopify will also create a Google + Payment account on your behalf. If you do not wish to keep your + Google Payment account active, it is your responsibility to + deactivate it. For the avoidance of doubt, Google Payment is a Third + Party Service, as defined in Section 15 of these Terms of Service. + + + + If you use a Google Payment supported payment gateway and your + customers have enabled Google Payment, customers may purchase goods + and services from your store using Google Payment. + + + + By using Google Payment on your store, you are agreeing to be bound + by the Google Payment API Terms of Service, as they may be amended + by Google from time to time. If Google amends the Google Payment API + Terms of Service, the amended and restated version will be posted + here: + + https://payments.developers.google.com/terms/sellertos + + . Such amendments to the Google Payment API Terms of Service are + effective as of the date of posting. Your continued use of Google + Payment on your store after the amended Google Payment API Terms of + Service are posted constitutes your agreement to, and acceptance of, + the amended Google Payment API Terms of Service. If you do not agree + to any changes to the Google Payment API Terms of Service, + de-activate your Google Payment account and do not continue to use + Google Payment on your store. + + + + 2.5 Domain Names + + + + Upon purchasing a domain name through Shopify, domain registration + will be preset to automatically renew each year so long as your + Shopify Account remains active. You acknowledge that it is your sole + responsibility to deactivate the auto-renewal function should you + choose to do so. + + + Which means + + + The person signing up for the Shopify Service is responsible for the + account and is bound by these Terms of Service. If you signup on + behalf of your employer, your employer owns the account and is also + bound by our Terms of Service. + + + + We automatically create accounts for you to accept payments. You are + responsible for activating and deactivating these accounts. + + + + Any domain you purchase through us will automatically renew unless + you opt out. + + +
    +
  1. General Conditions
  2. +
+ + You must read, agree with and accept all of the terms and conditions + contained in these Terms of Service, including the AUP and the + Privacy Policy before you may become a member of Shopify. + + + + Technical support is only provided to paying Account holders and is + only available via email. + + + The Terms of Service shall be governed by and interpreted in + accordance with the laws of the Province of Ontario and the laws of + Canada applicable therein, without regard to principles of conflicts + of laws. The parties irrevocably and unconditionally submit to the + exclusive jurisdiction of the courts of the Province of Ontario with + respect to any dispute or claim arising out of or in connection with + the Terms of Service. The United Nations Convention on Contracts for + the International Sale of Goods will not apply to these Terms of + Service and is hereby expressly excluded. + + + You acknowledge and agree that Shopify may amend these Terms of + Service at any time by posting the relevant amended and restated + Terms of Service on Shopify’s website, available at + + https://www.shopify.com/legal/terms + + and such amendments to the Terms of Service are effective as of the + date of posting. Your continued use of the Services after the + amended Terms of Service are posted to Shopify’s website constitutes + your agreement to, and acceptance of, the amended Terms of Service. + If you do not agree to any changes to the Terms of Service, do not + continue to use the Service. + + + You may not use the Shopify service for any illegal or unauthorized + purpose nor may you, in the use of the Service, violate any laws in + your jurisdiction (including but not limited to copyright laws), the + laws applicable to you in your customer’s jurisdiction, or the laws + of Canada and the Province of Ontario. You will comply with all + applicable laws, rules and regulations in your use of the Service. + + + You agree not to reproduce, duplicate, copy, sell, resell or exploit + any portion of the Service, use of the Service, or access to the + Service without the express written permission by Shopify. + + + You shall not purchase search engine or other pay per click keywords + (such as Google AdWords), or domain names that use Shopify or + Shopify trademarks and/or variations and misspellings thereof. + + + Questions about the Terms of Service should be sent to + support@shopify.com. + + + You understand that your Materials (not including credit card + information), may be transferred unencrypted and involve (a) + transmissions over various networks; and (b) changes to conform and + adapt to technical requirements of connecting networks or devices. + Credit Card information is always encrypted during transfer over + networks. + + + You acknowledge and agree that your use of the Service, including + information transmitted to or stored by Shopify, is governed by its + privacy policy at + + https://www.shopify.com/legal/privacy + + + + The Terms of Service may be available in languages other than + English. To the extent of any inconsistencies or conflicts between + these English Terms of Service and Shopify’s Terms of Service + available in another language, the most current English version of + the Terms of Service at + + https://www.shopify.com/legal/terms + + will prevail. + + + Which means + + + The Shopify service belongs to us. You are not allowed to rip it off + or use it for any illegal or sketchy purpose. + + + + If a dispute arises the issue will be dealt with in the Province of + Ontario. + + + + Your Materials may be transferred unencrypted and may be altered, + but credit card information is always encrypted. + + +
+
+ ); + }, +}; + +export const WithShadowOverComplexChildren = { + render() { + return ( + + + NOTE: Red shadow is for demo/debug purposes only. +
+ DO NOT do this in production. +
+ + + + + Last updated on: September 6, 2022 + + + + Welcome to Shopify! By signing up for a Shopify Account (as + defined in Section 1) or by using any Shopify Services (as + defined below), you are agreeing to be bound by the following + terms and conditions (the “Terms of Service”). + + + + As used in these Terms of Service, “we”, “ + us”, “our” and “ + Shopify” means the applicable Shopify + Contracting Party (as defined in Section 13 below), and “ + you” means the Shopify User (if registering for + or using a Shopify Service as an individual), or the business + employing the Shopify User (if registering for or using a + Shopify Service as a business) and any of its affiliates. + + + + + + + + + + + + + + + + + + + + + + + Shopify provides a complete commerce platform that enables + merchants to unify their commerce activities. Among other + features, this platform includes a range of tools for merchants to + build and customize online stores, sell in multiple places + (including web, mobile, social media, online marketplaces and + other online locations (“Online Services”) and in + person (“ + POS Services”)), manage products, inventory, + payments, fulfillment, shipping, business operations, marketing + and advertising, and engage with existing and potential customers. + Any such service or services offered by Shopify are referred to in + these Terms of Services as the “Service(s)”. Any + new features or tools which are added to the current Services will + also be subject to the Terms of Service. You can review the + current version of the Terms of Service at any time at + + https://www.shopify.com/legal/terms + + . + + + You must read, agree with and accept all of the terms and + conditions contained or expressly referenced in these Terms of + Service, including Shopify’s + + Acceptable Use Policy + + (“AUP”) and + Privacy Policy + , and, if applicable, the + + Supplementary Terms of Service for E.U. Merchants + + (“EU Terms”), the Shopify + + API License and Terms of Use + + (“API Terms”) and the Shopify + + Data Processing Addendum + + (“DPA”) before you may sign up for a Shopify + Account or use any Shopify Service. Additionally, if you offer + goods or services in relation to COVID-19, you must read, + acknowledge and agree to the + + Rules of Engagement for Sale of COVID-19 Related Products + + . + + + + + Everyday language summaries are provided for convenience only + and appear in bold near each section, but these summaries are + not legally binding. Please read the Terms of Service, including + any document referred to in these Terms of Service, for the + complete picture of your legal requirements. By using Shopify or + any Shopify services, you are agreeing to these terms. Be sure + to occasionally check back for updates. + + + + +
+ ); + }, +}; diff --git a/polaris-react/src/components/Select/Select.stories.tsx b/polaris-react/src/components/Select/Select.stories.tsx index 00747dbb938..ab4a4d3c9a3 100644 --- a/polaris-react/src/components/Select/Select.stories.tsx +++ b/polaris-react/src/components/Select/Select.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { LegacyCard, FormLayout, @@ -15,305 +15,323 @@ import {CaretDownIcon, CaretUpIcon} from '@shopify/polaris-icons'; export default { component: Select, -} as ComponentMeta; +} as Meta; -export function Default() { - const [selected, setSelected] = useState('today'); +export const Default = { + render() { + const [selected, setSelected] = useState('today'); - const handleSelectChange = useCallback((value) => setSelected(value), []); + const handleSelectChange = useCallback((value) => setSelected(value), []); - const options = [ - {label: 'Today', value: 'today'}, - {label: 'Yesterday', value: 'yesterday'}, - {label: 'Last 7 days', value: 'lastWeek'}, - ]; + const options = [ + {label: 'Today', value: 'today'}, + {label: 'Yesterday', value: 'yesterday'}, + {label: 'Last 7 days', value: 'lastWeek'}, + ]; - return ( - + ); + }, +}; -export function WithInlineLabel() { - const [selected, setSelected] = useState('newestUpdate'); +export const WithInlineLabel = { + render() { + const [selected, setSelected] = useState('newestUpdate'); - const handleSelectChange = useCallback((value) => setSelected(value), []); + const handleSelectChange = useCallback((value) => setSelected(value), []); - const options = [ - {label: 'Newest update', value: 'newestUpdate'}, - {label: 'Oldest update', value: 'oldestUpdate'}, - {label: 'Most spent', value: 'mostSpent'}, - {label: 'Most orders', value: 'mostOrders'}, - {label: 'Last name A–Z', value: 'lastNameAlpha'}, - {label: 'Last name Z–A', value: 'lastNameReverseAlpha'}, - ]; + const options = [ + {label: 'Newest update', value: 'newestUpdate'}, + {label: 'Oldest update', value: 'oldestUpdate'}, + {label: 'Most spent', value: 'mostSpent'}, + {label: 'Most orders', value: 'mostOrders'}, + {label: 'Last name A–Z', value: 'lastNameAlpha'}, + {label: 'Last name Z–A', value: 'lastNameReverseAlpha'}, + ]; - return ( - + ); + }, +}; -export function Disabled() { - return ( - + ); + }, +}; -export function Magic() { - return ( - + ); + }, +}; + +export const WithInlineLabelMagic = { + render() { + const [selected, setSelected] = useState('newestUpdate'); -export function WithInlineLabelMagic() { - const [selected, setSelected] = useState('newestUpdate'); + const handleSelectChange = useCallback((value) => setSelected(value), []); - const handleSelectChange = useCallback((value) => setSelected(value), []); + const options = [ + {label: 'Newest update', value: 'newestUpdate'}, + {label: 'Oldest update', value: 'oldestUpdate'}, + {label: 'Most spent', value: 'mostSpent'}, + {label: 'Most orders', value: 'mostOrders'}, + {label: 'Last name A–Z', value: 'lastNameAlpha'}, + {label: 'Last name Z–A', value: 'lastNameReverseAlpha'}, + ]; - const options = [ - {label: 'Newest update', value: 'newestUpdate'}, - {label: 'Oldest update', value: 'oldestUpdate'}, - {label: 'Most spent', value: 'mostSpent'}, - {label: 'Most orders', value: 'mostOrders'}, - {label: 'Last name A–Z', value: 'lastNameAlpha'}, - {label: 'Last name Z–A', value: 'lastNameReverseAlpha'}, - ]; + return ( + - ); -} +export const WithPrefix = { + render() { + const [selected, setSelected] = useState('enabled'); -export function WithPrefix() { - const [selected, setSelected] = useState('enabled'); + const handleSelectChange = useCallback((value) => setSelected(value), []); - const handleSelectChange = useCallback((value) => setSelected(value), []); + const options = [ + { + label: 'Increase', + value: 'Increase', + prefix: , + }, + { + label: 'Decrease', + value: 'Decrease', + prefix: , + }, + ]; - const options = [ - { - label: 'Increase', - value: 'Increase', - prefix: , - }, - { - label: 'Decrease', - value: 'Decrease', - prefix: , - }, - ]; + return ( + - ); -} +export const WithValidationError = { + render() { + const [selected, setSelected] = useState(''); -export function WithValidationError() { - const [selected, setSelected] = useState(''); + const handleSelectChange = useCallback((value) => setSelected(value), []); - const handleSelectChange = useCallback((value) => setSelected(value), []); + return ( + - ); -} +export const WithSeparateValidationError = { + render() { + const [weight, setWeight] = useState('12'); + const [unit, setUnit] = useState(''); -export function WithSeparateValidationError() { - const [weight, setWeight] = useState('12'); - const [unit, setUnit] = useState(''); + const handleWeightChange = useCallback((value) => setWeight(value), []); + const handleUnitChange = useCallback((value) => setUnit(value), []); - const handleWeightChange = useCallback((value) => setWeight(value), []); - const handleUnitChange = useCallback((value) => setUnit(value), []); + const unitSelectID = 'unit'; + const errorMessage = generateErrorMessage(); + const formGroupMarkup = ( + + + + + - - - - - ); + return {formGroupMarkup}; - return {formGroupMarkup}; + function generateErrorMessage() { + const weightError = + !weight && unit ? 'The numeric weight of the product ' : ''; + const unitError = + !unit && weight ? 'The unit of measure for the product weight' : ''; - function generateErrorMessage() { - const weightError = - !weight && unit ? 'The numeric weight of the product ' : ''; - const unitError = - !unit && weight ? 'The unit of measure for the product weight' : ''; + if (!weightError && !unitError) { + return ''; + } - if (!weightError && !unitError) { - return ''; + return ( + + {`${weightError}${unitError} is required when weight based shipping rates are enabled. `} + Manage shipping + + ); } + }, +}; +export const All = { + render() { return ( - - {`${weightError}${unitError} is required when weight based shipping rates are enabled. `} - Manage shipping - + + + {}} + disabled + helpText="Help text" + /> + {}} + /> + {}} + /> + {}} + /> + {}} + labelInline + /> + {}} + labelHidden + /> + + ); - } -} - -export function All() { - return ( - - - {}} - disabled - helpText="Help text" - /> - {}} - /> - {}} - /> - {}} - /> - {}} - labelInline - /> - {}} - labelHidden - /> - - - ); -} + }, +}; diff --git a/polaris-react/src/components/SelectAllActions/SelectAllActions.stories.tsx b/polaris-react/src/components/SelectAllActions/SelectAllActions.stories.tsx index 2191ab9041b..a6670b30a89 100644 --- a/polaris-react/src/components/SelectAllActions/SelectAllActions.stories.tsx +++ b/polaris-react/src/components/SelectAllActions/SelectAllActions.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; // eslint-disable-next-line import/no-deprecated import {SelectAllActions} from './SelectAllActions'; @@ -8,73 +8,81 @@ export default { // eslint-disable-next-line import/no-deprecated component: SelectAllActions, // eslint-disable-next-line import/no-deprecated -} as ComponentMeta; +} as Meta; -export function Default() { - const paginatedSelectAllAction = { - content: 'Select all', - onAction: () => console.log('paginatedSelectAllAction clicked'), - }; - return ( - - ); -} +export const Default = { + render() { + const paginatedSelectAllAction = { + content: 'Select all', + onAction: () => console.log('paginatedSelectAllAction clicked'), + }; + return ( + + ); + }, +}; -export function WithPaginatedSelectAllText() { - const paginatedSelectAllAction = { - content: 'Select all', - onAction: () => console.log('paginatedSelectAllAction clicked'), - }; - return ( - - ); -} +export const WithPaginatedSelectAllText = { + render() { + const paginatedSelectAllAction = { + content: 'Select all', + onAction: () => console.log('paginatedSelectAllAction clicked'), + }; + return ( + + ); + }, +}; -export function WithPagination() { - const paginatedSelectAllAction = { - content: 'Select all', - onAction: () => console.log('paginatedSelectAllAction clicked'), - }; - return ( - - ); -} +export const WithPagination = { + render() { + const paginatedSelectAllAction = { + content: 'Select all', + onAction: () => console.log('paginatedSelectAllAction clicked'), + }; + return ( + + ); + }, +}; -export function WithDeprecatedProps() { - const paginatedSelectAllAction = { - content: 'Select all', - onAction: () => console.log('paginatedSelectAllAction clicked'), - }; - return ( - console.log('onToggleAll called')} - /> - ); -} +export const WithDeprecatedProps = { + render() { + const paginatedSelectAllAction = { + content: 'Select all', + onAction: () => console.log('paginatedSelectAllAction clicked'), + }; + return ( + console.log('onToggleAll called')} + /> + ); + }, +}; diff --git a/polaris-react/src/components/SettingToggle/SettingToggle.stories.tsx b/polaris-react/src/components/SettingToggle/SettingToggle.stories.tsx index 28969c29ce6..a6f174dd073 100644 --- a/polaris-react/src/components/SettingToggle/SettingToggle.stories.tsx +++ b/polaris-react/src/components/SettingToggle/SettingToggle.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { SettingToggle, Text, @@ -15,246 +15,261 @@ import {InfoIcon} from '@shopify/polaris-icons'; export default { component: SettingToggle, -} as ComponentMeta; - -export function WithDeprecatedComponent() { - const [enabled, setEnabled] = useState(false); - - const contentStatus = enabled ? 'Turn off' : 'Turn on'; - - const handleToggle = useCallback(() => setEnabled((enabled) => !enabled), []); - - return ( - - - Simulate transactions to test your checkout and order flows. When test - mode is on, checkout does not accept real credit cards. - - - ); -} - -export function WithPrimitiveComponents() { - const [enabled, setEnabled] = useState(true); - - const handleToggle = useCallback(() => setEnabled((enabled) => !enabled), []); - - const contentStatus = enabled ? 'Turn off' : 'Turn on'; - - const toggleId = 'setting-toggle-uuid'; - const descriptionId = 'setting-toggle-description-uuid'; - - const {mdDown} = useBreakpoints(); - - const badgeTone = enabled ? 'success' : undefined; - - const badgeContent = enabled ? 'On' : 'Off'; - - const title = 'Test mode'; - const description = - 'Simulate transactions to test your checkout and order flows. When test mode is on, checkout does not accept real credit cards.'; - - const settingStatusMarkup = ( - - {badgeContent} - - ); - - const helpLink = ( - - ); - - const headerMarkup = ( - - - {settingTitle} - {!mdDown ? ( - - {actionMarkup} + {contentStatus} + + ); + + const headerMarkup = ( + + + {settingTitle} + {!mdDown ? ( + + {actionMarkup} + + ) : null} + + + ); + + const descriptionMarkup = ( + + + {description} + + {mdDown ? ( + + {actionMarkup} ) : null} - - - ); - - const descriptionMarkup = ( - - - {description} - - {mdDown ? ( - - {actionMarkup} - - ) : null} - - ); - - return ( - - - - - {headerMarkup} - {descriptionMarkup} - - - - Your checkout is only accepting test payments. - - - ); -} - -export function WithPrimitiveComponentsAndLongTitle() { - const [enabled, setEnabled] = useState(true); - - const handleToggle = useCallback(() => setEnabled((enabled) => !enabled), []); + ); + + return ( + + + + + {headerMarkup} + {descriptionMarkup} + + + + Your checkout is only accepting test payments. + + + + ); + }, +}; - const contentStatus = enabled ? 'Turn off' : 'Turn on'; +export const WithPrimitiveComponentsAndLongTitle = { + render() { + const [enabled, setEnabled] = useState(true); - const toggleId = 'setting-toggle-uuid'; - const descriptionId = 'setting-toggle-description-uuid'; + const handleToggle = useCallback( + () => setEnabled((enabled) => !enabled), + [], + ); - const {mdDown} = useBreakpoints(); + const contentStatus = enabled ? 'Turn off' : 'Turn on'; - const badgeTone = enabled ? 'success' : undefined; + const toggleId = 'setting-toggle-uuid'; + const descriptionId = 'setting-toggle-description-uuid'; - const badgeContent = enabled ? 'On' : 'Off'; + const {mdDown} = useBreakpoints(); - const title = - 'Test mode but with very long mega title that wraps to demonstrate how layout changes'; - const description = - 'Simulate transactions to test your checkout and order flows. When test mode is on, checkout does not accept real credit cards.'; + const badgeTone = enabled ? 'success' : undefined; - const settingStatusMarkup = ( - - {badgeContent} - - ); + const badgeContent = enabled ? 'On' : 'Off'; - const helpLink = ( - - ); - - const headerMarkup = ( - - - {settingTitle} - {!mdDown ? ( - - {actionMarkup} + {contentStatus} + + ); + + const headerMarkup = ( + + + {settingTitle} + {!mdDown ? ( + + {actionMarkup} + + ) : null} + + + ); + + const descriptionMarkup = ( + + + {description} + + {mdDown ? ( + + {actionMarkup} ) : null} - - - ); - - const descriptionMarkup = ( - - - {description} - - {mdDown ? ( - - {actionMarkup} - - ) : null} - - ); - - return ( - - - - - {headerMarkup} - {descriptionMarkup} - - - - Your checkout is only accepting test payments. - - - ); -} + ); + + return ( + + + + + {headerMarkup} + {descriptionMarkup} + + + + Your checkout is only accepting test payments. + + + + ); + }, +}; diff --git a/polaris-react/src/components/ShadowBevel/ShadowBevel.stories.tsx b/polaris-react/src/components/ShadowBevel/ShadowBevel.stories.tsx index 1b30869be7e..113f667d0e8 100644 --- a/polaris-react/src/components/ShadowBevel/ShadowBevel.stories.tsx +++ b/polaris-react/src/components/ShadowBevel/ShadowBevel.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import type {BoxProps} from '@shopify/polaris'; import {Box, BlockStack, InlineCode} from '@shopify/polaris'; @@ -7,82 +7,84 @@ import {ShadowBevel} from './ShadowBevel'; export default { component: ShadowBevel, -} as ComponentMeta; +} as Meta; -export function Default() { - const colors: BoxProps[] = [ - { - background: 'bg-fill-success', - color: 'text-success-on-bg-fill', - }, - { - background: 'bg-fill-info', - color: 'text-info-on-bg-fill', - }, - { - background: 'bg-fill-warning', - color: 'text-warning-on-bg-fill', - }, - { - background: 'bg-fill-critical', - color: 'text-critical-on-bg-fill', - }, - ]; +export const Default = { + render() { + const colors: BoxProps[] = [ + { + background: 'bg-fill-success', + color: 'text-success-on-bg-fill', + }, + { + background: 'bg-fill-info', + color: 'text-info-on-bg-fill', + }, + { + background: 'bg-fill-warning', + color: 'text-warning-on-bg-fill', + }, + { + background: 'bg-fill-critical', + color: 'text-critical-on-bg-fill', + }, + ]; - return ( - - - - Default - - - - - - With bevel: false - - - - - - With bevel: {'{xs: false, sm: true}'} - - + return ( + + + + Default + + - - - With{' '} - bevel: {'{xs: false, sm: true, lg: false}'} - - + + + With bevel: false + + - - - With as: article - - + + + With bevel: {'{xs: false, sm: true}'} + + - {colors.map(({background, color}) => ( - - {background} + + With{' '} + bevel: {'{xs: false, sm: true, lg: false}'} - ))} -
-
- ); -} + + + With as: article + + + + {colors.map(({background, color}) => ( + + + {background} + + + ))} + +
+
+ ); + }, +}; diff --git a/polaris-react/src/components/Sheet/Sheet.stories.tsx b/polaris-react/src/components/Sheet/Sheet.stories.tsx index cff9c00926c..168177ec24c 100644 --- a/polaris-react/src/components/Sheet/Sheet.stories.tsx +++ b/polaris-react/src/components/Sheet/Sheet.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Button, LegacyCard, @@ -21,509 +21,513 @@ import {XIcon, SearchIcon} from '@shopify/polaris-icons'; export default { component: Sheet, parameters: {layout: 'fullscreen'}, -} as ComponentMeta; - -export function Default() { - const [sheetActive, setSheetActive] = useState(true); - const [title, setTitle] = useState('Big yellow socks'); - const [description, setDescription] = useState( - "They’re big, yellow socks. What more could you possibly want from socks? These socks will change your life.\n\nThey’re made from light, hand-loomed cotton that’s so soft, you'll feel like you are walking on a cloud.", - ); - const [salesChannels, setSalesChannels] = useState([ - {value: 'onlineStore', label: 'Online Store'}, - {value: 'facebook', label: 'Facebook'}, - {value: 'googleShopping', label: 'Google shopping'}, - {value: 'facebookMarketing', label: 'Facebook Marketing'}, - ]); - const [selected, setSelected] = useState([]); - - const toggleSheetActive = useCallback( - () => setSheetActive((sheetActive) => !sheetActive), - [], - ); - const handleSelectedChange = useCallback((value) => setSelected(value), []); - const handleTitleChange = useCallback((value) => setTitle(value), []); - const handleDescriptionChange = useCallback( - (value) => setDescription(value), - [], - ); - - const selectedSalesChannels = selected.map((key) => { - return salesChannels.reduce((accumulator, current) => { - accumulator[current.value] = current.label; - return accumulator; - }, {})[key]; - }); - const hasSelectedSalesChannels = selectedSalesChannels.length > 0; - - const salesChannelsCardMarkup = hasSelectedSalesChannels ? ( - - {selectedSalesChannels.map((channel, index) => ( - {channel} - ))} - - ) : ( -
- - No sales channels selected - - -
- ); - - const salesChannelAction = hasSelectedSalesChannels - ? [ - { - onAction: toggleSheetActive, - content: 'Manage sales channels', - }, - ] - : undefined; - - return ( - - - {salesChannelsCardMarkup} - - ; + +export const Default = { + render() { + const [sheetActive, setSheetActive] = useState(true); + const [title, setTitle] = useState('Big yellow socks'); + const [description, setDescription] = useState( + "They’re big, yellow socks. What more could you possibly want from socks? These socks will change your life.\n\nThey’re made from light, hand-loomed cotton that’s so soft, you'll feel like you are walking on a cloud.", + ); + const [salesChannels, setSalesChannels] = useState([ + {value: 'onlineStore', label: 'Online Store'}, + {value: 'facebook', label: 'Facebook'}, + {value: 'googleShopping', label: 'Google shopping'}, + {value: 'facebookMarketing', label: 'Facebook Marketing'}, + ]); + const [selected, setSelected] = useState([]); + + const toggleSheetActive = useCallback( + () => setSheetActive((sheetActive) => !sheetActive), + [], + ); + const handleSelectedChange = useCallback((value) => setSelected(value), []); + const handleTitleChange = useCallback((value) => setTitle(value), []); + const handleDescriptionChange = useCallback( + (value) => setDescription(value), + [], + ); + + const selectedSalesChannels = selected.map((key) => { + return salesChannels.reduce((accumulator, current) => { + accumulator[current.value] = current.label; + return accumulator; + }, {})[key]; + }); + const hasSelectedSalesChannels = selectedSalesChannels.length > 0; + + const salesChannelsCardMarkup = hasSelectedSalesChannels ? ( + + {selectedSalesChannels.map((channel, index) => ( + {channel} + ))} + + ) : ( +
-
+ No sales channels selected + + +
+ ); + + const salesChannelAction = hasSelectedSalesChannels + ? [ + { + onAction: toggleSheetActive, + content: 'Manage sales channels', + }, + ] + : undefined; + + return ( + + + {salesChannelsCardMarkup} + +
- - Manage sales channels - -
- - - -
- - +
+ + Manage sales channels + +
+ + + +
+ + +
-
-
-
- ); -} - -export function WithSearchableListbox() { - const actionValue = '__ACTION__'; - - interface CustomerSegment { - id: string; - label: string; - value: string; - } - - const segments: CustomerSegment[] = [ - { - label: 'All customers', - id: 'gid://shopify/CustomerSegment/1', - value: '0', - }, - { - label: 'VIP customers', - id: 'gid://shopify/CustomerSegment/2', - value: '1', - }, - { - label: 'New customers', - id: 'gid://shopify/CustomerSegment/3', - value: '2', - }, - { - label: 'Abandoned carts - last 30 days', - id: 'gid://shopify/CustomerSegment/4', - value: '3', - }, - { - label: 'Wholesale customers', - id: 'gid://shopify/CustomerSegment/5', - value: '4', - }, - { - label: 'Email subscribers', - id: 'gid://shopify/CustomerSegment/6', - value: '5', - }, - { - label: 'From New York', - id: 'gid://shopify/CustomerSegment/7', - value: '6', - }, - { - label: 'Repeat buyers', - id: 'gid://shopify/CustomerSegment/8', - value: '7', - }, - { - label: 'First time buyers', - id: 'gid://shopify/CustomerSegment/9', - value: '8', - }, - { - label: 'From Canada', - id: 'gid://shopify/CustomerSegment/10', - value: '9', - }, - { - label: 'Bought in last 60 days', - id: 'gid://shopify/CustomerSegment/11', - value: '10', - }, - { - label: 'Bought last BFCM', - id: 'gid://shopify/CustomerSegment/12', - value: '11', - }, - ]; - - const lazyLoadSegments: CustomerSegment[] = Array.from(Array(100)).map( - (_, index) => ({ - label: `Other customers ${index + 13}`, - id: `gid://shopify/CustomerSegment/${index + 13}`, - value: `${index + 12}`, - }), - ); - - segments.push(...lazyLoadSegments); - - const interval = 25; - const [sheetOpen, setSheetOpen] = useState(true); - const [showFooterAction, setShowFooterAction] = useState(true); - const [query, setQuery] = useState(''); - const [lazyLoading, setLazyLoading] = useState(false); - const [willLoadMoreResults, setWillLoadMoreResults] = useState(true); - const [visibleOptionIndex, setVisibleOptionIndex] = useState(6); - const [activeOptionId, setActiveOptionId] = useState(segments[0].id); - const [selectedSegmentIndex, setSelectedSegmentIndex] = useState(0); - const [filteredSegments, setFilteredSegments] = useState( - [], - ); - - const handleClickShowAll = () => { - setShowFooterAction(false); - setVisibleOptionIndex(segments.length); - }; - - const handleFilterSegments = (query: string) => { - const nextFilteredSegments = segments.filter((segment) => { - return segment.label - .toLocaleLowerCase() - .includes(query.toLocaleLowerCase().trim()); - }); - - setFilteredSegments(nextFilteredSegments); - }; - - const handleQueryChange = (query: string) => { - setQuery(query); - - if (query.length >= 2) handleFilterSegments(query); - }; - - const handleQueryClear = () => { - handleQueryChange(''); - }; - - const handleResetVisibleOptionIndex = () => { - setVisibleOptionIndex(interval); - }; - - const handleOpenSheet = () => { - setSheetOpen(true); - }; - - const handleCloseSheet = () => { - setSheetOpen(false); - handleQueryChange(''); - handleResetVisibleOptionIndex(); - }; - - const handleSegmentSelect = (segmentIndex: string) => { - if (segmentIndex === actionValue) { - return handleClickShowAll(); - } - - setSelectedSegmentIndex(Number(segmentIndex)); - handleCloseSheet(); - }; - - const handleActiveOptionChange = (_: string, domId: string) => { - setActiveOptionId(domId); - }; - - /* This is just to illustrate lazy loading state vs loading state. This is an example, so we aren't fetching from GraphQL. You'd use `pageInfo.hasNextPage` from your GraphQL query data instead of this fake "willLoadMoreResults" state along with setting `first` your GraphQL query's variables to your app's default max edges limit (e.g., 250). */ - - const handleLazyLoadSegments = () => { - if (willLoadMoreResults && !showFooterAction) { - setLazyLoading(true); - - const options = query ? filteredSegments : segments; - - setTimeout(() => { - const remainingOptionCount = options.length - visibleOptionIndex; - const nextVisibleOptionIndex = - remainingOptionCount >= interval - ? visibleOptionIndex + interval - : visibleOptionIndex + remainingOptionCount; + + + ); + }, +}; - setLazyLoading(false); - setVisibleOptionIndex(nextVisibleOptionIndex); +export const WithSearchableListbox = { + render() { + const actionValue = '__ACTION__'; - if (remainingOptionCount <= interval) { - setWillLoadMoreResults(false); - } - }, 1000); + interface CustomerSegment { + id: string; + label: string; + value: string; } - }; - const listboxId = 'SearchableListboxInSheet'; - - /* Your app's feature/context specific activator here */ - const activator = ( - - ); - - const textFieldMarkup = ( -
- - } - ariaActiveDescendant={activeOptionId} - ariaControls={listboxId} - onChange={handleQueryChange} - onClearButtonClick={handleQueryClear} - /> - -
- ); + const segments: CustomerSegment[] = [ + { + label: 'All customers', + id: 'gid://shopify/CustomerSegment/1', + value: '0', + }, + { + label: 'VIP customers', + id: 'gid://shopify/CustomerSegment/2', + value: '1', + }, + { + label: 'New customers', + id: 'gid://shopify/CustomerSegment/3', + value: '2', + }, + { + label: 'Abandoned carts - last 30 days', + id: 'gid://shopify/CustomerSegment/4', + value: '3', + }, + { + label: 'Wholesale customers', + id: 'gid://shopify/CustomerSegment/5', + value: '4', + }, + { + label: 'Email subscribers', + id: 'gid://shopify/CustomerSegment/6', + value: '5', + }, + { + label: 'From New York', + id: 'gid://shopify/CustomerSegment/7', + value: '6', + }, + { + label: 'Repeat buyers', + id: 'gid://shopify/CustomerSegment/8', + value: '7', + }, + { + label: 'First time buyers', + id: 'gid://shopify/CustomerSegment/9', + value: '8', + }, + { + label: 'From Canada', + id: 'gid://shopify/CustomerSegment/10', + value: '9', + }, + { + label: 'Bought in last 60 days', + id: 'gid://shopify/CustomerSegment/11', + value: '10', + }, + { + label: 'Bought last BFCM', + id: 'gid://shopify/CustomerSegment/12', + value: '11', + }, + ]; + + const lazyLoadSegments: CustomerSegment[] = Array.from(Array(100)).map( + (_, index) => ({ + label: `Other customers ${index + 13}`, + id: `gid://shopify/CustomerSegment/${index + 13}`, + value: `${index + 12}`, + }), + ); + + segments.push(...lazyLoadSegments); + + const interval = 25; + const [sheetOpen, setSheetOpen] = useState(true); + const [showFooterAction, setShowFooterAction] = useState(true); + const [query, setQuery] = useState(''); + const [lazyLoading, setLazyLoading] = useState(false); + const [willLoadMoreResults, setWillLoadMoreResults] = useState(true); + const [visibleOptionIndex, setVisibleOptionIndex] = useState(6); + const [activeOptionId, setActiveOptionId] = useState(segments[0].id); + const [selectedSegmentIndex, setSelectedSegmentIndex] = useState(0); + const [filteredSegments, setFilteredSegments] = useState( + [], + ); + + const handleClickShowAll = () => { + setShowFooterAction(false); + setVisibleOptionIndex(segments.length); + }; + + const handleFilterSegments = (query: string) => { + const nextFilteredSegments = segments.filter((segment) => { + return segment.label + .toLocaleLowerCase() + .includes(query.toLocaleLowerCase().trim()); + }); + + setFilteredSegments(nextFilteredSegments); + }; + + const handleQueryChange = (query: string) => { + setQuery(query); + + if (query.length >= 2) handleFilterSegments(query); + }; + + const handleQueryClear = () => { + handleQueryChange(''); + }; + + const handleResetVisibleOptionIndex = () => { + setVisibleOptionIndex(interval); + }; + + const handleOpenSheet = () => { + setSheetOpen(true); + }; + + const handleCloseSheet = () => { + setSheetOpen(false); + handleQueryChange(''); + handleResetVisibleOptionIndex(); + }; + + const handleSegmentSelect = (segmentIndex: string) => { + if (segmentIndex === actionValue) { + return handleClickShowAll(); + } + + setSelectedSegmentIndex(Number(segmentIndex)); + handleCloseSheet(); + }; + + const handleActiveOptionChange = (_: string, domId: string) => { + setActiveOptionId(domId); + }; + + /* This is just to illustrate lazy loading state vs loading state. This is an example, so we aren't fetching from GraphQL. You'd use `pageInfo.hasNextPage` from your GraphQL query data instead of this fake "willLoadMoreResults" state along with setting `first` your GraphQL query's variables to your app's default max edges limit (e.g., 250). */ + + const handleLazyLoadSegments = () => { + if (willLoadMoreResults && !showFooterAction) { + setLazyLoading(true); + + const options = query ? filteredSegments : segments; + + setTimeout(() => { + const remainingOptionCount = options.length - visibleOptionIndex; + const nextVisibleOptionIndex = + remainingOptionCount >= interval + ? visibleOptionIndex + interval + : visibleOptionIndex + remainingOptionCount; + + setLazyLoading(false); + setVisibleOptionIndex(nextVisibleOptionIndex); + + if (remainingOptionCount <= interval) { + setWillLoadMoreResults(false); + } + }, 1000); + } + }; + + const listboxId = 'SearchableListboxInSheet'; + + /* Your app's feature/context specific activator here */ + const activator = ( + + ); + + const textFieldMarkup = ( +
+ + } + ariaActiveDescendant={activeOptionId} + ariaControls={listboxId} + onChange={handleQueryChange} + onClearButtonClick={handleQueryClear} + /> + +
+ ); + + const segmentOptions = query ? filteredSegments : segments; + + const segmentList = + segmentOptions.length > 0 + ? segmentOptions + .slice(0, visibleOptionIndex) + .map(({label, id, value}) => { + const selected = segments[selectedSegmentIndex].id === id; + + return ( + + + {label} + + + ); + }) + : null; + + const showAllMarkup = showFooterAction ? ( + + + Show all 111 segments + + + ) : null; - const segmentOptions = query ? filteredSegments : segments; - - const segmentList = - segmentOptions.length > 0 - ? segmentOptions - .slice(0, visibleOptionIndex) - .map(({label, id, value}) => { - const selected = segments[selectedSegmentIndex].id === id; - - return ( - - - {label} - - - ); - }) - : null; - - const showAllMarkup = showFooterAction ? ( - - - Show all 111 segments - - - ) : null; - - const lazyLoadingMarkup = lazyLoading ? ( - - ) : null; - - const noResultsMarkup = - segmentOptions.length === 0 ? ( - ) : null; - const listboxMarkup = ( -
- - {segmentList} - {showAllMarkup} - {noResultsMarkup} - {lazyLoadingMarkup} - -
- ); - - return ( -
- {activator} - + ) : null; + + const listboxMarkup = ( +
-
+ {segmentList} + {showAllMarkup} + {noResultsMarkup} + {lazyLoadingMarkup} + +
+ ); + + return ( +
+ {activator} +
- - Action - -
+ + + Look up customer segmentation membership + + + Look up whether a customer is included in a segment. + +
- - - Look up customer segmentation membership - - - Look up whether a customer is included in a segment. - - -
-
- {textFieldMarkup} - - - {listboxMarkup} - + {textFieldMarkup} + + + {listboxMarkup} + +
-
- - - ); -} + + + ); + }, +}; const StopPropagation = ({children}: React.PropsWithChildren) => { const stopEventPropagation = (event: React.MouseEvent | React.TouchEvent) => { diff --git a/polaris-react/src/components/SkeletonBodyText/SkeletonBodyText.stories.tsx b/polaris-react/src/components/SkeletonBodyText/SkeletonBodyText.stories.tsx index 87be0ceede9..fc4e5f43d40 100644 --- a/polaris-react/src/components/SkeletonBodyText/SkeletonBodyText.stories.tsx +++ b/polaris-react/src/components/SkeletonBodyText/SkeletonBodyText.stories.tsx @@ -1,15 +1,19 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {SkeletonBodyText} from '@shopify/polaris'; export default { component: SkeletonBodyText, -} as ComponentMeta; +} as Meta; -export function Default() { - return ; -} +export const Default = { + render() { + return ; + }, +}; -export function SingleLineContent() { - return ; -} +export const SingleLineContent = { + render() { + return ; + }, +}; diff --git a/polaris-react/src/components/SkeletonDisplayText/SkeletonDisplayText.stories.tsx b/polaris-react/src/components/SkeletonDisplayText/SkeletonDisplayText.stories.tsx index bbbad977479..668a58f2ca8 100644 --- a/polaris-react/src/components/SkeletonDisplayText/SkeletonDisplayText.stories.tsx +++ b/polaris-react/src/components/SkeletonDisplayText/SkeletonDisplayText.stories.tsx @@ -1,23 +1,31 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {SkeletonDisplayText} from '@shopify/polaris'; export default { component: SkeletonDisplayText, -} as ComponentMeta; +} as Meta; -export function MediumAndLarge() { - return ; -} +export const MediumAndLarge = { + render() { + return ; + }, +}; -export function ExtraLarge() { - return ; -} +export const ExtraLarge = { + render() { + return ; + }, +}; -export function Small() { - return ; -} +export const Small = { + render() { + return ; + }, +}; -export function MaxWidth() { - return ; -} +export const MaxWidth = { + render() { + return ; + }, +}; diff --git a/polaris-react/src/components/SkeletonPage/SkeletonPage.stories.tsx b/polaris-react/src/components/SkeletonPage/SkeletonPage.stories.tsx index 1b75edaa194..c4d9af3dc91 100644 --- a/polaris-react/src/components/SkeletonPage/SkeletonPage.stories.tsx +++ b/polaris-react/src/components/SkeletonPage/SkeletonPage.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { LegacyCard, Layout, @@ -11,242 +11,252 @@ import { export default { component: SkeletonPage, -} as ComponentMeta; +} as Meta; -export function WithDynamicContent() { - return ( - - - - - - - - - +export const WithDynamicContent = { + render() { + return ( + + + + - - - - - - - - - - - - + + - + - - - - - - - + + - + - - - - - - - - - ); -} - -export function WithStaticContent() { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + }, +}; -export function WithNarrowWidth() { - return ( - - - - - - - - - +export const WithStaticContent = { + render() { + return ( + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + ); + }, +}; + +export const WithNarrowWidth = { + render() { + return ( + + + + - - - - - - + + - + - - - - - - - + + - + - - - - - - - - - ); -} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + }, +}; -export function WithFullWidth() { - return ( - - - - - - - - - +export const WithFullWidth = { + render() { + return ( + + + + - - - - - - - - - - - - + + - + - - - - - - - + + - + - - - - - - - - - ); -} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + }, +}; -export function WithBackAction() { - return ( - - - - - - - - - - - - - - - +export const WithBackAction = { + render() { + return ( + + + + - - - - - - + + - + - - - - - - - + + - + - - - - - - - - - ); -} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + }, +}; diff --git a/polaris-react/src/components/SkeletonTabs/SkeletonTabs.stories.tsx b/polaris-react/src/components/SkeletonTabs/SkeletonTabs.stories.tsx index e6dbf80a8c8..1151f3a9391 100644 --- a/polaris-react/src/components/SkeletonTabs/SkeletonTabs.stories.tsx +++ b/polaris-react/src/components/SkeletonTabs/SkeletonTabs.stories.tsx @@ -6,51 +6,63 @@ export default { component: SkeletonTabs, } as Meta; -export function All() { - return ( - - - - - - - ); -} +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function Default() { - return ; -} +export const Default = { + render() { + return ; + }, +}; -export function WithACustomCount() { - return ; -} +export const WithACustomCount = { + render() { + return ; + }, +}; -export function InsideOfACard() { - return ( - -
- - - - Tab X selected - - -
-
- ); -} +export const InsideOfACard = { + render() { + return ( + +
+ + + + Tab X selected + + +
+
+ ); + }, +}; -export function InsideOfACardFitted() { - return ( - -
- - - - Tab X selected - - -
-
- ); -} +export const InsideOfACardFitted = { + render() { + return ( + +
+ + + + Tab X selected + + +
+
+ ); + }, +}; diff --git a/polaris-react/src/components/SkeletonThumbnail/SkeletonThumbnail.stories.tsx b/polaris-react/src/components/SkeletonThumbnail/SkeletonThumbnail.stories.tsx index 57f6941d6b4..d6a83828f6f 100644 --- a/polaris-react/src/components/SkeletonThumbnail/SkeletonThumbnail.stories.tsx +++ b/polaris-react/src/components/SkeletonThumbnail/SkeletonThumbnail.stories.tsx @@ -1,34 +1,46 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {SkeletonThumbnail, BlockStack} from '@shopify/polaris'; -export function All() { - return ( - - - - - - - ); -} +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; export default { component: SkeletonThumbnail, -} as ComponentMeta; +} as Meta; -export function Medium() { - return ; -} +export const Medium = { + render() { + return ; + }, +}; -export function Large() { - return ; -} +export const Large = { + render() { + return ; + }, +}; -export function Small() { - return ; -} +export const Small = { + render() { + return ; + }, +}; -export function ExtraSmall() { - return ; -} +export const ExtraSmall = { + render() { + return ; + }, +}; diff --git a/polaris-react/src/components/Spinner/Spinner.stories.tsx b/polaris-react/src/components/Spinner/Spinner.stories.tsx index 447cc6663c2..4edef0f1a30 100644 --- a/polaris-react/src/components/Spinner/Spinner.stories.tsx +++ b/polaris-react/src/components/Spinner/Spinner.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useEffect, useRef, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Button, LegacyCard, @@ -12,91 +12,105 @@ import { export default { component: Spinner, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - <> - - - - - ); -} +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + <> + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function Default() { - return ; -} +export const Default = { + render() { + return ; + }, +}; -export function Small() { - return ; -} +export const Small = { + render() { + return ; + }, +}; -export function WithFocusManagement() { - const tabs = useRef([ - { - id: 'all-customers', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-content', - }, - { - id: 'accepts-marketing', - content: 'Accepts marketing', - panelID: 'accepts-marketing-content', - }, - ]); +export const WithFocusManagement = { + render() { + const tabs = useRef([ + { + id: 'all-customers', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-content', + }, + { + id: 'accepts-marketing', + content: 'Accepts marketing', + panelID: 'accepts-marketing-content', + }, + ]); - const [selected, setSelected] = useState(0); - const [loading, setLoading] = useState(false); - const [value, setValue] = useState(''); - const [textFieldFocused, setTextFieldFocused] = useState(false); + const [selected, setSelected] = useState(0); + const [loading, setLoading] = useState(false); + const [value, setValue] = useState(''); + const [textFieldFocused, setTextFieldFocused] = useState(false); - useEffect(() => { - setTextFieldFocused(!loading); - }, [loading]); + useEffect(() => { + setTextFieldFocused(!loading); + }, [loading]); - const handleTabChange = useCallback((selectedTab) => { - setLoading(true); - setSelected(selectedTab); - setTimeout(() => { - setValue(''); - return setLoading(false); - }, 1500); - }, []); + const handleTabChange = useCallback((selectedTab) => { + setLoading(true); + setSelected(selectedTab); + setTimeout(() => { + setValue(''); + return setLoading(false); + }, 1500); + }, []); - const handleUrlChange = useCallback((value) => setValue(value), []); + const handleUrlChange = useCallback((value) => setValue(value), []); - const handleSubmit = useCallback((_event) => setValue(''), []); + const handleSubmit = useCallback((_event) => setValue(''), []); - const label = selected ? 'Marketing' : 'Customers'; - const sectionMarkup = loading ? ( - - ) : ( -
- - - - - - ); + const label = selected ? 'Marketing' : 'Customers'; + const sectionMarkup = loading ? ( + + ) : ( +
+ + + + + + ); - return ( - - - - {sectionMarkup} - - - - ); -} + return ( + + + + {sectionMarkup} + + + + ); + }, +}; diff --git a/polaris-react/src/components/Tabs/Tabs.stories.tsx b/polaris-react/src/components/Tabs/Tabs.stories.tsx index 9af0168c5a4..23fb5224c83 100644 --- a/polaris-react/src/components/Tabs/Tabs.stories.tsx +++ b/polaris-react/src/components/Tabs/Tabs.stories.tsx @@ -1,73 +1,48 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Tabs, BlockStack, LegacyCard, Text} from '@shopify/polaris'; export default { component: Tabs, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - - - - - - - - - ); -} -export function Default() { - const [selected, setSelected] = useState(0); +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; +export const Default = { + render() { + const [selected, setSelected] = useState(0); - const handleTabChange = (selectedTabIndex: number) => - setSelected(selectedTabIndex); + const handleTabChange = (selectedTabIndex: number) => + setSelected(selectedTabIndex); - const tabs = [ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ].map((item, index) => ({ - content: item, - index, - id: `${item.split(' ').join('-')}-${index}-default`, - })); + const tabs = [ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ].map((item, index) => ({ + content: item, + index, + id: `${item.split(' ').join('-')}-${index}-default`, + })); - return ( - - - - Tab {selected} selected - - - - ); -} - -export function InsideOfACard() { - const [selected, setSelected] = useState(0); - - const handleTabChange = (selectedTabIndex: number) => - setSelected(selectedTabIndex); - - const tabs = [ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - ].map((item, index) => ({ - content: item, - index, - id: `${item.split(' ').join('-')}-${index}-inside-of-a-card`, - })); - return ( - + return ( @@ -75,44 +50,79 @@ export function InsideOfACard() { - - ); -} + ); + }, +}; -export function Fitted() { - const [selected, setSelected] = useState(0); +export const InsideOfACard = { + render() { + const [selected, setSelected] = useState(0); - const handleTabChange = useCallback( - (selectedTabIndex: number) => setSelected(selectedTabIndex), - [], - ); + const handleTabChange = (selectedTabIndex: number) => + setSelected(selectedTabIndex); - const tabs = [ - { - id: 'all-customers-fitted', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-fitted-content', - }, - { - id: 'accepts-marketing-fitted', - content: 'Accepts marketing', - panelID: 'accepts-marketing-fitted-content', - }, - ]; + const tabs = [ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + ].map((item, index) => ({ + content: item, + index, + id: `${item.split(' ').join('-')}-${index}-inside-of-a-card`, + })); + return ( + + + + + Tab {selected} selected + + + + + ); + }, +}; - return ( - - - - - Tab {selected} selected - - - - - ); -} +export const Fitted = { + render() { + const [selected, setSelected] = useState(0); + + const handleTabChange = useCallback( + (selectedTabIndex: number) => setSelected(selectedTabIndex), + [], + ); + + const tabs = [ + { + id: 'all-customers-fitted', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-fitted-content', + }, + { + id: 'accepts-marketing-fitted', + content: 'Accepts marketing', + panelID: 'accepts-marketing-fitted-content', + }, + ]; + + return ( + + + + + Tab {selected} selected + + + + + ); + }, +}; type AlphaTabAction = | 'rename' @@ -121,176 +131,182 @@ type AlphaTabAction = | 'duplicate' | 'delete'; -export function WithActions() { - const sleep = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const [selected, setSelected] = useState(0); +export const WithActions = { + render() { + const sleep = (ms: number) => + new Promise((resolve) => setTimeout(resolve, ms)); + const [selected, setSelected] = useState(0); - const handleTabChange = (selectedTabIndex: number) => - setSelected(selectedTabIndex); + const handleTabChange = (selectedTabIndex: number) => + setSelected(selectedTabIndex); - const tabs = [ - 'All', - 'Unpaid', - 'Open', - 'Closed', - 'Local delivery', - 'Local pickup', - 'Returning customers', - 'New customers', - 'Abandoned checkouts', - 'Online store', - 'POS', - 'Facebook', - 'Instagram', - 'Twitter', - 'Pinterest', - 'Google', - 'Referral', - ].map((item, index) => ({ - content: item, - index, - id: `${item.split(' ').join('-')}-${index}-with-actions`, - actions: - index === 0 - ? [] - : [ - { - type: 'rename' as AlphaTabAction, - onAction: () => {}, - onPrimaryAction: () => {}, - }, - { - type: 'duplicate' as AlphaTabAction, - onAction: () => {}, - onPrimaryAction: () => {}, - }, - { - type: 'edit' as AlphaTabAction, - onAction: () => {}, - onPrimaryAction: () => {}, - }, - { - type: 'edit-columns' as AlphaTabAction, - onAction: () => {}, - onPrimaryAction: () => {}, - }, - { - type: 'delete' as AlphaTabAction, - onAction: () => {}, - onPrimaryAction: () => {}, - }, - ], - })); + const tabs = [ + 'All', + 'Unpaid', + 'Open', + 'Closed', + 'Local delivery', + 'Local pickup', + 'Returning customers', + 'New customers', + 'Abandoned checkouts', + 'Online store', + 'POS', + 'Facebook', + 'Instagram', + 'Twitter', + 'Pinterest', + 'Google', + 'Referral', + ].map((item, index) => ({ + content: item, + index, + id: `${item.split(' ').join('-')}-${index}-with-actions`, + actions: + index === 0 + ? [] + : [ + { + type: 'rename' as AlphaTabAction, + onAction: () => {}, + onPrimaryAction: () => {}, + }, + { + type: 'duplicate' as AlphaTabAction, + onAction: () => {}, + onPrimaryAction: () => {}, + }, + { + type: 'edit' as AlphaTabAction, + onAction: () => {}, + onPrimaryAction: () => {}, + }, + { + type: 'edit-columns' as AlphaTabAction, + onAction: () => {}, + onPrimaryAction: () => {}, + }, + { + type: 'delete' as AlphaTabAction, + onAction: () => {}, + onPrimaryAction: () => {}, + }, + ], + })); - return ( - - ); -} + return ( + + ); + }, +}; -export function WithBadgeContent() { - const [selected, setSelected] = useState(0); +export const WithBadgeContent = { + render() { + const [selected, setSelected] = useState(0); - const handleTabChange = useCallback( - (selectedTabIndex: number) => setSelected(selectedTabIndex), - [], - ); + const handleTabChange = useCallback( + (selectedTabIndex: number) => setSelected(selectedTabIndex), + [], + ); - const tabs = [ - { - id: 'all-customers-with-badge', - badge: '10+', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-with-badge-content', - }, - { - id: 'accepts-marketing-with-badge', - badge: '4', - content: 'Accepts marketing', - panelID: 'accepts-marketing-with-badge-content', - }, - ]; + const tabs = [ + { + id: 'all-customers-with-badge', + badge: '10+', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-with-badge-content', + }, + { + id: 'accepts-marketing-with-badge', + badge: '4', + content: 'Accepts marketing', + panelID: 'accepts-marketing-with-badge-content', + }, + ]; - return ( - - - - - Tab {selected} selected - - - - - ); -} + return ( + + + + + Tab {selected} selected + + + + + ); + }, +}; -export function WithCustomDisclosure() { - const [selected, setSelected] = useState(0); +export const WithCustomDisclosure = { + render() { + const [selected, setSelected] = useState(0); - const handleTabChange = useCallback( - (selectedTabIndex: number) => setSelected(selectedTabIndex), - [], - ); + const handleTabChange = useCallback( + (selectedTabIndex: number) => setSelected(selectedTabIndex), + [], + ); - const tabs = [ - { - id: 'all-customers-with-custom-disclosure', - content: 'All', - accessibilityLabel: 'All customers', - panelID: 'all-customers-with-custom-disclosure-content', - }, - { - id: 'accepts-marketing-with-custom-disclosure', - content: 'Accepts marketing', - panelID: 'accepts-marketing-with-custom-disclosure-content', - }, - { - id: 'repeat-customers-with-custom-disclosure', - content: 'Repeat customers', - panelID: 'repeat-customers-with-custom-disclosure-content', - }, - { - id: 'prospects-with-custom-disclosure', - content: 'Prospects', - panelID: 'prospects-with-custom-disclosure-content', - }, - { - id: 'opt-out-marketing-with-custom-disclosure', - content: 'Opted out of marketing', - panelID: 'opt-out-with-custom-disclosure-content', - }, - { - id: 'net-new-customers-with-custom-disclosure', - content: 'Net new customers', - panelID: 'net-new-customers-with-custom-disclosure-content', - }, - { - id: 'churned-customers-with-custom-disclosure', - content: 'Churned customers', - panelID: 'churned=customers-with-custom-disclosure-content', - }, - ]; + const tabs = [ + { + id: 'all-customers-with-custom-disclosure', + content: 'All', + accessibilityLabel: 'All customers', + panelID: 'all-customers-with-custom-disclosure-content', + }, + { + id: 'accepts-marketing-with-custom-disclosure', + content: 'Accepts marketing', + panelID: 'accepts-marketing-with-custom-disclosure-content', + }, + { + id: 'repeat-customers-with-custom-disclosure', + content: 'Repeat customers', + panelID: 'repeat-customers-with-custom-disclosure-content', + }, + { + id: 'prospects-with-custom-disclosure', + content: 'Prospects', + panelID: 'prospects-with-custom-disclosure-content', + }, + { + id: 'opt-out-marketing-with-custom-disclosure', + content: 'Opted out of marketing', + panelID: 'opt-out-with-custom-disclosure-content', + }, + { + id: 'net-new-customers-with-custom-disclosure', + content: 'Net new customers', + panelID: 'net-new-customers-with-custom-disclosure-content', + }, + { + id: 'churned-customers-with-custom-disclosure', + content: 'Churned customers', + panelID: 'churned=customers-with-custom-disclosure-content', + }, + ]; - return ( - - - - - Tab {selected} selected - - - - - ); -} + return ( + + + + + Tab {selected} selected + + + + + ); + }, +}; diff --git a/polaris-react/src/components/Tag/Tag.stories.tsx b/polaris-react/src/components/Tag/Tag.stories.tsx index c16e5017403..ec945b86add 100644 --- a/polaris-react/src/components/Tag/Tag.stories.tsx +++ b/polaris-react/src/components/Tag/Tag.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { InlineStack, Icon, @@ -13,165 +13,183 @@ import {WandIcon} from '@shopify/polaris-icons'; export default { component: Tag, -} as ComponentMeta; - -export function All() { - return ( - - Default - -
- Removable - -
- Clickable - -
- With Link - -
- With Custom Content - -
- Removable with Link - -
- Removable large - -
- ); -} - -export function Default() { - return ( - - Wholesale - Disabled - With URL - - ); -} - -export function Removable() { - const [selectedTags, setSelectedTags] = useState([ - 'Rustic', - 'Antique', - 'Vinyl', - 'Refurbished', - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ipsum quam. Aliquam fermentum bibendum vestibulum. Vestibulum condimentum luctus metus, sed sagittis magna pellentesque eget. Duis dapibus pretium nisi, et venenatis tortor dignissim ut. Quisque eget lacus ac ex eleifend ultrices. Phasellus facilisis ex sit amet leo elementum condimentum. Ut vel maximus felis. Etiam eget diam eu eros blandit interdum. Sed eu metus sed justo aliquam iaculis ac sit amet ex. Curabitur justo magna, porttitor non pulvinar eu, malesuada at leo. Cras mollis consectetur eros, quis maximus lorem dignissim at. Proin in rhoncus massa. Vivamus lectus nunc, fringilla euismod risus commodo, mattis blandit nulla.', - ]); - - const removeTag = useCallback( - (tag) => () => { - setSelectedTags((previousTags) => - previousTags.filter((previousTag) => previousTag !== tag), - ); - }, - [], - ); - - const tagMarkup = selectedTags.map((option) => ( - - {option} - - )); - - return {tagMarkup}; -} - -export function Clickable() { - return ( - - console.log('Clicked')}>Wholesale - console.log('Clicked')} disabled> - Wholesale (clickable disabled) +} as Meta; + +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + Default + +
+ Removable + +
+ Clickable + +
+ With Link + +
+ With Custom Content + +
+ Removable with Link + +
+ Removable large + +
+ /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; + +export const Default = { + render() { + return ( + + Wholesale + Disabled + With URL + + ); + }, +}; + +export const Removable = { + render() { + const [selectedTags, setSelectedTags] = useState([ + 'Rustic', + 'Antique', + 'Vinyl', + 'Refurbished', + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer at ipsum quam. Aliquam fermentum bibendum vestibulum. Vestibulum condimentum luctus metus, sed sagittis magna pellentesque eget. Duis dapibus pretium nisi, et venenatis tortor dignissim ut. Quisque eget lacus ac ex eleifend ultrices. Phasellus facilisis ex sit amet leo elementum condimentum. Ut vel maximus felis. Etiam eget diam eu eros blandit interdum. Sed eu metus sed justo aliquam iaculis ac sit amet ex. Curabitur justo magna, porttitor non pulvinar eu, malesuada at leo. Cras mollis consectetur eros, quis maximus lorem dignissim at. Proin in rhoncus massa. Vivamus lectus nunc, fringilla euismod risus commodo, mattis blandit nulla.', + ]); + + const removeTag = useCallback( + (tag) => () => { + setSelectedTags((previousTags) => + previousTags.filter((previousTag) => previousTag !== tag), + ); + }, + [], + ); + + const tagMarkup = selectedTags.map((option) => ( + + {option} -
- ); -} - -export function WithLink() { - return Wholesale; -} - -export function WithCustomContent() { - return ( - - - - - - Wholesale + )); + + return {tagMarkup}; + }, +}; + +export const Clickable = { + render() { + return ( + + console.log('Clicked')}>Wholesale + console.log('Clicked')} disabled> + Wholesale (clickable disabled) + - - ); -} - -export function RemovableWithLink() { - const [selectedTags, setSelectedTags] = useState([ - 'Rustic', - 'Antique', - 'Vinyl', - 'Refurbished', - ]); - - const removeTag = useCallback( - (tag) => () => { - setSelectedTags((previousTags) => - previousTags.filter((previousTag) => previousTag !== tag), - ); - }, - [], - ); - - const tagMarkup = selectedTags.map((option) => ( - - {option} - - )); - - return {tagMarkup}; -} - -export function RemovableLarge() { - const [selectedTags, setSelectedTags] = useState([ - 'Rustic', - 'Antique', - 'Vinyl', - 'Refurbished', - ]); - - const removeTag = useCallback( - (tag) => () => { - setSelectedTags((previousTags) => - previousTags.filter((previousTag) => previousTag !== tag), - ); - }, - [], - ); - - const tagMarkup = selectedTags.map((option) => ( - - {option} - - )); - - const tagWithLinkMarkup = selectedTags.map((option) => ( - - {option} - - )); - - return ( - - Large - {tagMarkup} - Large with link - {tagWithLinkMarkup} - - ); -} + ); + }, +}; + +export const WithLink = { + render() { + return Wholesale; + }, +}; + +export const WithCustomContent = { + render() { + return ( + + + + + + Wholesale + + + ); + }, +}; + +export const RemovableWithLink = { + render() { + const [selectedTags, setSelectedTags] = useState([ + 'Rustic', + 'Antique', + 'Vinyl', + 'Refurbished', + ]); + + const removeTag = useCallback( + (tag) => () => { + setSelectedTags((previousTags) => + previousTags.filter((previousTag) => previousTag !== tag), + ); + }, + [], + ); + + const tagMarkup = selectedTags.map((option) => ( + + {option} + + )); + + return {tagMarkup}; + }, +}; + +export const RemovableLarge = { + render() { + const [selectedTags, setSelectedTags] = useState([ + 'Rustic', + 'Antique', + 'Vinyl', + 'Refurbished', + ]); + + const removeTag = useCallback( + (tag) => () => { + setSelectedTags((previousTags) => + previousTags.filter((previousTag) => previousTag !== tag), + ); + }, + [], + ); + + const tagMarkup = selectedTags.map((option) => ( + + {option} + + )); + + const tagWithLinkMarkup = selectedTags.map((option) => ( + + {option} + + )); + + return ( + + Large + {tagMarkup} + Large with link + {tagWithLinkMarkup} + + ); + }, +}; diff --git a/polaris-react/src/components/Text/Text.stories.tsx b/polaris-react/src/components/Text/Text.stories.tsx index f1404292f60..b1dd5c921c7 100644 --- a/polaris-react/src/components/Text/Text.stories.tsx +++ b/polaris-react/src/components/Text/Text.stories.tsx @@ -1,165 +1,184 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {LegacyStack, Text} from '@shopify/polaris'; export default { component: Text, -} as ComponentMeta; +} as Meta; -export const Variants = () => ( - - - Text with Heading3xl variant - - - Text with Heading2xl variant - - - Text with HeadingXl variant - - - Text with HeadingLg variant - - - Text with HeadingMd variant - - - Text with HeadingSm variant - - - Text with HeadingXs variant - - - Text with BodyLg variant - - - Text with BodyMd variant - - - Text with BodySm variant - - - Text with BodyXs variant - - - Text as a strong tag - - -); +export const Variants = { + render: () => ( + + + Text with Heading3xl variant + + + Text with Heading2xl variant + + + Text with HeadingXl variant + + + Text with HeadingLg variant + + + Text with HeadingMd variant + + + Text with HeadingSm variant + + + Text with HeadingXs variant + + + Text with BodyLg variant + + + Text with BodyMd variant + + + Text with BodySm variant + + + Text with BodyXs variant + + + Text as a strong tag + + + ), +}; -export const WithAlignment = () => ( - - - Manage your Shopify store on-the-go with real-time notifications, access - to your dashboard, and order management, all from your smartphone. - - - Manage your Shopify store on-the-go with real-time notifications, access - to your dashboard, and order management, all from your smartphone. - - - Manage your Shopify store on-the-go with real-time notifications, access - to your dashboard, and order management, all from your smartphone. - - - Manage your Shopify store on-the-go with real-time notifications, access - to your dashboard, and order management, all from your smartphone. - - -); +export const WithAlignment = { + render: () => ( + + + Manage your Shopify store on-the-go with real-time notifications, access + to your dashboard, and order management, all from your smartphone. + + + Manage your Shopify store on-the-go with real-time notifications, access + to your dashboard, and order management, all from your smartphone. + + + Manage your Shopify store on-the-go with real-time notifications, access + to your dashboard, and order management, all from your smartphone. + + + Manage your Shopify store on-the-go with real-time notifications, access + to your dashboard, and order management, all from your smartphone. + + + ), +}; -export const WithFontWeight = () => ( - - - Sales this year - - - Sales this year - - - Sales this year - - - Sales this year - - -); +export const WithFontWeight = { + render: () => ( + + + Sales this year + + + Sales this year + + + Sales this year + + + Sales this year + + + ), +}; -export const WithTone = () => ( - - - Use to de-emphasize a piece of text that is less important to merchants - than other nearby text. May also be used to indicate when normal content - is absent, for example, “No supplier listed”. Don’t use only for aesthetic - effect. - - - Use in combination with a symbol showing an increasing value to indicate - an upward trend. - - - Use to denote something that needs attention, or that merchants need to - take action on. - - - Use in combination with a symbol showing a decreasing value to indicate a - downward trend. - - - Recommended for text generated by magic AI. - - - Recommended for secondary-level prominence of text suggested by magic AI. - - -); +export const WithTone = { + render: () => ( + + + Use to de-emphasize a piece of text that is less important to merchants + than other nearby text. May also be used to indicate when normal content + is absent, for example, “No supplier listed”. Don’t use only for + aesthetic effect. + + + Use in combination with a symbol showing an increasing value to indicate + an upward trend. + + + Use to denote something that needs attention, or that merchants need to + take action on. + + + Use in combination with a symbol showing a decreasing value to indicate + a downward trend. + + + Recommended for text generated by magic AI. + + + Recommended for secondary-level prominence of text suggested by magic + AI. + + + ), +}; -export const WithInheritance = () => ( - - This is a 2xl heading -
- This is also a 2xl heading -
-); +export const WithInheritance = { + render: () => ( + + This is a 2xl heading +
+ This is also a 2xl heading +
+ ), +}; -export const WithTruncate = () => ( - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tincidunt vel - lorem nec pretium. Vestibulum ante ipsum primis in faucibus orci luctus et - ultrices posuere cubilia curae; Morbi sollicitudin ex nec imperdiet - pellentesque. Etiam dapibus ipsum non ligula molestie rhoncus. Vivamus eget - iaculis lectus. Sed porttitor leo at nulla mollis malesuada. Vestibulum ante - ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; - Vestibulum vestibulum porttitor mollis. Nam dictum ante sed lobortis - commodo. Ut luctus ut metus vel bibendum. - -); +export const WithTruncate = { + render: () => ( + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam tincidunt vel + lorem nec pretium. Vestibulum ante ipsum primis in faucibus orci luctus et + ultrices posuere cubilia curae; Morbi sollicitudin ex nec imperdiet + pellentesque. Etiam dapibus ipsum non ligula molestie rhoncus. Vivamus + eget iaculis lectus. Sed porttitor leo at nulla mollis malesuada. + Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere + cubilia curae; Vestibulum vestibulum porttitor mollis. Nam dictum ante sed + lobortis commodo. Ut luctus ut metus vel bibendum. + + ), +}; -export const ParentWithChild = () => ( - - Parent Text component with{' '} - - bold - {' '} - children - -); +export const ParentWithChild = { + render: () => ( + + Parent Text component with{' '} + + bold + {' '} + children + + ), +}; -export const InADefinitionList = () => ( -
- - Definition Title - - - Definition Description - -
-); +export const InADefinitionList = { + render: () => ( +
+ + Definition Title + + + Definition Description + +
+ ), +}; -export const WithTextDecoration = () => ( - - - $100.00 - - -); +export const WithTextDecoration = { + render: () => ( + + + $100.00 + + + ), +}; diff --git a/polaris-react/src/components/TextContainer/TextContainer.stories.tsx b/polaris-react/src/components/TextContainer/TextContainer.stories.tsx index 8cbd109740e..450dcc450ed 100644 --- a/polaris-react/src/components/TextContainer/TextContainer.stories.tsx +++ b/polaris-react/src/components/TextContainer/TextContainer.stories.tsx @@ -1,51 +1,58 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {Text, TextContainer} from '@shopify/polaris'; export default { component: TextContainer, -} as ComponentMeta; +} as Meta; -export function Default() { - return ( - - - Install the Shopify POS App - - - Shopify POS is the easiest way to sell your products in person. - Available for iPad, iPhone, and Android. - - - ); -} +export const Default = { + render() { + return ( + + + Install the Shopify POS App + + + Shopify POS is the easiest way to sell your products in person. + Available for iPad, iPhone, and Android. + + + ); + }, +}; -export function Tight() { - return ( - - - Install the Shopify POS App - - - Shopify POS is the easiest way to sell your products in person. - Available for iPad, iPhone, and Android. - - - ); -} +export const Tight = { + render() { + return ( + + + Install the Shopify POS App + + + Shopify POS is the easiest way to sell your products in person. + Available for iPad, iPhone, and Android. + + + ); + }, +}; -export function Loose() { - return ( - - - Manage your Shopify store on-the-go with real-time notifications, access - to your dashboard, and order management, all from your smartphone. - - - Shopify POS is the fastest and easiest way to start accepting Visa, - Mastercard, American Express, and Discover right from your smartphone or - tablet. - - - ); -} +export const Loose = { + render() { + return ( + + + Manage your Shopify store on-the-go with real-time notifications, + access to your dashboard, and order management, all from your + smartphone. + + + Shopify POS is the fastest and easiest way to start accepting Visa, + Mastercard, American Express, and Discover right from your smartphone + or tablet. + + + ); + }, +}; diff --git a/polaris-react/src/components/TextField/TextField.stories.tsx b/polaris-react/src/components/TextField/TextField.stories.tsx index a2fa6061943..fbf6d63a874 100644 --- a/polaris-react/src/components/TextField/TextField.stories.tsx +++ b/polaris-react/src/components/TextField/TextField.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useEffect, useMemo, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Button, LegacyCard, @@ -25,1044 +25,1105 @@ import { export default { component: TextField, -} as ComponentMeta; - -export function Default() { - const [value, setValue] = useState('Jaded Pixel'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - return ( - - ); -} - -export function Magic() { - const [value, setValue] = useState('Jaded Pixel'); - const [value1, setValue1] = useState('Jaded Pixel'); - const [value2, setValue2] = useState('Jaded Pixel'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - const handleChange1 = useCallback((newValue) => setValue1(newValue), []); - const handleChange2 = useCallback((newValue) => setValue2(newValue), []); - - return ( - +} as Meta; + +export const Default = { + render() { + const [value, setValue] = useState('Jaded Pixel'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + return ( + ); + }, +}; + +export const Magic = { + render() { + const [value, setValue] = useState('Jaded Pixel'); + const [value1, setValue1] = useState('Jaded Pixel'); + const [value2, setValue2] = useState('Jaded Pixel'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + const handleChange1 = useCallback((newValue) => setValue1(newValue), []); + const handleChange2 = useCallback((newValue) => setValue2(newValue), []); + + return ( + + + } + autoComplete="off" + tone="magic" + /> + + + + } + tone="magic" + autoComplete="off" + /> + + ); + }, +}; + +export const Number = { + render() { + const [value, setValue] = useState('1.0'); + const [value1, setValue1] = useState('1.0'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + const handleChange1 = useCallback((newValue) => setValue1(newValue), []); + + return ( + + + + + ); + }, +}; + +export const Integer = { + render() { + const [value, setValue] = useState('1'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + return ( } + label="Integer" + type="integer" + value={value} + onChange={handleChange} autoComplete="off" - tone="magic" /> + ); + }, +}; + +export const Email = { + render() { + const [value, setValue] = useState('bernadette.lapresse@jadedpixel.com'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + return ( - - - } - tone="magic" - autoComplete="off" + label="Email" + type="email" + value={value} + onChange={handleChange} + autoComplete="email" /> - - ); -} + ); + }, +}; -export function Number() { - const [value, setValue] = useState('1.0'); - const [value1, setValue1] = useState('1.0'); +export const Multiline = { + render() { + const [value, setValue] = useState('1776 Barnes Street\nOrlando, FL 32801'); - const handleChange = useCallback((newValue) => setValue(newValue), []); - const handleChange1 = useCallback((newValue) => setValue1(newValue), []); + const handleChange = useCallback((newValue) => setValue(newValue), []); - return ( - + return ( + ); + }, +}; + +export const WithHiddenLabel = { + render() { + const [value, setValue] = useState('12'); + const [selected, setSelected] = useState('yes'); + + const handleTextChange = useCallback((newValue) => setValue(newValue), []); + + const handleChoiceChange = useCallback( + (selections) => setSelected(selections[0]), + [], + ); + + return ( + + + + } + /> + + ); + }, +}; + +export const WithLabelAction = { + render() { + const [textFieldValue, setTextFieldValue] = useState('6201.11.0000'); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + return ( + + ); + }, +}; + +export const WithRightAlignedText = { + render() { + const [textFieldValue, setTextFieldValue] = useState('1'); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + return ( + + Price + + + ); + }, +}; + +export const WithPlaceholderText = { + render() { + const [textFieldValue, setTextFieldValue] = useState(''); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + return ( - - ); -} - -export function Integer() { - const [value, setValue] = useState('1'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - return ( - - ); -} - -export function Email() { - const [value, setValue] = useState('bernadette.lapresse@jadedpixel.com'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - return ( - - ); -} - -export function Multiline() { - const [value, setValue] = useState('1776 Barnes Street\nOrlando, FL 32801'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - return ( - - ); -} - -export function WithHiddenLabel() { - const [value, setValue] = useState('12'); - const [selected, setSelected] = useState('yes'); - - const handleTextChange = useCallback((newValue) => setValue(newValue), []); - - const handleChoiceChange = useCallback( - (selections) => setSelected(selections[0]), - [], - ); - - return ( - - setTextFieldValue(value), + [], + ); + + return ( + + ); + }, +}; + +export const WithPrefixOrSuffix = { + render() { + const [textFieldValue, setTextFieldValue] = useState('2.00'); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + return ( + + + + + ); + }, +}; + +export const WithVerticalContent = { + render() { + const tags = ['Rustic', 'Antique', 'Vinyl', 'Refurbished']; + const [textFieldValue, setTextFieldValue] = useState(''); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + const verticalContentMarkup = + tags.length > 0 ? ( + + {tags.map((tag) => ( + {tag} + ))} + + ) : null; + + return ( + + ); + }, +}; + +export const WithConnectedFields = { + render() { + const [textFieldValue, setTextFieldValue] = useState('10.6'); + const [selectValue, setSelectValue] = useState('kg'); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + const handleSelectChange = useCallback( + (value) => setSelectValue(value), + [], + ); + + return ( } + connectedRight={} /> - - ); -} - -export function WithLabelAction() { - const [textFieldValue, setTextFieldValue] = useState('6201.11.0000'); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - return ( - - ); -} - -export function WithRightAlignedText() { - const [textFieldValue, setTextFieldValue] = useState('1'); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - return ( - - Price + ); + }, +}; + +export const WithValidationError = { + render() { + const [textFieldValue, setTextFieldValue] = useState(''); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + return ( - - ); -} - -export function WithPlaceholderText() { - const [textFieldValue, setTextFieldValue] = useState(''); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - return ( - - ); -} - -export function WithHelpText() { - const [textFieldValue, setTextFieldValue] = useState( - 'bernadette.lapresse@jadedpixel.com', - ); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - return ( - - ); -} - -export function WithPrefixOrSuffix() { - const [textFieldValue, setTextFieldValue] = useState('2.00'); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - return ( - + ); + }, +}; + +export const WithSeparateValidationError = { + render() { + const [textFieldValue, setTextFieldValue] = useState(''); + const [selectTypeValue, setSelectTypeValue] = useState('Product type'); + const [selectConditionValue, setSelectConditionValue] = + useState('is equal to'); + + const handleTextFieldValueChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + const handleSelectTypeChange = useCallback( + (value) => setSelectTypeValue(value), + [], + ); + + const handleSelectConditionChange = useCallback( + (value) => setSelectConditionValue(value), + [], + ); + + const textFieldID = 'ruleContent'; + const isInvalid = isValueInvalid(textFieldValue); + const errorMessage = isInvalid + ? 'Enter 3 or more characters for product type is equal to' + : ''; + + const formGroupMarkup = ( + + + + + + + + +
+ +
+
+ } - /> - ); -} - -export function WithValidationError() { - const [textFieldValue, setTextFieldValue] = useState(''); - - const handleTextFieldChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - return ( - - ); -} - -export function WithSeparateValidationError() { - const [textFieldValue, setTextFieldValue] = useState(''); - const [selectTypeValue, setSelectTypeValue] = useState('Product type'); - const [selectConditionValue, setSelectConditionValue] = - useState('is equal to'); - - const handleTextFieldValueChange = useCallback( - (value) => setTextFieldValue(value), - [], - ); - - const handleSelectTypeChange = useCallback( - (value) => setSelectTypeValue(value), - [], - ); - - const handleSelectConditionChange = useCallback( - (value) => setSelectConditionValue(value), - [], - ); - - const textFieldID = 'ruleContent'; - const isInvalid = isValueInvalid(textFieldValue); - const errorMessage = isInvalid - ? 'Enter 3 or more characters for product type is equal to' - : ''; - - const formGroupMarkup = ( - - - - - - - - -
- -
-
- } - connectedRight={} - /> - - - {}} - autoComplete="off" - /> - {}} - autoComplete="off" - /> - {}} - autoComplete="off" - /> - - - {}} - autoComplete="off" - /> - {}} - autoComplete="off" - /> - {}} - autoComplete="off" - /> - - - {}} - autoComplete="off" - size="slim" - /> + ); + }, +}; + +export const WithValueSelectedOnFocus = { + render() { + const [textFieldValue, setTextFieldValue] = useState('Jaded Pixel'); + + const handleTextFieldChange = useCallback( + (value) => setTextFieldValue(value), + [], + ); + + return ( + + ); + }, +}; + +export const WithInlineSuggestion = { + render() { + const suggestions = useMemo( + () => [ + 'Alabama', + 'Alaska', + 'American Samoa', + 'Arizona', + 'Arkansas', + 'California', + 'Colorado', + 'Connecticut', + 'Delaware', + 'District of Columbia', + 'Florida', + 'Georgia', + 'Guam', + 'Hawaii', + 'Idaho', + 'Illinois', + 'Indiana', + 'Iowa', + 'Kansas', + 'Kentucky', + 'Louisiana', + 'Maine', + 'Maryland', + 'Massachusetts', + 'Michigan', + 'Minnesota', + 'Icon Outlying Islands', + 'Mississippi', + 'Missouri', + 'Montana', + 'Nebraska', + 'Nevada', + 'New Hampshire', + 'New Jersey', + 'New Mexico', + 'New York', + 'North Carolina', + 'North Dakota', + 'Northern Mariana Islands', + 'Ohio', + 'Oklahoma', + 'Oregon', + 'Pennsylvania', + 'Puerto Rico', + 'Rhode Island', + 'South Carolina', + 'South Dakota', + 'Tennessee', + 'Texas', + 'U.S. Virgin Islands', + 'Utah', + 'Vermont', + 'Virginia', + 'Washington', + 'West Virginia', + 'Wisconsin', + 'Wyoming', + ], + [], + ); + + const [value, setValue] = useState(''); + const [suggestion, setSuggestion] = useState(); + + const handleChange = useCallback( + (value: string) => { + const suggestion = + value && + suggestions.find((suggestion) => + suggestion.toLowerCase().startsWith(value.toLowerCase()), + ); + + setValue(value); + setSuggestion(suggestion); + }, + [suggestions], + ); + + const handleKeyDown = useCallback( + (event: React.KeyboardEvent) => { + if (event.key === 'Enter' || event.key === 'Tab') { + setValue(suggestion || value); + setSuggestion(''); + } else if (event.key === 'Backspace') { + setValue(value); + setSuggestion(''); + } + }, + [value, suggestion], + ); + + return ( +
{}} + type="text" + label="State" + value={value} + onChange={handleChange} + suggestion={suggestion} autoComplete="off" - variant="borderless" - size="slim" /> - - - ); -} - -export function WithFormSubmit() { - const [adjustment, setAdjustment] = useState('0'); - const [onHandTotal, setOnHandTotal] = useState(0); - - return ( - -
{ - event.preventDefault(); - setAdjustment('0'); - setOnHandTotal(onHandTotal + parseInt(adjustment, 10)); - }} - > - - - On hand quantity ({onHandTotal.toString()}) - +
+ ); + }, +}; + +export const All = { + render() { + return ( + + + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + helpText="Help text" + disabled + /> + {}} + autoComplete="off" + readOnly + /> + {}} + error="Error message." + autoComplete="off" + /> + + + {}} + autoComplete="off" + /> + {}} + labelAction={{content: 'Action'}} + autoComplete="off" + /> + {}} + placeholder="Example" + autoComplete="off" + /> + {}} + helpText="Help text." + autoComplete="email" + /> + + + {}} + prefix="$" + autoComplete="off" + /> + {}} + prefix="$" + autoComplete="off" + tone="magic" + /> + {}} + prefix={} + autoComplete="off" + /> setAdjustment(value)} + label="Prefix icon with magic" + type="search" + value="Value" + onChange={() => {}} + prefix={} autoComplete="off" + tone="magic" + /> + {}} + suffix={ + + + + } + autoComplete="off" + /> + {}} + suffix={ + + + + } + tone="magic" + autoComplete="off" + /> + {}} + maxLength={20} + autoComplete="off" + showCharacterCount + /> + + + {}} + clearButton + onClearButtonClick={() => {}} + autoComplete="off" + /> + {}} + requiredIndicator + autoComplete="off" + /> + {}} + monospaced + autoComplete="off" + /> + {}} + variant="borderless" + autoComplete="off" + /> + + + {}} + multiline={4} + autoComplete="off" + /> + {}} + error="Error message." + multiline={4} + autoComplete="off" + /> + + + {}} + placeholder="Label hidden" + autoComplete="off" + /> + + + {}} + autoComplete="off" + connectedLeft={} + connectedRight={} + /> + + + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + + + {}} + autoComplete="off" + /> + {}} + autoComplete="off" + /> + {}} + autoComplete="off" /> - - - - - ); -} - -export function With1PasswordDisabled() { - const [value, setValue] = useState('Jaded Pixel'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - return ( - - ); -} - -export function WithAutoSize() { - const [value, setValue] = useState('Jaded Pixel'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - return ( - - ); -} - -export function WithAutoSizeAndDynamicSuffix() { - const [value, setValue] = useState(''); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - const suffix = value ? 'in: Unfulfilled orders' : null; - - return ( - - ); -} - -export function WithAutoSizeAndOtherElements() { - const [value, setValue] = useState('Jaded Pixel'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - const handleClearButtonClick = useCallback(() => setValue(''), []); - - return ( - - ); -} - -export function WithLoading() { - const [value, setValue] = useState('Jaded Pixel'); - - const handleChange = useCallback((newValue) => setValue(newValue), []); - - const handleClearButtonClick = useCallback(() => setValue(''), []); - - return ( - - ); -} +
+ + {}} + autoComplete="off" + size="slim" + /> + {}} + autoComplete="off" + variant="borderless" + size="slim" + /> + + + ); + }, +}; + +export const WithFormSubmit = { + render() { + const [adjustment, setAdjustment] = useState('0'); + const [onHandTotal, setOnHandTotal] = useState(0); + + return ( + +
{ + event.preventDefault(); + setAdjustment('0'); + setOnHandTotal(onHandTotal + parseInt(adjustment, 10)); + }} + > + + + On hand quantity ({onHandTotal.toString()}) + + setAdjustment(value)} + autoComplete="off" + type="number" + selectTextOnFocus + /> + + + +
+ ); + }, +}; + +export const With1PasswordDisabled = { + render() { + const [value, setValue] = useState('Jaded Pixel'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + return ( + + ); + }, +}; + +export const WithAutoSize = { + render() { + const [value, setValue] = useState('Jaded Pixel'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + return ( + + ); + }, +}; + +export const WithAutoSizeAndDynamicSuffix = { + render() { + const [value, setValue] = useState(''); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + const suffix = value ? 'in: Unfulfilled orders' : null; + + return ( + + ); + }, +}; + +export const WithAutoSizeAndOtherElements = { + render() { + const [value, setValue] = useState('Jaded Pixel'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + const handleClearButtonClick = useCallback(() => setValue(''), []); + + return ( + + ); + }, +}; + +export const WithLoading = { + render() { + const [value, setValue] = useState('Jaded Pixel'); + + const handleChange = useCallback((newValue) => setValue(newValue), []); + + const handleClearButtonClick = useCallback(() => setValue(''), []); + + return ( + + ); + }, +}; diff --git a/polaris-react/src/components/ThemeProvider/ThemeProvider.stories.tsx b/polaris-react/src/components/ThemeProvider/ThemeProvider.stories.tsx index facf8c75809..4befb4523eb 100644 --- a/polaris-react/src/components/ThemeProvider/ThemeProvider.stories.tsx +++ b/polaris-react/src/components/ThemeProvider/ThemeProvider.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Frame, Icon, @@ -12,86 +12,89 @@ import {HeartIcon, NotificationIcon} from '@shopify/polaris-icons'; export default { component: ThemeProvider, -} as ComponentMeta; +} as Meta; -export function Default() { - const [isHeartMenuOpen, setIsHeartMenuOpen] = useState(true); +export const Default = { + render() { + const [isHeartMenuOpen, setIsHeartMenuOpen] = useState(true); - const toggleIsHeartMenuOpen = useCallback( - () => setIsHeartMenuOpen((isHeartMenuOpen) => !isHeartMenuOpen), - [], - ); + const toggleIsHeartMenuOpen = useCallback( + () => setIsHeartMenuOpen((isHeartMenuOpen) => !isHeartMenuOpen), + [], + ); - const [isNotificationsMenuOpen, setIsNotificationsMenuOpen] = useState(false); + const [isNotificationsMenuOpen, setIsNotificationsMenuOpen] = + useState(false); - const toggleIsNotificationsMenuOpen = useCallback( - () => - setIsNotificationsMenuOpen( - (isNotificationsMenuOpen) => !isNotificationsMenuOpen, - ), - [], - ); + const toggleIsNotificationsMenuOpen = useCallback( + () => + setIsNotificationsMenuOpen( + (isNotificationsMenuOpen) => !isNotificationsMenuOpen, + ), + [], + ); - const heartMenu = ( - - + const heartMenu = ( + + + + + + Light theme popover button + + + + } + open={isHeartMenuOpen} + onOpen={toggleIsHeartMenuOpen} + onClose={toggleIsHeartMenuOpen} + actions={[ + { + items: [{content: 'Light theme popover'}], + }, + ]} + /> + + ); + + const notificationsMenu = ( + + - + - Light theme popover button + Dark theme popover button - - } - open={isHeartMenuOpen} - onOpen={toggleIsHeartMenuOpen} - onClose={toggleIsHeartMenuOpen} - actions={[ - { - items: [{content: 'Light theme popover'}], - }, - ]} - /> - - ); + } + open={isNotificationsMenuOpen} + onOpen={toggleIsNotificationsMenuOpen} + onClose={toggleIsNotificationsMenuOpen} + actions={[ + { + items: [{content: 'Dark theme popover'}], + }, + ]} + /> + + ); - const notificationsMenu = ( - - - - - Dark theme popover button - - + return ( + + {heartMenu} + {notificationsMenu} + + } + /> } - open={isNotificationsMenuOpen} - onOpen={toggleIsNotificationsMenuOpen} - onClose={toggleIsNotificationsMenuOpen} - actions={[ - { - items: [{content: 'Dark theme popover'}], - }, - ]} /> - - ); - - return ( - - {heartMenu} - {notificationsMenu} - - } - /> - } - /> - ); -} + ); + }, +}; diff --git a/polaris-react/src/components/Thumbnail/Thumbnail.stories.tsx b/polaris-react/src/components/Thumbnail/Thumbnail.stories.tsx index ccd3a112597..018073d533c 100644 --- a/polaris-react/src/components/Thumbnail/Thumbnail.stories.tsx +++ b/polaris-react/src/components/Thumbnail/Thumbnail.stories.tsx @@ -1,65 +1,79 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {InlineStack, Thumbnail, BlockStack} from '@shopify/polaris'; import {NoteIcon} from '@shopify/polaris-icons'; export default { component: Thumbnail, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - - - - - - - - - - ); -} +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function Default() { - return ( - - ); -} +export const Default = { + render() { + return ( + + ); + }, +}; -export function ExtraSmall() { - return ( - - ); -} +export const ExtraSmall = { + render() { + return ( + + ); + }, +}; -export function Small() { - return ( - - ); -} +export const Small = { + render() { + return ( + + ); + }, +}; -export function Large() { - return ( - - ); -} +export const Large = { + render() { + return ( + + ); + }, +}; -export function WithComponentSource() { - return ; -} +export const WithComponentSource = { + render() { + return ; + }, +}; diff --git a/polaris-react/src/components/Toast/Toast.stories.tsx b/polaris-react/src/components/Toast/Toast.stories.tsx index 2f26bc9aa62..724ea5edc87 100644 --- a/polaris-react/src/components/Toast/Toast.stories.tsx +++ b/polaris-react/src/components/Toast/Toast.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Button, ButtonGroup, @@ -15,341 +15,363 @@ import {MagicIcon} from '@shopify/polaris-icons'; export default { component: Toast, -} as ComponentMeta; - -export function Default() { - const [active, setActive] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const toastMarkup = active ? ( - - ) : null; - - return ( -
- - - - {toastMarkup} - - -
- ); -} - -export function MultipleMessages() { - const [activeToasts, setActiveToasts] = useState([]); - - const toggleActive = (id: number) => - setActiveToasts((activeToasts) => { - const isToastActive = activeToasts.includes(id); - return isToastActive - ? activeToasts.filter((activeToast) => activeToast !== id) - : [...activeToasts, id]; - }); - - const toggleActiveOne = useCallback(() => toggleActive(1), []); - - const toggleActiveTwo = useCallback(() => toggleActive(2), []); - - const toggleActiveThree = useCallback(() => toggleActive(3), []); - - const toggleActiveFour = useCallback(() => toggleActive(4), []); - - const toggleActiveFive = useCallback(() => toggleActive(5), []); - - const toggleActiveSix = useCallback(() => toggleActive(6), []); - - const toastDuration = 5000; - - const toastMarkup1 = activeToasts.includes(1) ? ( - - ) : null; - - const toastMarkup2 = activeToasts.includes(2) ? ( - - ) : null; - - const toastMarkup3 = activeToasts.includes(3) ? ( - - ) : null; - - const toastMarkup4 = activeToasts.includes(4) ? ( - - ) : null; - - const toastMarkup5 = activeToasts.includes(5) ? ( - - ) : null; - - const toastMarkup6 = activeToasts.includes(6) ? ( - - ) : null; - - return ( -
- - - - - - - - - - - {toastMarkup1} - {toastMarkup2} - {toastMarkup3} - {toastMarkup4} - {toastMarkup5} - {toastMarkup6} - - -
- ); -} - -export function WithCustomDuration() { - const [active, setActive] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const toastMarkup = active ? ( - - ) : null; - - return ( -
- - - - {toastMarkup} - - -
- ); -} - -export function WithAction() { - const [active, setActive] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const toastMarkup = active ? ( - {}, - }} - duration={10000} - onDismiss={toggleActive} - /> - ) : null; - - return ( -
- - - - {toastMarkup} - - -
- ); -} - -export function Error() { - const [active, setActive] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const toastMarkup = active ? ( - - ) : null; - - return ( -
- - - - {toastMarkup} - - -
- ); -} - -export function InsideModal() { - const [toastActive, setToastActive] = useState(false); - const [toast2Active, setToast2Active] = useState(false); - const [modalActive, setModalActive] = useState(true); - - const handleChange = useCallback( - () => setModalActive(!modalActive), - [modalActive], - ); - - const toggleActive = useCallback( - () => setToastActive((toastActive) => !toastActive), - [], - ); - - const toggle2Active = useCallback( - () => setToast2Active((toastActive) => !toastActive), - [], - ); - - const activator = ; - - const toastMarkup = toastActive ? ( - - ) : null; - - const toast2Markup = toast2Active ? ( - - ) : null; - - return ( -
- - - {toastMarkup} - {toast2Markup} - ; + +export const Default = { + render() { + const [active, setActive] = useState(false); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const toastMarkup = active ? ( + + ) : null; + + return ( +
+ + + + {toastMarkup} + + +
+ ); + }, +}; + +export const MultipleMessages = { + render() { + const [activeToasts, setActiveToasts] = useState([]); + + const toggleActive = (id: number) => + setActiveToasts((activeToasts) => { + const isToastActive = activeToasts.includes(id); + return isToastActive + ? activeToasts.filter((activeToast) => activeToast !== id) + : [...activeToasts, id]; + }); + + const toggleActiveOne = useCallback(() => toggleActive(1), []); + + const toggleActiveTwo = useCallback(() => toggleActive(2), []); + + const toggleActiveThree = useCallback(() => toggleActive(3), []); + + const toggleActiveFour = useCallback(() => toggleActive(4), []); + + const toggleActiveFive = useCallback(() => toggleActive(5), []); + + const toggleActiveSix = useCallback(() => toggleActive(6), []); + + const toastDuration = 5000; + + const toastMarkup1 = activeToasts.includes(1) ? ( + + ) : null; + + const toastMarkup2 = activeToasts.includes(2) ? ( + + ) : null; + + const toastMarkup3 = activeToasts.includes(3) ? ( + + ) : null; + + const toastMarkup4 = activeToasts.includes(4) ? ( + + ) : null; + + const toastMarkup5 = activeToasts.includes(5) ? ( + + ) : null; + + const toastMarkup6 = activeToasts.includes(6) ? ( + + ) : null; + + return ( +
+ + + + + + + + + + + {toastMarkup1} + {toastMarkup2} + {toastMarkup3} + {toastMarkup4} + {toastMarkup5} + {toastMarkup6} + + +
+ ); + }, +}; + +export const WithCustomDuration = { + render() { + const [active, setActive] = useState(false); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const toastMarkup = active ? ( + + ) : null; + + return ( +
+ + + + {toastMarkup} + + +
+ ); + }, +}; + +export const WithAction = { + render() { + const [active, setActive] = useState(false); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const toastMarkup = active ? ( + {}, + }} + duration={10000} + onDismiss={toggleActive} + /> + ) : null; + + return ( +
+ + + + {toastMarkup} + + +
+ ); + }, +}; + +export const Error = { + render() { + const [active, setActive] = useState(false); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const toastMarkup = active ? ( + + ) : null; + + return ( +
+ + + + {toastMarkup} + + +
+ ); + }, +}; + +export const InsideModal = { + render() { + const [toastActive, setToastActive] = useState(false); + const [toast2Active, setToast2Active] = useState(false); + const [modalActive, setModalActive] = useState(true); + + const handleChange = useCallback( + () => setModalActive(!modalActive), + [modalActive], + ); + + const toggleActive = useCallback( + () => setToastActive((toastActive) => !toastActive), + [], + ); + + const toggle2Active = useCallback( + () => setToast2Active((toastActive) => !toastActive), + [], + ); + + const activator = ; + + const toastMarkup = toastActive ? ( + + ) : null; + + const toast2Markup = toast2Active ? ( + + ) : null; + + return ( +
+ + + {toastMarkup} + {toast2Markup} + - - - - Use Instagram posts to share your products with millions of - people. Let shoppers buy from your store without leaving - Instagram. - - - - - - - - - - -
- ); -} - -export function Magic() { - const [active, setActive] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const toastMarkup = active ? ( - - ) : null; - - return ( -
- - - - {toastMarkup} - - -
- ); -} - -export function WithOnClick() { - const [active, setActive] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const toastMarkup = active ? ( - - ) : null; - - return ( -
- - - - {toastMarkup} - - -
- ); -} - -export function MagicWithOnClick() { - const [active, setActive] = useState(false); - - const toggleActive = useCallback(() => setActive((active) => !active), []); - - const toastMarkup = active ? ( - - ) : null; - - return ( -
- - - - {toastMarkup} - - -
- ); -} + }} + secondaryActions={[ + { + content: 'Learn more', + onAction: handleChange, + }, + ]} + > + + + + Use Instagram posts to share your products with millions of + people. Let shoppers buy from your store without leaving + Instagram. + + + + + + + +
+
+ +
+ ); + }, +}; + +export const Magic = { + render() { + const [active, setActive] = useState(false); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const toastMarkup = active ? ( + + ) : null; + + return ( +
+ + + + {toastMarkup} + + +
+ ); + }, +}; + +export const WithOnClick = { + render() { + const [active, setActive] = useState(false); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const toastMarkup = active ? ( + + ) : null; + + return ( +
+ + + + {toastMarkup} + + +
+ ); + }, +}; + +export const MagicWithOnClick = { + render() { + const [active, setActive] = useState(false); + + const toggleActive = useCallback(() => setActive((active) => !active), []); + + const toastMarkup = active ? ( + + ) : null; + + return ( +
+ + + + {toastMarkup} + + +
+ ); + }, +}; diff --git a/polaris-react/src/components/Tooltip/Tooltip.stories.tsx b/polaris-react/src/components/Tooltip/Tooltip.stories.tsx index 173bf0a2fc3..63b984a9439 100644 --- a/polaris-react/src/components/Tooltip/Tooltip.stories.tsx +++ b/polaris-react/src/components/Tooltip/Tooltip.stories.tsx @@ -1,6 +1,6 @@ import React, {useState} from 'react'; import {QuestionCircleIcon} from '@shopify/polaris-icons'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import { Button, ButtonGroup, @@ -18,551 +18,586 @@ import type {TooltipProps} from '@shopify/polaris'; export default { component: Tooltip, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - - - - - - - - - - - - - - - - ); -} - -export function Default() { - return ( - - - - Order #1001 - - - - ); -} - -export function PreferredPosition() { - return ( - - - - - - Tooltip positioned - {' '} - - above - {' '} - - the activator - - - - - - - - Tooltip positioned - {' '} - - below - {' '} - - the activator - - - - - - - ); -} - -export function Width() { - return ( - - - - - - Tooltip with - {' '} - - default - {' '} - - content width - - - - - - - - Tooltip with - {' '} - - wide - {' '} - - content width - - - - - - - ); -} - -export function Padding() { - return ( - - - - - - Tooltip with - {' '} - - default - {' '} - - content padding - - - - - - - - Tooltip with - {' '} - - 4 - {' '} - - content padding - - - - - - - ); -} +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + + + + + + + + + + + + + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function BorderRadius() { - return ( - - - - - - Tooltip with - {' '} - - default - {' '} - - border radius - - - - - - - - Tooltip with - {' '} - - 2 - {' '} - - border radius - - - +export const Default = { + render() { + return ( + + + + Order #1001 + - - - ); -} + + ); + }, +}; -export function VisibleOnlyWithChildInteraction() { - return ( - -
- - - - - - - - - - - - - - - -
-
- ); -} - -export function WithHoverDelay() { - return ( - - - - TEXT EXAMPLE - - - - - No delay - - - - +export const PreferredPosition = { + render() { + return ( + + - - 1 second hover delay - - - - - - - - BUTTON EXAMPLE - - - - + + + Tooltip positioned + {' '} + + above + {' '} + + the activator + + + - - - + + + Tooltip positioned + {' '} + + below + {' '} + + the activator + + + - - - ); -} - -export function ActivatorAsDiv() { - return ( - - - - Order #1001 - - - - ); -} + + ); + }, +}; -export function WithSuffix() { - return ( - - - - - Bold - - ⌘B - - - } - > - - +export const Width = { + render() { + return ( + + - Italic - - ⌘I - - - } + active + content="This content has the default width and will break into a new line at 200px width" > - + + + Tooltip with + {' '} + + default + {' '} + + content width + + + - Underline - - ⌘U - - - } + active + content="This content has the wide width and will break into a new line at 275px width" + width="wide" > - + + + Tooltip with + {' '} + + wide + {' '} + + content width + + + - - Strikethrough - - ⌘S - - - } - > - - - - Bold - - ⌘B - - - } - preferredPosition="below" - > - + + + ); + }, +}; + +export const Padding = { + render() { + return ( + + + + + + Tooltip with + {' '} + + default + {' '} + + content padding + + + - Italic - - ⌘I - - - } - preferredPosition="below" + active + content="This content has padding of 4 (space-400 / 16px)" + padding="400" > - + + + Tooltip with + {' '} + + 4 + {' '} + + content padding + + + + + + ); + }, +}; + +export const BorderRadius = { + render() { + return ( + + - Underline - - ⌘U - - - } - preferredPosition="below" + active + content="This content has the default (radius-100) border radius" > - + + + Tooltip with + {' '} + + default + {' '} + + border radius + + + - Strikethrough - - ⌘S - - - } - preferredPosition="below" + active + content="This content has a border radius of 200 (radius-200)" + borderRadius="200" > - - - - - - ); -} - -export function Alignment() { - return ( - - - - - - - - + + + Tooltip with + {' '} + + 2 + {' '} + + border radius + + + - - - - - - - - - - - - - - - - ); -} + + + ); + }, +}; -export function HasUnderline() { - return ( - - - - Order #1001 - - - - ); -} +export const VisibleOnlyWithChildInteraction = { + render() { + return ( + +
+ + + + + + + + + + + + + + + +
+
+ ); + }, +}; -export function PersistOnClick() { - return ( - - - - Order #1001 - - - - ); -} +export const WithHoverDelay = { + render() { + return ( + + + + TEXT EXAMPLE + + + + + No delay + + + + + + + 1 second hover delay + + + + -export function ActiveStates() { - const [popoverActive, setPopoverActive] = useState(false); - const [tooltipActive, setTooltipActive] = - useState(true); + + + BUTTON EXAMPLE + + + + + + + + + + + + + + ); + }, +}; - return ( - - - +export const ActivatorAsDiv = { + render() { + return ( + + - Active false + Order #1001 - + + ); + }, +}; + +export const WithSuffix = { + render() { + return ( + + + + + Bold + + ⌘B + + + } + > + + + + Italic + + ⌘I + + + } + > + + + + Underline + + ⌘U + + + } + > + + + + Strikethrough + + ⌘S + + + } + > + + + + Bold + + ⌘B + + + } + preferredPosition="below" + > + + + + Italic + + ⌘I + + + } + preferredPosition="below" + > + + + + Underline + + ⌘U + + + } + preferredPosition="below" + > + + + + Strikethrough + + ⌘S + + + } + preferredPosition="below" + > + + + + + + ); + }, +}; + +export const Alignment = { + render() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + ); + }, +}; + +export const HasUnderline = { + render() { + return ( + + - Active true + Order #1001 + + ); + }, +}; + +export const PersistOnClick = { + render() { + return ( + - Active undefined + Order #1001 - + + ); + }, +}; + +export const ActiveStates = { + render() { + const [popoverActive, setPopoverActive] = useState(false); + const [tooltipActive, setTooltipActive] = + useState(true); + + return ( + + + + + Active false + + + + + Active true + + + + + Active undefined + + + + + { + setPopoverActive(true); + setTooltipActive(false); + }} + > + Popover Activator + + } + autofocusTarget="first-node" + preferredPosition="below" + preferredAlignment="left" + onClose={() => { + setPopoverActive(false); + setTooltipActive(true); + }} + > +
+ + + popoverActive: {popoverActive.toString()} + + + tooltipActive: {tooltipActive?.toString()} + + +
+
+
+
+
+
+ ); + }, +}; + +export const OneCharacter = { + render() { + return ( + + - { - setPopoverActive(true); - setTooltipActive(false); - }} - > - Popover Activator - - } - autofocusTarget="first-node" - preferredPosition="below" - preferredAlignment="left" - onClose={() => { - setPopoverActive(false); - setTooltipActive(true); - }} - > -
- - - popoverActive: {popoverActive.toString()} - - - tooltipActive: {tooltipActive?.toString()} - - -
-
+ Order #1001
- -
- ); -} - -export function OneCharacter() { - return ( - - - - Order #1001 - - - - ); -} + + ); + }, +}; diff --git a/polaris-react/src/components/TopBar/TopBar.stories.tsx b/polaris-react/src/components/TopBar/TopBar.stories.tsx index 0c4dd834a04..da802f5e291 100644 --- a/polaris-react/src/components/TopBar/TopBar.stories.tsx +++ b/polaris-react/src/components/TopBar/TopBar.stories.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useState} from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {ActionList, Frame, Icon, TopBar, Text, Avatar} from '@shopify/polaris'; import {ArrowLeftIcon, QuestionCircleIcon} from '@shopify/polaris-icons'; @@ -7,7 +7,7 @@ import type {UserMenuProps} from '../../../build/ts/latest/src/components/TopBar export default { component: TopBar, -} as ComponentMeta; +} as Meta; function TopBarWrapper({ userActions, @@ -142,80 +142,86 @@ function TopBarWrapper({ ); } -export function Default() { - const userActions: UserMenuProps['actions'] = [ - { - items: [{content: 'Back to Shopify', icon: ArrowLeftIcon}], - }, - { - items: [{content: 'Community forums'}], - }, - ]; - return ( - - ); -} - -export function WithCustomActivator() { - const userActions: UserMenuProps['actions'] = [ - { - items: [{content: 'Back to Shopify', icon: ArrowLeftIcon}], - }, - { - items: [{content: 'Community forums'}], - }, - ]; - - const customActivator = ( - <> - - - - Xquenda Andreev - - - Hem Canada - - - - ); - - return ( - - ); -} - -export function WithMessage() { - const userActions: UserMenuProps['actions'] = [ - { - items: [{content: 'Back to Shopify', icon: ArrowLeftIcon}], - }, - { - items: [{content: 'Community forums'}], - }, - ]; - - return ( - {}}, - }} - /> - ); -} +export const Default = { + render() { + const userActions: UserMenuProps['actions'] = [ + { + items: [{content: 'Back to Shopify', icon: ArrowLeftIcon}], + }, + { + items: [{content: 'Community forums'}], + }, + ]; + return ( + + ); + }, +}; + +export const WithCustomActivator = { + render() { + const userActions: UserMenuProps['actions'] = [ + { + items: [{content: 'Back to Shopify', icon: ArrowLeftIcon}], + }, + { + items: [{content: 'Community forums'}], + }, + ]; + + const customActivator = ( + <> + + + + Xquenda Andreev + + + Hem Canada + + + + ); + + return ( + + ); + }, +}; + +export const WithMessage = { + render() { + const userActions: UserMenuProps['actions'] = [ + { + items: [{content: 'Back to Shopify', icon: ArrowLeftIcon}], + }, + { + items: [{content: 'Community forums'}], + }, + ]; + + return ( + {}}, + }} + /> + ); + }, +}; diff --git a/polaris-react/src/components/VideoThumbnail/VideoThumbnail.stories.tsx b/polaris-react/src/components/VideoThumbnail/VideoThumbnail.stories.tsx index 61fbcf10625..0a1b3e8b6a0 100644 --- a/polaris-react/src/components/VideoThumbnail/VideoThumbnail.stories.tsx +++ b/polaris-react/src/components/VideoThumbnail/VideoThumbnail.stories.tsx @@ -1,90 +1,100 @@ import React from 'react'; -import type {ComponentMeta} from '@storybook/react'; +import type {Meta} from '@storybook/react'; import {MediaCard, Text, BlockStack, VideoThumbnail} from '@shopify/polaris'; export default { component: VideoThumbnail, -} as ComponentMeta; +} as Meta; -export function All() { - return ( - - - - Default - - - +export const All = { + render() { + return ( + /* eslint-disable react/jsx-pascal-case */ + + + + Default + + + - - - With progress - - - + + + With progress + + + - - - Outside media card - - + + + Outside media card + + + - - ); -} + /* eslint-enable react/jsx-pascal-case */ + ); + }, +}; -export function Default() { - return ( - {}, - }} - description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - > - {}} - /> - - ); -} +export const Default = { + render() { + return ( + {}, + }} + description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + > + {}} + /> + + ); + }, +}; -export function WithProgress() { - return ( - {}, - }} - description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." - popoverActions={[{content: 'Dismiss', onAction: () => {}}]} - > - {}} - /> - - ); -} +export const WithProgress = { + render() { + return ( + {}, + }} + description="In this course, you’ll learn how the Kular family turned their mom’s recipe book into a global business." + popoverActions={[{content: 'Dismiss', onAction: () => {}}]} + > + {}} + /> + + ); + }, +}; -export function OutsideMediaCard() { - return ( -
- {}} - /> -
- ); -} +export const OutsideMediaCard = { + render() { + return ( +
+ {}} + /> +
+ ); + }, +}; From c4be04498eb06c75990c7b9a29105531c0cacff1 Mon Sep 17 00:00:00 2001 From: Jess Telford Date: Tue, 23 Apr 2024 16:13:40 +1000 Subject: [PATCH 4/4] Add changeset --- .changeset/wild-islands-fry.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/wild-islands-fry.md diff --git a/.changeset/wild-islands-fry.md b/.changeset/wild-islands-fry.md new file mode 100644 index 00000000000..9dacc76aae0 --- /dev/null +++ b/.changeset/wild-islands-fry.md @@ -0,0 +1,6 @@ +--- +'@shopify/polaris-migrator': patch +'@shopify/polaris': patch +--- + +Migrate Storybook stories to CSF v3