diff --git a/.storybook/main.js b/.storybook/main.js index bc6c29a5a8..4f11fcd6a5 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -1,10 +1,9 @@ module.exports = { - stories: ['../stories/**/*.@(mdx|stories.@(ts|tsx))'], + stories: ['../stories/**/*.@(mdx|stories.@(ts|tsx))', '../src/**/**/*.@(mdx|stories.@(ts|tsx))'], addons: [ '@storybook/addon-essentials', '@storybook/addon-storysource', - // '@storybook/addon-knobs', '@storybook/addon-mdx-gfm' ], @@ -26,6 +25,7 @@ module.exports = { }, docs: { - autodocs: true + autodocs: true, + defaultName: 'Stories', } }; diff --git a/.storybook/preview.js b/.storybook/preview.js index 9eb7b32b36..b60797cc23 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -2,6 +2,7 @@ import React from 'react'; import { QueryClient, QueryClientProvider } from 'react-query'; import { CoreUiThemeProvider } from '../src/lib/next'; import { brand, coreUIAvailableThemes} from '../src/lib/style/theme'; +import { Wrapper } from '../stories/common'; export const globalTypes = { @@ -19,10 +20,16 @@ export const globalTypes = { const withThemeProvider = (Story, context) => { const theme = coreUIAvailableThemes[context.globals.theme]; + const {viewMode} = context return ( - + {/* Wrapper to make the stories take the full screen but not in docs */} + + + + + ); @@ -31,6 +38,11 @@ const withThemeProvider = (Story, context) => { export const decorators = [withThemeProvider]; export const parameters = { + layout: 'fullscreen', + docs:{ + toc : {headingSelector: 'h2,h3', + title: "Table of Contents"}, + }, controls:{ //All props with color in name will automatically have a control 'color' //with colors presets to theme colors, possible to have the color name from theme in control @@ -47,6 +59,7 @@ export const parameters = { 'Guidelines', 'Templates', 'Components', + ['Navigation', 'Data Display', 'Inputs', 'Feedback', 'Progress & loading', 'Styling', 'Deprecated'] ], }, diff --git a/package-lock.json b/package-lock.json index ee5a16543b..100a4f19a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,6 @@ "@js-temporal/polyfill": "^0.4.3", "@storybook/addon-actions": "^7.5.3", "@storybook/addon-essentials": "^7.5.3", - "@storybook/addon-knobs": "^7.0.2", "@storybook/addon-links": "^7.5.3", "@storybook/addon-mdx-gfm": "^7.5.3", "@storybook/addon-storyshots": "^7.5.3", @@ -5382,88 +5381,6 @@ "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/addon-knobs": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-7.0.2.tgz", - "integrity": "sha512-PzKuscxcBPhA2jpDxJ/F+BvBRqHJ8qBki1kS1IOjmJbAfE96WFnweXZ73ImyAJnRtmtReCL6p0ZmFkrNDMDpUw==", - "dev": true, - "dependencies": { - "copy-to-clipboard": "^3.3.3", - "core-js": "^3.29.0", - "escape-html": "^1.0.3", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.21", - "prop-types": "^15.8.1", - "qs": "^6.11.1", - "react-colorful": "^5.6.1", - "react-lifecycles-compat": "^3.0.4", - "react-select": "^5.7.0" - }, - "peerDependencies": { - "@storybook/addons": "^7.0.0", - "@storybook/api": "^7.0.0", - "@storybook/components": "^7.0.0", - "@storybook/core-events": "^7.0.0", - "@storybook/theming": "^7.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/@storybook/addon-knobs/node_modules/@floating-ui/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", - "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", - "dev": true, - "dependencies": { - "@floating-ui/utils": "^0.1.3" - } - }, - "node_modules/@storybook/addon-knobs/node_modules/@floating-ui/dom": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", - "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", - "dev": true, - "dependencies": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" - } - }, - "node_modules/@storybook/addon-knobs/node_modules/memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", - "dev": true - }, - "node_modules/@storybook/addon-knobs/node_modules/react-select": { - "version": "5.7.7", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.7.tgz", - "integrity": "sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.0", - "@emotion/cache": "^11.4.0", - "@emotion/react": "^11.8.1", - "@floating-ui/dom": "^1.0.1", - "@types/react-transition-group": "^4.4.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.6.0", - "react-transition-group": "^4.3.0", - "use-isomorphic-layout-effect": "^1.1.2" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/@storybook/addon-links": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.5.3.tgz", @@ -8482,15 +8399,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-transition-group": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.7.tgz", - "integrity": "sha512-ICCyBl5mvyqYp8Qeq9B5G/fyBSRC0zx3XM3sCC6KkcMsNeAHqXBKkmat4GqdJET5jtYUpZXrxI5flve5qhi2Eg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/react-virtualized-auto-sizer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz", @@ -11815,15 +11723,6 @@ "node": ">=0.10.0" } }, - "node_modules/copy-to-clipboard": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", - "dev": true, - "dependencies": { - "toggle-selection": "^1.0.6" - } - }, "node_modules/copyfiles": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", @@ -11893,17 +11792,6 @@ "node": ">=10" } }, - "node_modules/core-js": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.0.tgz", - "integrity": "sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/core-js-compat": { "version": "3.33.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.0.tgz", @@ -12900,12 +12788,6 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", - "dev": true - }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -16172,16 +16054,6 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "node_modules/global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dev": true, - "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, "node_modules/global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -21797,15 +21669,6 @@ "node": ">=6" } }, - "node_modules/min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dev": true, - "dependencies": { - "dom-walk": "^0.1.0" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -27107,12 +26970,6 @@ "integrity": "sha512-bAnyV6SU2n1AvuBvEgi8t7KiIn5rRiEmwFp4+elx/1ueuncAUyubITfXDMwOqStgUwh8pDzLdWgDKLicsJPikw==", "dev": true }, - "node_modules/toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", - "dev": true - }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -27739,20 +27596,6 @@ } } }, - "node_modules/use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", - "dev": true, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/use-resize-observer": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", @@ -32708,69 +32551,6 @@ "@storybook/preview-api": "7.5.3" } }, - "@storybook/addon-knobs": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-7.0.2.tgz", - "integrity": "sha512-PzKuscxcBPhA2jpDxJ/F+BvBRqHJ8qBki1kS1IOjmJbAfE96WFnweXZ73ImyAJnRtmtReCL6p0ZmFkrNDMDpUw==", - "dev": true, - "requires": { - "copy-to-clipboard": "^3.3.3", - "core-js": "^3.29.0", - "escape-html": "^1.0.3", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.21", - "prop-types": "^15.8.1", - "qs": "^6.11.1", - "react-colorful": "^5.6.1", - "react-lifecycles-compat": "^3.0.4", - "react-select": "^5.7.0" - }, - "dependencies": { - "@floating-ui/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", - "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", - "dev": true, - "requires": { - "@floating-ui/utils": "^0.1.3" - } - }, - "@floating-ui/dom": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", - "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", - "dev": true, - "requires": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" - } - }, - "memoize-one": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", - "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", - "dev": true - }, - "react-select": { - "version": "5.7.7", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.7.tgz", - "integrity": "sha512-HhashZZJDRlfF/AKj0a0Lnfs3sRdw/46VJIRd8IbB9/Ovr74+ZIwkAdSBjSPXsFMG+u72c5xShqwLSKIJllzqw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.12.0", - "@emotion/cache": "^11.4.0", - "@emotion/react": "^11.8.1", - "@floating-ui/dom": "^1.0.1", - "@types/react-transition-group": "^4.4.0", - "memoize-one": "^6.0.0", - "prop-types": "^15.6.0", - "react-transition-group": "^4.3.0", - "use-isomorphic-layout-effect": "^1.1.2" - } - } - } - }, "@storybook/addon-links": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.5.3.tgz", @@ -34974,15 +34754,6 @@ "@types/react": "*" } }, - "@types/react-transition-group": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.7.tgz", - "integrity": "sha512-ICCyBl5mvyqYp8Qeq9B5G/fyBSRC0zx3XM3sCC6KkcMsNeAHqXBKkmat4GqdJET5jtYUpZXrxI5flve5qhi2Eg==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/react-virtualized-auto-sizer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz", @@ -37481,15 +37252,6 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, - "copy-to-clipboard": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", - "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", - "dev": true, - "requires": { - "toggle-selection": "^1.0.6" - } - }, "copyfiles": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", @@ -37545,12 +37307,6 @@ } } }, - "core-js": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.0.tgz", - "integrity": "sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==", - "dev": true - }, "core-js-compat": { "version": "3.33.0", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.33.0.tgz", @@ -38289,12 +38045,6 @@ "entities": "^2.0.0" } }, - "dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", - "dev": true - }, "domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -40760,16 +40510,6 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dev": true, - "requires": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -44815,15 +44555,6 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dev": true, - "requires": { - "dom-walk": "^0.1.0" - } - }, "min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -48960,12 +48691,6 @@ "integrity": "sha512-bAnyV6SU2n1AvuBvEgi8t7KiIn5rRiEmwFp4+elx/1ueuncAUyubITfXDMwOqStgUwh8pDzLdWgDKLicsJPikw==", "dev": true }, - "toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", - "dev": true - }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -49430,12 +49155,6 @@ "tslib": "^2.0.0" } }, - "use-isomorphic-layout-effect": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", - "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", - "dev": true - }, "use-resize-observer": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz", diff --git a/package.json b/package.json index 7589153c83..cc6f6cd11e 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "@js-temporal/polyfill": "^0.4.3", "@storybook/addon-actions": "^7.5.3", "@storybook/addon-essentials": "^7.5.3", - "@storybook/addon-knobs": "^7.0.2", "@storybook/addon-links": "^7.5.3", "@storybook/addon-mdx-gfm": "^7.5.3", "@storybook/addon-storyshots": "^7.5.3", diff --git a/src/lib/components/buttonv2/Buttonv2.component.tsx b/src/lib/components/buttonv2/Buttonv2.component.tsx index 23877b52b4..19719289a6 100644 --- a/src/lib/components/buttonv2/Buttonv2.component.tsx +++ b/src/lib/components/buttonv2/Buttonv2.component.tsx @@ -1,8 +1,9 @@ import React, { ButtonHTMLAttributes } from 'react'; import styled, { css } from 'styled-components'; -import { Tooltip, Props as TooltipProps } from '../tooltip/Tooltip.component'; -import { fontSize, fontWeight } from '../../style/theme'; import { spacing } from '../../spacing'; +import { fontSize, fontWeight } from '../../style/theme'; +import { Loader } from '../loader/Loader.component'; +import { Tooltip, Props as TooltipProps } from '../tooltip/Tooltip.component'; export type Props = Omit< ButtonHTMLAttributes, 'size' | 'label' @@ -14,10 +15,12 @@ export type Props = Omit< icon?: React.ReactNode; label?: React.ReactNode; tooltip?: Omit; + isLoading?: boolean; }; export const ButtonStyled = styled.button` -webkit-appearance: none; -moz-appearance: none; + appearance: none; position: relative; display: inline-flex; user-select: none; @@ -35,7 +38,6 @@ export const ButtonStyled = styled.button` font-size: ${fontSize.base}; border-radius: ${spacing.r4}; height: ${(props) => (props.size === 'inline' ? spacing.r24 : spacing.r32)}; - ${(props) => { const brand = props.theme; @@ -185,6 +187,21 @@ export const ButtonIcon = styled.span<{ label: React.ReactNode }>` `} `; +export const ButtonLoader = styled(Loader)<{ label; variant }>` + ${(props) => { + return css` + margin-right: ${props.label ? spacing.r8 : '0'}; + svg { + fill: ${props.variant === 'danger' + ? props.theme.statusCritical + : props.variant === 'outline' + ? props.theme.textPrimary + : props.theme.textSecondary}; + } + `; + }} +`; + function Button({ variant, size, @@ -193,6 +210,7 @@ function Button({ icon, onClick, tooltip, + isLoading, ...rest }: Props) { if (!icon && !label) { @@ -214,7 +232,7 @@ function Button({ <> - {icon && ( - - {icon} - + {icon && + (isLoading ? ( + + ) : ( + + {icon} + + ))} + {!icon && isLoading && ( + )} {label} > diff --git a/stories/Button/button.guideline.mdx b/stories/Button/button.guideline.mdx new file mode 100644 index 0000000000..37d7b695bc --- /dev/null +++ b/stories/Button/button.guideline.mdx @@ -0,0 +1,197 @@ +import { + Meta, + Story, + Canvas, + Primary, + Controls, + Unstyled, + Source, + Title, +} from '@storybook/blocks'; +import { Button } from '../../src/lib/components/buttonv2/Buttonv2.component'; + +import * as ButtonStories from './button.stories'; + + + +# Button + +Buttons are used to trigger an action or event when activated. + +## Size & style + +### Style + +- Height: 2rem +- Border-radius: 3px +- Minimum width: 5rem + +### Padding + +Button’s label measurement: + +- Line height: 1.25rem +- Vertical padding: 0.5rem +- Horizontal padding of 1rem +- Space between icon & label: 0.5rem + +### Button spacing + +- Horizontal spacing: 1rem +- Vertical spacing: 0.75rem +- Space between 2 buttons: 1.5rem - when there is no space constraint + +## Usage + +Button labels should be as short and clear as possible and should describe the action the button performs.\ + +- Use one or two words if possible, +- Remove most prepositions and articles (a, an, the). +- Examples: Cancel, Close, Create, Delete, Edit, Learn More, Review, Save, Study, View Scores, etc., +- Stick to using verbs (Complete, Start, Finish, Search) or a simple verb + noun combination for buttons (Next page, Submit post, Learn more), +- Capitalize the noun after the verb (Create Folder, Create Node, Edit Location). +- Maintain labelling method consistency across all of your buttons, +- Don't use punctuation or exclamation marks (!), +- And, most importantly, don't write "Click here". + +## Variations + +The button can be modified in different way to match its usage. + +### Variant + +Buttons have a set of predefined variants to use in different context. + + + + +#### Primary + +Used for the main action. It should only appear once within a group of buttons (or even a screen). +For example, “Continue” in a form. + + + +#### Secondary + +Used for a secondary action within a group of buttons. + + + +#### Outline + +Used for low-emphasis action, as an alternative to Primary or Secondary buttons. +It's suitable for dismissive action, such as the "Cancel" button. + + + +#### Danger + +Used for critical action, typically delete actions. +Actions triggered by such button often require additional validation, as the critical action cannot be undone. + + + +### Links + +The Button component can be used as a link to another element of the UI. +When the link send to another site, use the "External-link-alt" icon. + +### Size + +Only 2 sizes are available for the button component : default and inline. + +Inline size is use for constraint spaces, like in tables or in key/values sections. +On all others cases, use the default size. + + + +### States + +#### Disabled state + +Clicks on the button should trigger no action, and the cursor should display a "not-allowed" indicator. \ +A tooltip explaining the reason for the button’s disabled state should appear on hover. + + + +#### Loading State + +Display a spinner animation within the button. \ +Disable any interactions during the loading process. + + + +## Group of Button + +- Primary buttons placed on the right of a group. +- Dismissive actions placed on the left. It allows the user to return to the previous screen or step in the process. + +Align button groups with the container's right side by default; however, based on the use case and visual balance it can be aligned differently. + + + +## Icon on buttons + +### Usage + +Every button gets a label.\ +Icons are optional and mainly used to show how buttons are different, to aid memory and differentiation.\ +Universally understood icons work well (ie. print, close, play/pause, save).\ +Use standard icons when their use matches their meaning, or at least the user's intent.\ +Avoid creating new icons for every action, especially infrequently used ones.\ +Avoid using an icon alone in a button. If no label is provided, then use a tooltip. + +### Placement + +Icons are to be positioned only on the left side of the text.\ +Icons should be vertically center-aligned with the text.\ +The icon should be (approximately) the same height as the text.\ +Seeing the icon first help users to scan the page more easily, except for few cases such as navigation (right arrow). + + + + + +### Accessibility + +- Icons in Button Design: \ + Easily recognizable icons help with the quick recognition of a button’s function. If the icon is not clear enough, it loses its purpose, so in such cases, avoid using icons. +- Aria Labels: \ + Providing descriptive labels for screen readers is really helpful, especially for buttons that use icons only. + +## Ghost Buttons + +Ghost buttons are subtle and contribute to a minimalist interface design. +They are low-emphasis, making them ideal for non-primary actions in UIs. +They're also effective in space-limited areas like tables or key-value lists. + +- Ensure tooltips are included for clarity +- Don't confuse them with non-interactive elements like descriptive icons or status indicators +- Use them for secondary or less crucial actions. +- Don't opt for them over Outline buttons, which are more visibly recognizable as buttons. +- Create too many different instances of ghost buttons; limit them to common actions (e.g. link to other UIs). + + + +### Playground + + + + diff --git a/stories/buttonv2.stories.tsx b/stories/Button/button.stories.tsx similarity index 51% rename from stories/buttonv2.stories.tsx rename to stories/Button/button.stories.tsx index 26a7c2d739..3ae42183c9 100644 --- a/stories/buttonv2.stories.tsx +++ b/stories/Button/button.stories.tsx @@ -1,17 +1,11 @@ -import React from 'react'; import { action } from '@storybook/addon-actions'; -import { - Button, - Props, -} from '../src/lib/components/buttonv2/Buttonv2.component'; -import { Wrapper } from './common'; -import { CopyButton } from '../src/lib/next'; - -import { tooltipArgTypes, iconArgType } from './controls'; -import { Form, Icon, Input, Stack } from '../src/lib'; -import { StoryObj } from '@storybook/react'; -import { Position } from '../src/lib/components/tooltip/Tooltip.component'; -import { CSSProperties } from 'styled-components'; +import React from 'react'; +import { Form, FormGroup, FormSection, Icon, Stack } from '../../src/lib'; +import { Button } from '../../src/lib/components/buttonv2/Buttonv2.component'; +import { Input } from '../../src/lib/next'; +import { brand } from '../../src/lib/style/theme'; +import { iconArgType } from '../controls'; +import { Wrapper } from '../common'; export default { title: 'Components/Button', @@ -26,30 +20,18 @@ export default { args: { onClick: action('Button clicked'), }, + render: ({ icon, ...args }) => { + return } />; + }, argTypes: { - ...tooltipArgTypes, + onClick: { + description: 'Function called on click', + }, + variant: { + description: 'Button variant', + }, icon: iconArgType, }, - render: ({ - // defines new args to have control over tooltip properties - tooltipOverlay, - tooltipPlacement, - tooltipOverlayStyle, - icon, - ...args - }) => { - const props: Props = { ...args }; - // define tootltip with the new args - props.tooltip = { - overlay: tooltipOverlay, - placement: tooltipPlacement, - overlayStyle: tooltipOverlayStyle, - }; - - return ( - } {...props}> - ); - }, }; export const Playground = { @@ -65,25 +47,25 @@ export const DefaultButtons = { } + icon={icon && } {...args} /> } + icon={icon && } {...args} /> } + icon={icon && } {...args} /> } + icon={icon && } {...args} /> > @@ -105,35 +87,92 @@ export const Secondary = { }, }; -export const Tertiary = { +export const Outline = { args: { variant: 'outline', - label: 'Tertiary', + label: 'Outline', + }, +}; + +export const Danger = { + args: { + variant: 'danger', + label: 'Danger', }, }; export const SimpleForm = { - render: ({ ...args }) => { + render: ({ args }) => { return ( - + } + /> } > - {}} /> + + } + required + > + } + required + > + ); }, }; +export const ButtonSizes = { + render: ({ icon, ...args }) => { + return ( + <> + } + {...args} + /> + } + {...args} + /> + > + ); + }, +}; + export const ButtonsWithIcon = { ...DefaultButtons, args: { - icon: , + icon: 'Save', }, }; @@ -151,14 +190,21 @@ export const ButtonDisabled = { }, }; +export const ButtonLoading = { + ...ButtonsWithIcon, + args: { + isLoading: true, + }, +}; + export const IconButtonWithTooltip = { - render: ({ icon, ...args }) => { + render: ({ ...args }) => { return ( - <> - } {...args} /> + + } {...args} /> } + icon={} tooltip={{ overlayStyle: { width: '80px', @@ -167,22 +213,19 @@ export const IconButtonWithTooltip = { placement: 'top', }} /> + + } variant="danger" /> } - {...args} - variant="danger" - /> - } {...args} + icon={} variant="outline" /> - > + ); }, args: { variant: 'primary', - icon: 'Delete', + icon: , tooltip: { overlayStyle: { width: '80px', @@ -231,77 +274,35 @@ export const GhostButtons = { ); }, }; -export const CopyButtons: StoryObj< - Props & { - label?: string; - textToCopy: string; - variant?: 'outline' | 'ghost'; - tooltipPlacement: Position; - tooltipOverlay: React.ReactNode; - tooltipOverlayStyle: CSSProperties; - } -> = { - render: ({ ...args }) => , - args: { - textToCopy: 'test', + +export const LinkButton = { + render: ({ icon, ...args }) => { + return ( + <> + } + {...args} + variant="primary" + onClick={() => window.open('/')} + /> + } + variant="primary" + onClick={() => + window.open('https://en.wikipedia.org/wiki/Button_(computing)') + } + /> + > + ); }, argTypes: { icon: { - table: { - disable: true, - }, - }, - tooltipPlacement: { - table: { - disable: true, - }, + description: + 'Use the icon External-link to indicate that the button will redirect outside the UI', + control: 'radio', + options: ['External-link', 'No icon'], }, - tooltip: { - table: { - disable: true, - }, - }, - tooltipOverlay: { - table: { - disable: true, - }, - }, - tooltipOverlayStyle: { - table: { - disable: true, - }, - }, - }, -}; -export const CopyButtonsWithLabel = { - ...CopyButtons, - args: { - ...CopyButtons.args, - label: 'Test', - }, -}; - -export const OutlinedCopyButton = { - ...CopyButtons, - args: { - ...CopyButtons.args, - variant: 'outline', - }, -}; - -export const OutlinedCopyButtonWithLabel = { - ...OutlinedCopyButton, - args: { - ...OutlinedCopyButton.args, - label: 'Test', - }, -}; - -export const OutlinedCopyButtonWithBigLabel = { - ...OutlinedCopyButton, - args: { - ...OutlinedCopyButton.args, - label: 'Certificate', - textToCopy: 'Certificate', }, }; diff --git a/stories/Icon.mdx b/stories/Icon.mdx index 2f5def73d9..df0da2599e 100644 --- a/stories/Icon.mdx +++ b/stories/Icon.mdx @@ -19,12 +19,12 @@ import * as IconStories from './icon.stories'; - + - + diff --git a/stories/InfoMessage/infomessage.guideline.mdx b/stories/InfoMessage/infomessage.guideline.mdx new file mode 100644 index 0000000000..ae6f417722 --- /dev/null +++ b/stories/InfoMessage/infomessage.guideline.mdx @@ -0,0 +1,32 @@ +import { Meta, Story, Canvas, Primary, Controls } from '@storybook/blocks'; + +import * as Stories from './infomessage.stories.tsx'; + + + +# InfoMessage + +This component provides complementary information to the user to help them understand what to do. +A link can be added for more information. + +## Style + +## Usage + +It is used only for non critical information. +It is typically used in forms or in modal to help the user. + + + +## Variations + +### Background + +This component automatically adapts its background to contrast with its parent element. + + + +## Playground + + + diff --git a/stories/infomessage.stories.tsx b/stories/InfoMessage/infomessage.stories.tsx similarity index 76% rename from stories/infomessage.stories.tsx rename to stories/InfoMessage/infomessage.stories.tsx index 9d56a7ede7..ac6936adec 100644 --- a/stories/infomessage.stories.tsx +++ b/stories/InfoMessage/infomessage.stories.tsx @@ -1,16 +1,31 @@ -import React from 'react'; -import { InfoMessage } from '../src/lib/components/infomessage/InfoMessage.component'; -import { Wrapper } from './common'; import { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; import { useTheme } from 'styled-components'; -import { CoreUITheme } from '../src/lib/style/theme'; +import { InfoMessage } from '../../src/lib/components/infomessage/InfoMessage.component'; +import { CoreUITheme } from '../../src/lib/style/theme'; type Story = StoryObj; const meta: Meta = { title: 'Components/InfoMessage', component: InfoMessage, - decorators: [(story) => {story()}], + argTypes: { + title: { + description: 'Title of the info message', + control: { + type: 'text', + }, + }, + content: { + description: 'Content of the info message', + control: { + type: 'text', + }, + }, + link: { + description: 'Link to an external resource', + }, + }, }; export default meta; @@ -30,20 +45,14 @@ export const Playground: StoryObj< padding: '1rem', }} > - - - + ); }, + args: { + title: 'Title for the provided info', + content: 'Some text that will help the user to understand what to do', + }, argTypes: { backgroundColor: { description: 'Background color of the parent element', @@ -71,7 +80,7 @@ export const Default: Story = { export const WithLink: Story = { args: { ...Default.args, - link: 'toDocs', + link: '', }, }; diff --git a/stories/Select/select.guideline.mdx b/stories/Select/select.guideline.mdx new file mode 100644 index 0000000000..9692609935 --- /dev/null +++ b/stories/Select/select.guideline.mdx @@ -0,0 +1,73 @@ +import { + Meta, + Story, + Canvas, + Primary, + Controls, + Unstyled, + Source, +} from '@storybook/blocks'; +import { Select } from '../../src/lib/components/selectv2/Selectv2.component'; + +import * as SelectStories from './selectv2.stories'; + + + +# Select + +## Size & Style + +## Usage + +Use the select component to allow the user to choose between defined options. +You can use icons to differentiates the different options; in this case, all labels should have icons. + +## Variations + +The select component come with multiple props allowing customization and adaptation to various scenarios. + +### Size variations + +By default the Select component width is 20.5rem . +You can reduce its size by defining the 'size' props to two third, half or one third of the default size : + + + +### Options number + +Depending on the number of options provided to the select, different features will be automatically enabled. + +#### No option + +When no option are provided, a clear information will be given to the user + + + +#### Scrollbar: + +When the number of options exceeds four, a scrollbar appears, allowing users to scroll through the available options. + + + +#### Searchbar: + +If the number of options is greater than eight, +a search bar is automatically added, enabling users to quickly find and select options. + + + +### Disable state + +The Select component can be easily disabled, preventing user interaction. +This is useful in scenarios where user input is not allowed or required + + + +### Dropdown Placement + +In cases where there is limited space at the bottom of the viewport, +the dropdown menu intelligently opens toward the top to ensure visibility and usability. + + + + diff --git a/stories/Select/selectv2.stories.tsx b/stories/Select/selectv2.stories.tsx new file mode 100644 index 0000000000..dcb2889c1c --- /dev/null +++ b/stories/Select/selectv2.stories.tsx @@ -0,0 +1,120 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Icon } from '../../src/lib/components/icon/Icon.component'; +import { Modal } from '../../src/lib/components/modal/Modal.component'; +import { Select } from '../../src/lib/components/selectv2/Selectv2.component'; +import { Wrapper } from '../common'; + +export default { + title: 'Components/Inputs/Select', + component: Select, + decorators: [ + (story) => {story()}, + ], +}; +const sizes = ['1/3', '1/2', '2/3', '1']; + +const SelectWrapper = styled.div` + display: flex; + justify-content: space-around; + height: 15rem; +`; + +const generateOptions = (n = 10) => + Array.from(new Array(n), (_, index) => ( + : null} + >{`Option ${index + 1}`} + )); + +const optionsWithSearchBar = generateOptions(25); +const optionsWithoutSearchBar = generateOptions(7); +const defaultOptions = generateOptions(4); +const thousandsOfOptions = generateOptions(1000); + +export const Playground = { + args: { + children: defaultOptions, + placeholder: 'Playground', + }, +}; + +export const WithoutOptions = { + args: { + options: [], + placeholder: 'No options', + }, +}; + +export const DisabledSelect = { + args: { + disabled: true, + defaultValue: defaultOptions[0].props.value, + children: defaultOptions, + }, +}; + +export const WithScrollbar = { + name: 'More than 4 items', + args: { + children: optionsWithoutSearchBar, + }, +}; + +export const WithSearchBar = { + args: { + children: optionsWithSearchBar, + }, +}; + +export const LotsOfOptions = { + args: { + children: thousandsOfOptions, + }, +}; + +export const DifferentSizes = { + render: (args) => ( + + {sizes.map((size) => ( + + ))} + + ), + args: { + children: defaultOptions, + }, +}; + +export const NotEnoughPlaceAtTheBottom = { + render: (args) => ( + + + + ), + args: { + children: optionsWithSearchBar, + }, +}; + +export const InsideModal = { + render: (args) => ( + + + + ), + args: { + children: optionsWithoutSearchBar, + }, +}; diff --git a/stories/areachart.stories.tsx b/stories/areachart.stories.tsx index c575682d96..16e2c598d0 100644 --- a/stories/areachart.stories.tsx +++ b/stories/areachart.stories.tsx @@ -106,7 +106,6 @@ const id_area_chart = 'vis_area_chart'; export default { title: 'Components/Data Display/Charts/Area Chart', component: AreaChart, - decorators: [(story) => {story()}], }; export const Default = { diff --git a/stories/banner.stories.tsx b/stories/banner.stories.tsx index 02d0e47e5f..eb8e8136b7 100644 --- a/stories/banner.stories.tsx +++ b/stories/banner.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { Banner } from '../src/lib/components/banner/Banner.component'; import { Icon } from '../src/lib/components/icon/Icon.component'; import { Wrapper } from './common'; -import { iconOptions } from './controls'; +import { iconArgType } from './controls'; export default { title: 'Components/Feedback/Banner', @@ -12,9 +12,7 @@ export default { icon: 'Exclamation-triangle', }, argTypes: { - icon: { - options: iconOptions, - }, + icon: iconArgType, }, }; diff --git a/stories/chips.stories.tsx b/stories/chips.stories.tsx index aefb9c3e63..147a875321 100644 --- a/stories/chips.stories.tsx +++ b/stories/chips.stories.tsx @@ -1,9 +1,9 @@ -import { Chips } from '../src/lib/components/chips/Chips.component'; -import React from 'react'; import { action } from '@storybook/addon-actions'; -import { Wrapper } from './common'; +import React from 'react'; +import { Chips } from '../src/lib/components/chips/Chips.component'; import { Icon } from '../src/lib/components/icon/Icon.component'; -import { iconOptions } from './controls'; +import { Wrapper } from './common'; +import { iconArgType } from './controls'; export default { title: 'Components/Deprecated/Chips', @@ -19,9 +19,7 @@ export default { ), ], argTypes: { - icon: { - options: iconOptions, - }, + icon: iconArgType, }, }; diff --git a/stories/common.tsx b/stories/common.tsx index 5864717b2c..cea1333180 100644 --- a/stories/common.tsx +++ b/stories/common.tsx @@ -2,10 +2,10 @@ import React from 'react'; import styled from 'styled-components'; import { getThemePropSelector } from '../src/lib/utils'; const StyledWrapper = styled.div` - padding: 30px; - height: 30vh; - background-color: ${getThemePropSelector('backgroundLevel1')}; - color: ${getThemePropSelector('textPrimary')}; + padding: 3rem; + height: 100%; + background-color: ${(props) => props.theme.backgroundLevel1}; + color: ${(props) => props.theme.textPrimary}; `; const StyledTitle = styled.h3` color: ${getThemePropSelector('textPrimary')}; diff --git a/stories/controls.ts b/stories/controls.ts index 945d0ad9c0..9ed5ec3216 100644 --- a/stories/controls.ts +++ b/stories/controls.ts @@ -2,6 +2,22 @@ import { iconTable } from "../src/lib/components/icon/Icon.component"; export const iconOptions = Object.keys(iconTable); +export const sizesOptions = ['smaller', 'small', 'base', 'large', 'larger']; + +export const placementOptions = [ + 'top', + 'bottom', + 'left', + 'top-start', + 'top-end', + 'right', + 'right-start', + 'right-end', + 'bottom-end', + 'bottom-start', + 'left-start', + 'left-end', + ]; export const localeArgtype = { control: { type: 'radio' }, options: ['en', 'fr'], @@ -11,7 +27,10 @@ export const localeArgtype = { export const iconArgType = { control: { type: 'select' }, options: iconOptions, - description: 'Icon to display in the button', + description: 'Icon to display with the component', + table: { + type: { summary: 'Element' }, + }, }; export const variantsOptions = [ @@ -20,22 +39,7 @@ export const variantsOptions = [ 'buttonDelete', 'backgroundLevel1', ]; -export const sizesOptions = ['smaller', 'small', 'base', 'large', 'larger']; -export const placementOptions = [ - 'top', - 'bottom', - 'left', - 'top-start', - 'top-end', - 'right', - 'right-start', - 'right-end', - 'bottom-end', - 'bottom-start', - 'left-start', - 'left-end', - ]; export const tooltipArgTypes = { tooltip: { diff --git a/stories/copybutton.stories.tsx b/stories/copybutton.stories.tsx new file mode 100644 index 0000000000..7aedad22e9 --- /dev/null +++ b/stories/copybutton.stories.tsx @@ -0,0 +1,58 @@ +import { Meta, StoryObj } from '@storybook/react'; +import React from 'react'; +import { CopyButton } from '../src/lib/next'; +import { Wrapper } from './common'; + +type Story = StoryObj; + +const meta: Meta = { + title: 'Components/CopyButton', + component: CopyButton, + decorators: [ + (story) => ( + + {story()} + + ), + ], +}; + +export default meta; + +export const CopyButtons: Story = { + args: { + textToCopy: 'Playground', + }, +}; +export const CopyButtonsWithLabel: Story = { + ...CopyButtons, + args: { + ...CopyButtons.args, + label: 'Test', + }, +}; + +export const OutlinedCopyButton: Story = { + ...CopyButtons, + args: { + ...CopyButtons.args, + variant: 'outline', + }, +}; + +export const OutlinedCopyButtonWithLabel: Story = { + ...OutlinedCopyButton, + args: { + ...OutlinedCopyButton.args, + label: 'Test', + }, +}; + +export const OutlinedCopyButtonWithBigLabel: Story = { + ...OutlinedCopyButton, + args: { + ...OutlinedCopyButton.args, + label: 'Certificate', + textToCopy: 'Certificate', + }, +}; diff --git a/stories/dropdown.stories.tsx b/stories/dropdown.stories.tsx index 5ccc19cfb2..3aba3d2a43 100644 --- a/stories/dropdown.stories.tsx +++ b/stories/dropdown.stories.tsx @@ -1,10 +1,10 @@ +import { action } from '@storybook/addon-actions'; import React from 'react'; +import { Icon } from '../src/lib'; import { Dropdown } from '../src/lib/components/dropdown/Dropdown.component'; -import { action } from '@storybook/addon-actions'; import { Wrapper } from './common'; -import { Icon } from '../src/lib'; import { - iconOptions, + iconArgType, sizesOptions as sizes, variantsOptions as variants, } from './controls'; @@ -49,9 +49,7 @@ export default { items, }, argTypes: { - icon: { - options: iconOptions, - }, + icon: iconArgType, size: { options: sizes, control: { @@ -88,7 +86,7 @@ export const DropdownWithText = { export const DropdownWithIcon = { args: { - icon: , + icon: 'Folder', caret: false, }, }; diff --git a/stories/emptystate.stories.tsx b/stories/emptystate.stories.tsx index f9cd477490..6c284bf78c 100644 --- a/stories/emptystate.stories.tsx +++ b/stories/emptystate.stories.tsx @@ -4,7 +4,6 @@ import { Wrapper } from './common'; export default { title: 'Components/Data Display/EmptyState', component: EmptyState, - decorators: [(story) => {story()}], args: { icon: 'Node-backend', label: 'Node', diff --git a/stories/form.stories.tsx b/stories/form.stories.tsx index 73957d355c..61ba2e9a5f 100644 --- a/stories/form.stories.tsx +++ b/stories/form.stories.tsx @@ -1,19 +1,18 @@ +import React, { useState } from 'react'; +import { Banner } from '../src/lib/components/banner/Banner.component'; +import { Button } from '../src/lib/components/buttonv2/Buttonv2.component'; import { Form, FormGroup, FormSection, } from '../src/lib/components/form/Form.component'; -import React from 'react'; -import { brand } from '../src/lib/style/theme'; -import { Stack } from '../src/lib/spacing'; -import { Button } from '../src/lib/components/buttonv2/Buttonv2.component'; import { Icon } from '../src/lib/components/icon/Icon.component'; import { Input } from '../src/lib/components/inputv2/inputv2'; -import { Toggle } from '../src/lib/components/toggle/Toggle.component'; -import { Banner } from '../src/lib/components/banner/Banner.component'; -import { Text } from '../src/lib/components/text/Text.component'; import { Select } from '../src/lib/components/selectv2/Selectv2.component'; -import { iconOptions } from './controls'; +import { Text } from '../src/lib/components/text/Text.component'; +import { Toggle } from '../src/lib/components/toggle/Toggle.component'; +import { Stack } from '../src/lib/spacing'; +import { iconArgType } from './controls'; export default { title: 'Templates/Form', @@ -24,17 +23,24 @@ export default { subTitle: 'Some Subtitle', }, argTypes: { - layout: { control: false }, + layout: { + control: false, + description: + 'Control the layout of the form, it is an object containing "kind", "title", "subTitle" and "icon", if the kind is "page" the title and subTitle are required', + table: { + type: { + summary: + 'Object{kind: "page" | "tab", title: string, subTitle: string, icon: Element}', + }, + }, + }, kind: { options: ['page', 'tab'], control: { type: 'radio' }, }, icon: { - options: iconOptions, - control: { - type: 'select', - }, if: { arg: 'kind', eq: 'page' }, + ...iconArgType, }, title: { control: 'text', @@ -55,166 +61,164 @@ export const PageForm = { subTitle, icon, }; + const [toggle, setToggle] = useState(true); return ( - + + } + /> + + } + banner={ + } + title={'Error'} + > + There is an error + + } > - - - } - /> - - } - banner={ - } - title={'Error'} - > - There is an error - - } + - - } - help="Optional helper text" - required - disabled - > - } - error="Invalid email format. Try with a better format." - helpErrorPosition="right" - required - > - - - {}} toggle={true} name="toggle" /> - } - help="Optional helper text" - required={false} - > - } - error="Invalid email format. Try with a better format." - helpErrorPosition="right" - required={false} - > - } - help="optional helper text" - helpErrorPosition="bottom" - required={false} - > - - - } + help="Optional helper text" + required + disabled + > + } + error="Invalid email format. Try with a better format." + helpErrorPosition="right" + required + > + + + { + setToggle(!toggle); + }} + toggle={toggle} + name="toggle" + /> + } + help="Optional helper text" + required={false} + > + } + error="Invalid email format. Try with a better format." + helpErrorPosition="right" + required={false} + > + } + help="optional helper text" + helpErrorPosition="bottom" + required={false} + > + + + - - - - Governance - - - An user with a specific IAM permissions can - overwrite/delete protected object versions during the - retention period. - - - Compliance + Governance - No one can overwrite protected object versions during the - retention period. + An user with a specific IAM permissions can overwrite/delete + protected object versions during the retention period. - } - required={true} - > - {}} - value={'value-1'} - > - Value 1 - Value 2 - Value 3 - - } - /> - - - + + + Compliance + + + No one can overwrite protected object versions during the + retention period. + + + } + required={true} + > + {}} + value={'value-1'} + > + Value 1 + Value 2 + Value 3 + + } + /> + + ); }, args: { diff --git a/stories/guideline/button-guideline.mdx b/stories/guideline/button-guideline.mdx deleted file mode 100644 index 0710f23f19..0000000000 --- a/stories/guideline/button-guideline.mdx +++ /dev/null @@ -1,137 +0,0 @@ -import { Meta, Story, Canvas, Primary, Controls } from '@storybook/blocks'; -import { Button } from '../../src/lib/components/button/Button.component'; -import * as ButtonStories from '../buttonv2.stories'; - - - -# Button - -## Size & style - -- Only 1 size is used - Height: 32px -- Border-radius: 3px -- Minimum width: 80px - -| | px | -| ------- | --- | -| Smaller | 24 | -| Small | 28 | -| Default | 32 | -| Large | 36 | -| Larger | 40 | - -## Padding - -Button’s label measurement: - -- Line height: 20px -- Vertical padding: 8px -- Horizontal padding of 16px -- Space between icon & label: 8px - -## Explicit button label - -Button labels should be as short and clear as possible and should describe the action the button performs.\ -Use one or two words if possible. Remove most prepositions and articles (a, an, the). - -Examples: Cancel, Close, Create, Delete, Edit, Learn more, Review, Save, Study, View scores, etc. - -Since buttons are action points for the user, button text should also be actionable. Stick to using verbs (Complete, Start/Finish, Search) or a simple verb + noun combination for buttons (Next Page, Submit Post, Learn More). Whichever labeling method you choose, maintain consistency across all of your buttons. - -- Use sentence case. -- Capitalize proper nouns. -- Use specific action-oriented text for CTAs. - -Examples: Add Volume, Create Account, Go to Dashboard, Reset Password, Send Reset link, Sign in, etc. - -Be sure to: - -- Check for consistent use across the UI. -- Reserve enough space for translation to other languages. -- Avoid excessive use of exclamation points (!). - -Don't: - -- Use icons only. -- Use punctuation. -- Write “Click here.” - -## Type - -### Primary - -Used for the main action. It appears once within a group of buttons. For example, “Continue” in a form. - - - -### Secondary/base - -Use for the secondary action within a group of buttons. - - - -### Tertiary - -Dismissive action, such as the cancel button. - - - - -### Links - -_to add_ - -## States - -_to produce_ - -### Disabled button - -Disabled state only if an action on the current screen can enable it (action possibility). - - - -## Placement - -- Primary buttons placed on the right of a group. -- Dismissive actions placed on the left. It allows the user to return to the previous screen or step in the process. - -Align button groups with the container's right side by default; however, based on the use case and visual balance it can be aligned differently. - - - -### Button spacing - -- Horizontal spacing: 16px -- Vertical spacing: 12px -- Space between 2 buttons: 24px - when there is no space constraint - -## Icon on buttons - -### Which icon - -Every button gets a label.\ -Icons are optional and mainly used to show how buttons are different, to aid memory and differentiation.\ -Universally understood icons work well (ie. print, close, play/pause, save).\ -Use standard icons when their use matches their meaning, or at least the user's intent.\ -Avoid creating new icons for every action, especially infrequently used ones.\ -Avoid using an icon alone in a button, with no label. - -### Placement - -If icon + label, then the icon is placed on the left side.\ -Seeing the icon first help users to scan the page more easily, except for few cases such as navigation (right arrow). - -### Size - -The icon should be (approximately) the same height as the text, or a lot bigger. - - - - - -### Playground - - - - diff --git a/stories/guideline/docs-template.mdx b/stories/guideline/docs-template.mdx new file mode 100644 index 0000000000..b83f3f1c85 --- /dev/null +++ b/stories/guideline/docs-template.mdx @@ -0,0 +1,43 @@ +import { + Meta, + Story, + Canvas, + Primary, + Controls, + Unstyled, + Source, +} from '@storybook/blocks'; + +{/* import * as Stories from './componentStories'; */} + + + +# Component name + +General description + +## Style + +## Usage + +General guideline about the component +Do & Don'ts ? + +## Variations + +### Size variations + +What sizes are used for this component ? When to use them + +### Style Variations + +Does this component has variations ? When to use them + +### Status Variations + +Does this component can be disable ? When ? + +## Playground + +Playground section with pure story and every control enable +Allow to "built" the component visually and export the code directly diff --git a/stories/linechart.stories.tsx b/stories/linechart.stories.tsx index dce407a2c3..3550517c7e 100644 --- a/stories/linechart.stories.tsx +++ b/stories/linechart.stories.tsx @@ -254,7 +254,6 @@ const tooltipConfigInOut = { export default { title: 'Components/Data Display/Charts/LineChart', component: LineChart, - decorators: [(story) => {story()}], args: { width: 800, tooltip: true, diff --git a/stories/linecharttemporal.stories.tsx b/stories/linecharttemporal.stories.tsx index a1c204143c..6ff3d14502 100644 --- a/stories/linecharttemporal.stories.tsx +++ b/stories/linecharttemporal.stories.tsx @@ -10,7 +10,7 @@ import { Wrapper } from './common'; import { dataLineChartV2, dataLineChartV2_readwrite } from './data/linechart'; import { defaultRenderTooltipSerie } from '../src/lib/components/linetemporalchart/tooltip'; export default { - title: 'Components/Data Display/Charts/v2/LineTemporalChart', + title: 'Components/Data Display/Charts/LineTemporalChart', component: LineTemporalChart, decorators: [ (story) => ( diff --git a/stories/loader.stories.tsx b/stories/loader.stories.tsx index 39c449e974..a057901c7b 100644 --- a/stories/loader.stories.tsx +++ b/stories/loader.stories.tsx @@ -6,7 +6,6 @@ import { Size } from '../src/lib/components/constants'; const info = { title: 'Components/Progress & loading/Loader', component: Loader, - decorators: [(story) => {story()}], args: { size: 'base', children: 'Loading', diff --git a/stories/progressbar.stories.tsx b/stories/progressbar.stories.tsx index 7635464737..8fc6717c9f 100644 --- a/stories/progressbar.stories.tsx +++ b/stories/progressbar.stories.tsx @@ -4,13 +4,7 @@ import { Wrapper, Title } from './common'; export default { title: 'Components/Progress & loading/ProgressBar', component: ProgressBar, - decorators: [ - (story) => ( - - {story()} - - ), - ], + decorators: [(story) => {story()}], args: { percentage: 50, buildinLabel: '50%', diff --git a/stories/searchinput.stories.tsx b/stories/searchinput.stories.tsx index 12b2c7eb19..d6eba65a04 100644 --- a/stories/searchinput.stories.tsx +++ b/stories/searchinput.stories.tsx @@ -3,7 +3,7 @@ import { action } from '@storybook/addon-actions'; import { SearchInput } from '../src/lib/components/searchinput/SearchInput.component'; import { Wrapper, Title } from './common'; export default { - title: 'Components/Deprecated/SearchInput', + title: 'Components/Inputs/SearchInput', component: SearchInput, }; export const Default = { diff --git a/stories/select.stories.tsx b/stories/select.stories.tsx index e5c262604f..b88b5d1323 100644 --- a/stories/select.stories.tsx +++ b/stories/select.stories.tsx @@ -17,7 +17,6 @@ const customFormatOptionLabel = ({ value, label, ...rest }) => ( export default { title: 'Components/Deprecated/Selector/Select', component: Select, - decorators: [(story) => {story()}], argTypes: { options: { description: 'Array of objects with label, title and value properties', diff --git a/stories/selectinput.stories.tsx b/stories/selectinput.stories.tsx index ed4d0a8616..1756dbb36a 100644 --- a/stories/selectinput.stories.tsx +++ b/stories/selectinput.stories.tsx @@ -20,7 +20,7 @@ const SelectWrapper = styled.div` `; const meta: Meta = { - title: 'Components/Inputs/v2/SelectInput', + title: 'Components/Inputs/SelectInput', component: Select, decorators: [(story) => {story()}], args: { diff --git a/stories/selectv2.stories.tsx b/stories/selectv2.stories.tsx deleted file mode 100644 index 19785652a5..0000000000 --- a/stories/selectv2.stories.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { - Select, - Option, -} from '../src/lib/components/selectv2/Selectv2.component'; -import React, { useState } from 'react'; -import { Wrapper } from './common'; -import { Icon } from '../src/lib/components/icon/Icon.component'; -import { Modal } from '../src/lib/components/modal/Modal.component'; -export default { - title: 'Components/Inputs/v2/Select', - component: Select, - decorators: [ - (story) => {story()}, - ], -}; - -const generateOptions = (n = 10) => - Array.from(new Array(n), (_, index) => ({ - label: `Item ${index}`, - value: index.toString(), - disabled: index !== 0 && index % 8 === 0, - icon: index % 5 === 0 ? : null, - })); - -const optionsWithSearchBar = generateOptions(25); -const optionsWithoutSearchBar = generateOptions(7); -const defaultOptions = generateOptions(4); -const thousandsOfOptions = generateOptions(1000); - -const CustomSelect = (props) => { - const [value, setValue] = useState(''); - return ( - setValue(value)} {...props}> - {props.opts && - props.opts.map((o, i) => ( - - {o.label} - - ))} - - ); -}; - -export const Playground = { - args: { - options: defaultOptions, - placeholder: 'Playground', - }, -}; - -export const WithoutOptions = { - args: { - options: [{}], - placeholder: 'No options', - }, -}; - -export const DisabledSelect = { - args: { - disabled: true, - defaultValue: defaultOptions[1].value, - }, -}; - -export const WithScollbar = { - name: 'More than 4 items', - args: { - options: optionsWithoutSearchBar, - }, -}; - -export const WithSearchBar = { - render: (args) => { - return ; - }, - args: { - opts: optionsWithSearchBar, - }, -}; - -export const LotsOfOptions = { - ...WithSearchBar, - args: { - opts: thousandsOfOptions, - }, -}; - -export const NotEnoughPlaceAtTheBottom = { - render: (args) => ( - - - - ), - args: { - options: optionsWithSearchBar, - }, -}; - -export const RoundedVariant = { - args: { - variant: 'rounded', - options: defaultOptions, - }, -}; - -export const InsideModal = { - render: (args) => ( - - - - ), - args: { - options: optionsWithoutSearchBar, - }, -}; diff --git a/stories/statuswrapper.stories.tsx b/stories/statuswrapper.stories.tsx index 0d4a60ee8b..8def8f8925 100644 --- a/stories/statuswrapper.stories.tsx +++ b/stories/statuswrapper.stories.tsx @@ -18,7 +18,6 @@ const PreviewWrapper = styled(Wrapper)` export default { title: 'Components/Data Display/StatusWrapper', component: StatusWrapper, - decorators: [(story) => {story()}], args: { children: , }, diff --git a/stories/steppers.stories.tsx b/stories/steppers.stories.tsx index f6552b55cc..5f390883ac 100644 --- a/stories/steppers.stories.tsx +++ b/stories/steppers.stories.tsx @@ -91,7 +91,6 @@ stepsWithError[2] = { export default { title: 'Components/Progress & loading/Steppers', component: Steppers, - decorators: [(story) => {story()}], }; export const DefaultSteppers = { diff --git a/stories/tablev2.stories.tsx b/stories/tablev2.stories.tsx index cf43fded42..e2a52779da 100644 --- a/stories/tablev2.stories.tsx +++ b/stories/tablev2.stories.tsx @@ -16,7 +16,7 @@ const Flex = styled(Box)` `; const info = { - title: 'Components/Data Display/V2/Table', + title: 'Components/Data Display/Table', component: Table, }; diff --git a/stories/tabsv2.stories.tsx b/stories/tabsv2.stories.tsx index 903dbb39ce..e7c5a2591b 100644 --- a/stories/tabsv2.stories.tsx +++ b/stories/tabsv2.stories.tsx @@ -11,15 +11,9 @@ const Content = styled.div` color: ${(props) => props.theme.textPrimary}; `; export default { - title: 'Components/Navigation/v2/Tabs', + title: 'Components/Navigation/Tabs', component: Tabs, - decorators: [ - (story) => ( - - {story()} - - ), - ], + decorators: [(story) => {story()}], argTypes: { activeTabSeparator: { control: { diff --git a/stories/toast.stories.tsx b/stories/toast.stories.tsx index 196a32a811..2def42b637 100644 --- a/stories/toast.stories.tsx +++ b/stories/toast.stories.tsx @@ -90,7 +90,7 @@ const Template = (args: Omit) => { ? 'Check-circle' : 'Info-circle'; return ( - <> + {!open && ( setOpen(true)} /> )} @@ -100,54 +100,39 @@ const Template = (args: Omit) => { icon={} {...args} /> - > - ); -}; - -export const SimpleToast = ({}) => { - const [open, setOpen] = useState(false); - - const handleClick = () => { - setOpen(true); - }; - - return ( - - {!open && } - {"I'm a toast"}} - onClose={() => setOpen(false)} - status="info" - /> ); }; -export const ToastWithProgressBar = ({}) => { - const [open, setOpen] = useState(false); +export const SimpleToast = { + render: (args) => { + const [open, setOpen] = useState(false); - const handleClick = () => { - setOpen(true); - }; + const handleClick = () => { + setOpen(true); + }; - return ( - - {!open && ( - + {!open && } + {"I'm a toast"}} + onClose={() => setOpen(false)} + status="info" + {...args} /> - )} - {"I'm a toast with a progress bar"}} - onClose={() => setOpen(false)} - status="info" - withProgressBar - /> - - ); + + ); + }, +}; + +export const ToastWithProgressBar = { + ...SimpleToast, + args: { + message: {"I'm a toast with a progress bar"}, + withProgressBar: true, + }, }; export const CustomToast: { diff --git a/stories/toggle.stories.tsx b/stories/toggle.stories.tsx index 863674208c..90bfd24aae 100644 --- a/stories/toggle.stories.tsx +++ b/stories/toggle.stories.tsx @@ -5,7 +5,6 @@ import { useArgs } from '@storybook/preview-api'; export default { title: 'Components/Inputs/Toggle', component: Toggle, - decorators: [(story) => {story()}], args: { name: 'toggle', },