diff --git a/src/AppBar/AppBar.mdx b/src/AppBar/AppBar.mdx index d28ffac9..d15d8bbd 100644 --- a/src/AppBar/AppBar.mdx +++ b/src/AppBar/AppBar.mdx @@ -5,7 +5,7 @@ menu: Components import { AppBar } from './AppBar'; import Toolbar from '../Toolbar/Toolbar'; -import Button from '../Button/Button'; +import { Button } from '../Button/Button'; import TextField from '../TextField/TextField'; import List from '../List/List'; import ListItem from '../ListItem/ListItem'; diff --git a/src/Bar/Bar.mdx b/src/Bar/Bar.mdx index b316a35f..5cdcfb9c 100644 --- a/src/Bar/Bar.mdx +++ b/src/Bar/Bar.mdx @@ -6,7 +6,7 @@ menu: Components import { Bar } from '../Bar/Bar'; import { AppBar } from '../AppBar/AppBar.js'; import Toolbar from '../Toolbar/Toolbar.js'; -import Button from '../Button/Button.js'; +import { Button } from '../Button/Button.js'; # Bar diff --git a/src/Button/Button.mdx b/src/Button/Button.mdx index 5cdffc97..db5d0b04 100644 --- a/src/Button/Button.mdx +++ b/src/Button/Button.mdx @@ -3,11 +3,11 @@ name: Button menu: Components --- -import Button from './Button' -import Window from '../Window/Window' -import WindowContent from '../WindowContent/WindowContent' -import Cutout from '../Cutout/Cutout' -import Toolbar from '../Toolbar/Toolbar' +import { Button } from './Button'; +import Window from '../Window/Window'; +import WindowContent from '../WindowContent/WindowContent'; +import Cutout from '../Cutout/Cutout'; +import Toolbar from '../Toolbar/Toolbar'; # Button @@ -16,7 +16,7 @@ import Toolbar from '../Toolbar/Toolbar' #### Default - + #### Disabled @@ -58,15 +58,9 @@ import Toolbar from '../Toolbar/Toolbar' justifyContent: 'space-between' }} > - - - + + + @@ -90,14 +84,10 @@ import Toolbar from '../Toolbar/Toolbar' > Primary - - diff --git a/src/Button/Button.spec.js b/src/Button/Button.spec.tsx similarity index 98% rename from src/Button/Button.spec.js rename to src/Button/Button.spec.tsx index 741f1c8b..f79ad1e4 100644 --- a/src/Button/Button.spec.js +++ b/src/Button/Button.spec.tsx @@ -1,10 +1,9 @@ -import React from 'react'; import { render, fireEvent } from '@testing-library/react'; import { renderWithTheme, theme } from '../../test/utils'; import { blockSizes } from '../common/system'; -import Button from './Button'; +import { Button } from './Button'; const defaultProps = { children: 'click me' diff --git a/src/Button/Button.stories.js b/src/Button/Button.stories.tsx similarity index 95% rename from src/Button/Button.stories.js rename to src/Button/Button.stories.tsx index 8ca66f0f..12792fe3 100644 --- a/src/Button/Button.stories.js +++ b/src/Button/Button.stories.tsx @@ -1,17 +1,17 @@ -import React from 'react'; -import styled from 'styled-components'; - +import { ComponentMeta } from '@storybook/react'; +import { useState } from 'react'; import { Button, - Window, - WindowHeader, - WindowContent, + Cutout, + Divider, List, ListItem, - Divider, - Cutout, - Toolbar + Toolbar, + Window, + WindowContent, + WindowHeader } from 'react95'; +import styled from 'styled-components'; const Wrapper = styled.div` padding: 5rem; @@ -32,7 +32,7 @@ export default { title: 'Button', component: Button, decorators: [story => {story()}] -}; +} as ComponentMeta; export function Default() { return ( @@ -66,7 +66,7 @@ Default.story = { const imageSrc = 'https://image.freepik.com/foto-gratuito/la-frutta-fresca-del-kiwi-tagliata-a-meta-con-la-decorazione-completa-del-pezzo-e-bella-sulla-tavola-di-legno_47436-1.jpg'; export function Menu() { - const [open, setOpen] = React.useState(false); + const [open, setOpen] = useState(false); return ( diff --git a/src/Button/Button.js b/src/Button/Button.tsx similarity index 59% rename from src/Button/Button.js rename to src/Button/Button.tsx index d28153b9..84fb1df0 100644 --- a/src/Button/Button.js +++ b/src/Button/Button.tsx @@ -1,36 +1,61 @@ /* eslint-disable no-nested-ternary */ -import React from 'react'; -import propTypes from 'prop-types'; - +import React, { forwardRef } from 'react'; import styled, { css } from 'styled-components'; import { createBorderStyles, - createWellBorderStyles, createBoxStyles, - createFlatBoxStyles, createDisabledTextStyles, + createFlatBoxStyles, createHatchedBackground, + createWellBorderStyles, focusOutline } from '../common'; -import { noOp } from '../common/utils'; import { blockSizes } from '../common/system'; +import { noOp } from '../common/utils'; +import { CommonStyledProps, Sizes } from '../types'; -const commonButtonStyles = css` +type ButtonProps = { + active?: boolean; + children?: React.ReactNode; + disabled?: boolean; + fullWidth?: boolean; + onClick?: React.ButtonHTMLAttributes['onClick']; + onTouchStart?: React.ButtonHTMLAttributes['onTouchStart']; + primary?: boolean; + size?: Sizes; + square?: boolean; + type?: string; + variant?: 'default' | 'menu' | 'flat'; +} & React.ButtonHTMLAttributes & + CommonStyledProps; + +type StyledButtonProps = Pick< + ButtonProps, + | 'active' + | 'disabled' + | 'fullWidth' + | 'primary' + | 'size' + | 'square' + | 'variant' +>; + +const commonButtonStyles = css` position: relative; display: inline-flex; align-items: center; justify-content: center; - height: ${({ size }) => blockSizes[size]}; - width: ${({ fullWidth, square, size }) => + height: ${({ size = 'md' }) => blockSizes[size]}; + width: ${({ fullWidth, size = 'md', square }) => fullWidth ? '100%' : square ? blockSizes[size] : 'auto'}; padding: ${({ square }) => (square ? 0 : `0 10px`)}; font-size: 1rem; user-select: none; &:active { - padding-top: ${({ isDisabled }) => !isDisabled && '2px'}; + padding-top: ${({ disabled }) => !disabled && '2px'}; } - padding-top: ${({ active, isDisabled }) => active && !isDisabled && '2px'}; + padding-top: ${({ active, disabled }) => active && !disabled && '2px'}; &:after { content: ''; position: absolute; @@ -46,8 +71,8 @@ const commonButtonStyles = css` font-family: inherit; `; -export const StyledButton = styled.button` - ${({ variant, theme, active, isDisabled, primary }) => +export const StyledButton = styled.button` + ${({ active, disabled, primary, theme, variant }) => variant === 'flat' ? css` ${createFlatBoxStyles()} @@ -63,7 +88,7 @@ export const StyledButton = styled.button` outline-offset: -4px; `} &:focus:after, &:active:after { - ${!active && !isDisabled && focusOutline} + ${!active && !disabled && focusOutline} outline-offset: -4px; } ` @@ -73,18 +98,18 @@ export const StyledButton = styled.button` border: 2px solid transparent; &:hover, &:focus { - ${!isDisabled && !active && createWellBorderStyles(false)} + ${!disabled && !active && createWellBorderStyles(false)} } &:active { - ${!isDisabled && createWellBorderStyles(true)} + ${!disabled && createWellBorderStyles(true)} } ${active && createWellBorderStyles(true)} - ${isDisabled && createDisabledTextStyles()} + ${disabled && createDisabledTextStyles()} ` : css` ${createBoxStyles()}; border: none; - ${isDisabled && createDisabledTextStyles()} + ${disabled && createDisabledTextStyles()} ${active ? createHatchedBackground({ mainColor: theme.material, @@ -115,11 +140,11 @@ export const StyledButton = styled.button` : createBorderStyles({ invert: false })} } &:active:before { - ${!isDisabled && createBorderStyles({ invert: true })} + ${!disabled && createBorderStyles({ invert: true })} } &:focus:after, &:active:after { - ${!active && !isDisabled && focusOutline} + ${!active && !disabled && focusOutline} outline-offset: -8px; } &:active:focus:after, @@ -130,15 +155,36 @@ export const StyledButton = styled.button` ${commonButtonStyles} `; -const Button = React.forwardRef(function Button(props, ref) { - const { onClick, disabled, children, ...otherProps } = props; - +const Button = forwardRef(function Button( + { + onClick, + disabled = false, + children, + type = 'button', + fullWidth = false, + size = 'md', + square = false, + active = false, + onTouchStart = noOp, + primary = false, + variant = 'default', + ...otherProps + }, + ref +) { return ( {children} @@ -146,33 +192,4 @@ const Button = React.forwardRef(function Button(props, ref) { ); }); -Button.defaultProps = { - type: 'button', - onClick: null, - disabled: false, - fullWidth: false, - size: 'md', - square: false, - active: false, - // onTouchStart below to enable button :active style on iOS - onTouchStart: noOp, - primary: false, - variant: 'default' -}; - -Button.propTypes = { - type: propTypes.string, - onClick: propTypes.func, - disabled: propTypes.bool, - fullWidth: propTypes.bool, - size: propTypes.oneOf(['sm', 'md', 'lg']), - square: propTypes.bool, - active: propTypes.bool, - onTouchStart: propTypes.func, - primary: propTypes.bool, - variant: propTypes.oneOf(['default', 'menu', 'flat']), - // eslint-disable-next-line react/require-default-props - children: propTypes.node -}; - -export default Button; +export { Button, ButtonProps }; diff --git a/src/Checkbox/Checkbox.mdx b/src/Checkbox/Checkbox.mdx index af820a72..137aca20 100644 --- a/src/Checkbox/Checkbox.mdx +++ b/src/Checkbox/Checkbox.mdx @@ -5,7 +5,7 @@ menu: Components import { Checkbox } from './Checkbox'; import Fieldset from '../Fieldset/Fieldset'; -import Button from '../Button/Button'; +import { Button } from '../Button/Button'; import Cutout from '../Cutout/Cutout'; import List from '../List/List'; import ListItem from '../ListItem/ListItem'; diff --git a/src/DatePicker/DatePicker.js b/src/DatePicker/DatePicker.js index 3cb11fa7..b79c496f 100644 --- a/src/DatePicker/DatePicker.js +++ b/src/DatePicker/DatePicker.js @@ -9,7 +9,7 @@ import WindowContent from '../WindowContent/WindowContent'; import Select from '../Select/Select'; import NumberField from '../NumberField/NumberField'; import Cutout from '../Cutout/Cutout'; -import Button from '../Button/Button'; +import { Button } from '../Button/Button'; import Toolbar from '../Toolbar/Toolbar'; const Calendar = styled(Cutout)` diff --git a/src/NumberField/NumberField.js b/src/NumberField/NumberField.js index 140c7bbd..2f747a9a 100644 --- a/src/NumberField/NumberField.js +++ b/src/NumberField/NumberField.js @@ -5,7 +5,7 @@ import styled, { css } from 'styled-components'; import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled'; import { clamp } from '../common/utils'; -import Button from '../Button/Button'; +import { Button } from '../Button/Button'; import { blockSizes } from '../common/system'; import TextField from '../TextField/TextField'; diff --git a/src/Tooltip/Tooltip.mdx b/src/Tooltip/Tooltip.mdx index b809b0df..bb18dfc7 100644 --- a/src/Tooltip/Tooltip.mdx +++ b/src/Tooltip/Tooltip.mdx @@ -4,7 +4,7 @@ menu: Components --- import Tooltip from './Tooltip'; -import Button from '../Button/Button'; +import { Button } from '../Button/Button'; # Tooltip diff --git a/src/Tree/Tree.stories.js b/src/Tree/Tree.stories.js index 1ce132e0..32561e72 100644 --- a/src/Tree/Tree.stories.js +++ b/src/Tree/Tree.stories.js @@ -2,7 +2,7 @@ import React, { useState, useCallback } from 'react'; import styled from 'styled-components'; import { Tree, Fieldset } from 'react95'; -import Button from '../Button/Button'; +import { Button } from '../Button/Button'; const Wrapper = styled.div` background: ${({ theme }) => theme.material}; diff --git a/src/Window/Window.mdx b/src/Window/Window.mdx index fe9f650d..740f6e01 100644 --- a/src/Window/Window.mdx +++ b/src/Window/Window.mdx @@ -3,11 +3,11 @@ name: Window menu: Components --- -import Window from './Window' -import WindowContent from '../WindowContent/WindowContent' -import WindowHeader from '../WindowHeader/WindowHeader' -import Button from '../Button/Button' -import Toolbar from '../Toolbar/Toolbar' +import Window from './Window'; +import WindowContent from '../WindowContent/WindowContent'; +import WindowHeader from '../WindowHeader/WindowHeader'; +import { Button } from '../Button/Button'; +import Toolbar from '../Toolbar/Toolbar'; # Window diff --git a/src/index.ts b/src/index.ts index 097c044a..ee3a0431 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,7 @@ export * from './Anchor/Anchor'; export * from './AppBar/AppBar'; export * from './Avatar/Avatar'; export * from './Bar/Bar'; -export { default as Button } from './Button/Button'; +export * from './Button/Button'; export * from './Checkbox/Checkbox'; export { default as ColorInput } from './ColorInput/ColorInput'; export * from './Counter/Counter';