diff --git a/packages/strapi-design-system/src/Button/Button.js b/packages/strapi-design-system/src/Button/Button.js index 9faec700d..3df9f4b9c 100644 --- a/packages/strapi-design-system/src/Button/Button.js +++ b/packages/strapi-design-system/src/Button/Button.js @@ -20,6 +20,7 @@ const rotation = keyframes` const LoadingWrapper = styled.div` animation: ${rotation} 2s infinite linear; + will-change: transform; `; const BoxFullHeight = styled(Box)` diff --git a/packages/strapi-design-system/src/Loader/Loader.js b/packages/strapi-design-system/src/Loader/Loader.js index d1b9f9015..885c5bd2a 100644 --- a/packages/strapi-design-system/src/Loader/Loader.js +++ b/packages/strapi-design-system/src/Loader/Loader.js @@ -15,6 +15,7 @@ const rotation = keyframes` const LoaderImg = styled.img` animation: ${rotation} 1s infinite linear; + will-change: transform; ${({ small, theme }) => small && `width: ${theme.spaces[6]}; height: ${theme.spaces[6]};`} `; diff --git a/packages/strapi-design-system/src/TextButton/TextButton.js b/packages/strapi-design-system/src/TextButton/TextButton.js index 3a2e0ea8a..88dd5f7ed 100644 --- a/packages/strapi-design-system/src/TextButton/TextButton.js +++ b/packages/strapi-design-system/src/TextButton/TextButton.js @@ -1,11 +1,26 @@ import React from 'react'; import PropTypes from 'prop-types'; -import styled from 'styled-components'; +import styled, { keyframes } from 'styled-components'; +import Loader from '@strapi/icons/Loader'; import { Box } from '../Box'; import { Typography } from '../Typography'; import { Flex } from '../Flex'; import { buttonFocusStyle } from '../themes/utils'; +const rotation = keyframes` + from { + transform: rotate(0deg); + } + to { + transform: rotate(359deg); + } +`; + +const LoadingWrapper = styled.div` + animation: ${rotation} 2s infinite linear; + will-change: transform; +`; + const TextButtonWrapper = styled(Flex)` background: transparent; border: none; @@ -29,27 +44,43 @@ const TextButtonWrapper = styled(Flex)` ${buttonFocusStyle} `; -export const TextButton = React.forwardRef(({ children, startIcon, endIcon, onClick, disabled, ...props }, ref) => { - const handleClick = onClick && !disabled ? onClick : undefined; +export const TextButton = React.forwardRef( + ({ children, startIcon, endIcon, onClick, disabled, loading, ...props }, ref) => { + const handleClick = onClick && !disabled ? onClick : undefined; + const isDisabled = disabled || loading; - return ( - - {startIcon && ( - - {startIcon} - - )} - - {children} - - {endIcon && ( - - {endIcon} - - )} - - ); -}); + return ( + + {(startIcon || loading) && ( + + {loading ? ( + + + + ) : ( + startIcon + )} + + )} + + {children} + + {endIcon && ( + + {endIcon} + + )} + + ); + }, +); TextButton.displayName = 'TextButton'; @@ -57,6 +88,7 @@ TextButton.defaultProps = { disabled: false, startIcon: undefined, endIcon: undefined, + loading: false, onClick: undefined, }; @@ -64,6 +96,7 @@ TextButton.propTypes = { children: PropTypes.node.isRequired, disabled: PropTypes.bool, endIcon: PropTypes.element, + loading: PropTypes.bool, onClick: PropTypes.func, startIcon: PropTypes.element, }; diff --git a/packages/strapi-design-system/src/TextButton/TextButton.stories.mdx b/packages/strapi-design-system/src/TextButton/TextButton.stories.mdx index cc951ff81..d4dee6bfe 100644 --- a/packages/strapi-design-system/src/TextButton/TextButton.stories.mdx +++ b/packages/strapi-design-system/src/TextButton/TextButton.stories.mdx @@ -39,6 +39,13 @@ Depending on the permissions a user have or the status of an action, a TextButto Click on me + + + +## Disabled + + +
} endIcon={}> Disabled TextButton @@ -47,6 +54,18 @@ Depending on the permissions a user have or the status of an action, a TextButto +## Loading + + + +
+ } endIcon={}> + Loading + +
+
+
+ ## Props diff --git a/packages/strapi-design-system/tests/__snapshots__/storyshots.spec.js.snap b/packages/strapi-design-system/tests/__snapshots__/storyshots.spec.js.snap index 99d49b564..8638e3b9f 100644 --- a/packages/strapi-design-system/tests/__snapshots__/storyshots.spec.js.snap +++ b/packages/strapi-design-system/tests/__snapshots__/storyshots.spec.js.snap @@ -5271,6 +5271,7 @@ exports[`Storyshots Design System/Components/Button icons 1`] = ` .c14 { -webkit-animation: gzYjWD 2s infinite linear; animation: gzYjWD 2s infinite linear; + will-change: transform; } .c9 { @@ -26355,6 +26356,7 @@ exports[`Storyshots Design System/Components/Loader base 1`] = ` .c3 { -webkit-animation: gzYjWD 1s infinite linear; animation: gzYjWD 1s infinite linear; + will-change: transform; }
+
+ + +`; + +exports[`Storyshots Design System/Components/TextButton disabled 1`] = ` +.c1 { + border: 0; + -webkit-clip: rect(0 0 0 0); + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.c0 { + background: #ffffff; + padding: 8px; +} + +.c2 { + padding: 8px; + height: 100%; +} + +.c5 { + padding-right: 8px; +} + +.c7 { + padding-left: 8px; +} + +.c6 { + color: #666687; + font-size: 0.75rem; + line-height: 1.33; +} + +.c3 { + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; +} + +.c4 { + background: transparent; + border: none; + position: relative; + outline: none; +} + +.c4[aria-disabled='true'] { + pointer-events: none; +} + +.c4[aria-disabled='true'] svg path { + fill: #666687; +} + +.c4 svg { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + font-size: 0.625rem; +} + +.c4 svg path { + fill: #4945ff; +} + +.c4:after { + -webkit-transition-property: all; + transition-property: all; + -webkit-transition-duration: 0.2s; + transition-duration: 0.2s; + border-radius: 8px; + content: ''; + position: absolute; + top: -4px; + bottom: -4px; + left: -4px; + right: -4px; + border: 2px solid transparent; +} + +.c4:focus-visible { + outline: none; +} + +.c4:focus-visible:after { + border-radius: 8px; + content: ''; + position: absolute; + top: -5px; + bottom: -5px; + left: -5px; + right: -5px; + border: 2px solid #4945ff; +} + +
+
+
+

+ Storybook story +

+
+
`; +exports[`Storyshots Design System/Components/TextButton loading 1`] = ` +.c1 { + border: 0; + -webkit-clip: rect(0 0 0 0); + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.c0 { + background: #ffffff; + padding: 8px; +} + +.c2 { + padding: 8px; + height: 100%; +} + +.c5 { + padding-right: 8px; +} + +.c8 { + padding-left: 8px; +} + +.c7 { + color: #666687; + font-size: 0.75rem; + line-height: 1.33; +} + +.c3 { + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; +} + +.c6 { + -webkit-animation: gzYjWD 2s infinite linear; + animation: gzYjWD 2s infinite linear; + will-change: transform; +} + +.c4 { + background: transparent; + border: none; + position: relative; + outline: none; +} + +.c4[aria-disabled='true'] { + pointer-events: none; +} + +.c4[aria-disabled='true'] svg path { + fill: #666687; +} + +.c4 svg { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + font-size: 0.625rem; +} + +.c4 svg path { + fill: #4945ff; +} + +.c4:after { + -webkit-transition-property: all; + transition-property: all; + -webkit-transition-duration: 0.2s; + transition-duration: 0.2s; + border-radius: 8px; + content: ''; + position: absolute; + top: -4px; + bottom: -4px; + left: -4px; + right: -4px; + border: 2px solid transparent; +} + +.c4:focus-visible { + outline: none; +} + +.c4:focus-visible:after { + border-radius: 8px; + content: ''; + position: absolute; + top: -5px; + bottom: -5px; + left: -5px; + right: -5px; + border: 2px solid #4945ff; +} + +
+
+
+

+ Storybook story +

+
+
+
+ +
+
+
+
+`; + exports[`Storyshots Design System/Components/TextInput base 1`] = ` .c1 { border: 0;