From b3127e26baa494a2cf0fbc00fe2ad05c3808cf4b Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 19:26:18 -0400 Subject: [PATCH 01/29] docs(anchor): categorize under Typography --- src/Anchor/Anchor.mdx | 28 ---------------------------- src/Anchor/Anchor.stories.tsx | 8 +++----- src/Anchor/Anchor.tsx | 31 ++++++++++++++++--------------- 3 files changed, 19 insertions(+), 48 deletions(-) delete mode 100644 src/Anchor/Anchor.mdx diff --git a/src/Anchor/Anchor.mdx b/src/Anchor/Anchor.mdx deleted file mode 100644 index 7c0c3409..00000000 --- a/src/Anchor/Anchor.mdx +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: Anchor -menu: Components ---- - -import Anchor from './Anchor'; - -# Anchor - -## Usage - - - - Expensive Toys - - - -## API - -### Props - - - -### Import - -``` -import { Anchor } from 'react95' -``` diff --git a/src/Anchor/Anchor.stories.tsx b/src/Anchor/Anchor.stories.tsx index f2fb21c7..7bb6c7c2 100644 --- a/src/Anchor/Anchor.stories.tsx +++ b/src/Anchor/Anchor.stories.tsx @@ -1,16 +1,15 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; +import { Anchor } from 'react95'; import styled from 'styled-components'; -import { Anchor } from './Anchor'; - const Wrapper = styled.div` padding: 5rem; background: ${({ theme }) => theme.material}; `; export default { - title: 'Anchor', + title: 'Typography/Anchor', component: Anchor, decorators: [story => {story()}] } as ComponentMeta; @@ -18,9 +17,8 @@ export default { export function Default() { return (

- Everybody likes + Everybody likes{' '} - {' '} https://expensive.toys

diff --git a/src/Anchor/Anchor.tsx b/src/Anchor/Anchor.tsx index 5e27e141..20170fea 100644 --- a/src/Anchor/Anchor.tsx +++ b/src/Anchor/Anchor.tsx @@ -3,7 +3,12 @@ import styled from 'styled-components'; import { CommonStyledProps } from '../types'; -const StyledAnchor = styled.a` +type AnchorProps = { + children: React.ReactNode; +} & React.AnchorHTMLAttributes & + CommonStyledProps; + +const StyledAnchor = styled.a<{ underline: boolean }>` color: ${({ theme }) => theme.anchor}; font-size: inherit; text-decoration: underline; @@ -12,20 +17,16 @@ const StyledAnchor = styled.a` } `; -type AnchorProps = { - children: React.ReactNode; -} & React.AnchorHTMLAttributes & - CommonStyledProps; +const Anchor = forwardRef( + ({ children, ...otherProps }: AnchorProps, ref) => { + return ( + + {children} + + ); + } +); -const Anchor = forwardRef(function Anchor( - { children, ...otherProps }: AnchorProps, - ref -) { - return ( - - {children} - - ); -}); +Anchor.displayName = 'Anchor'; export { Anchor, AnchorProps }; From c2fdbf1a187598d7a6acbc8938cc96467ab0eb93 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 20:12:26 -0400 Subject: [PATCH 02/29] chore(appbar): categorize under Environment --- src/AppBar/AppBar.mdx | 90 ----------------------------------- src/AppBar/AppBar.stories.tsx | 2 +- src/AppBar/AppBar.tsx | 24 +++++----- 3 files changed, 14 insertions(+), 102 deletions(-) delete mode 100644 src/AppBar/AppBar.mdx diff --git a/src/AppBar/AppBar.mdx b/src/AppBar/AppBar.mdx deleted file mode 100644 index 85a2325e..00000000 --- a/src/AppBar/AppBar.mdx +++ /dev/null @@ -1,90 +0,0 @@ ---- -name: AppBar -menu: Components ---- - -import { AppBar } from './AppBar'; -import { Toolbar } from '../Toolbar/Toolbar'; -import { Button } from '../Button/Button'; -import { TextField } from '../TextField/TextField'; -import List from '../List/List'; -import ListItem from '../ListItem/ListItem'; -import Divider from '../Divider/Divider'; - -# AppBar - -## Usage - -#### Default - - - {() => { - const [open, setOpen] = React.useState(false); - function handleClick() { - setOpen(!open); - } - function handleClose() { - setOpen(false); - } - const renderMenu = () => { - return ( -
- {open && ( - - - - 👨‍💻 - - Profile - - - - 📁 - - My account - - - - - 🔙 - - Logout - - - )} - -
- ); - }; - return ( - - - {renderMenu()} - - - - ); - }} -
- -## API - -### Import - -``` -import { AppBar } from 'react95' -``` - -### Props - - diff --git a/src/AppBar/AppBar.stories.tsx b/src/AppBar/AppBar.stories.tsx index bb12aa22..69b0e848 100644 --- a/src/AppBar/AppBar.stories.tsx +++ b/src/AppBar/AppBar.stories.tsx @@ -18,7 +18,7 @@ const Wrapper = styled.div` `; export default { - title: 'AppBar', + title: 'Environment/AppBar', component: AppBar, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/AppBar/AppBar.tsx b/src/AppBar/AppBar.tsx index 8fa4cca9..416ae5a2 100644 --- a/src/AppBar/AppBar.tsx +++ b/src/AppBar/AppBar.tsx @@ -1,7 +1,8 @@ import React, { forwardRef } from 'react'; import styled from 'styled-components'; -import { CommonStyledProps } from '../types'; + import { createBorderStyles, createBoxStyles } from '../common'; +import { CommonStyledProps } from '../types'; type AppBarProps = { children: React.ReactNode; @@ -22,15 +23,16 @@ const StyledAppBar = styled.header` width: 100%; `; -const AppBar = forwardRef(function AppBar( - { children, fixed = true, ...otherProps }, - ref -) { - return ( - - {children} - - ); -}); +const AppBar = forwardRef( + ({ children, fixed = true, ...otherProps }, ref) => { + return ( + + {children} + + ); + } +); + +AppBar.displayName = 'AppBar'; export { AppBar, AppBarProps }; From 4c8fc2cbf2ab5e32fd46fd936aae1ef170f870d9 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 20:14:28 -0400 Subject: [PATCH 03/29] docs(avatar): categorize under Other --- src/Avatar/Avatar.mdx | 50 -------------------------------- src/Avatar/Avatar.stories.tsx | 2 +- src/Avatar/Avatar.tsx | 54 +++++++++++++++++++---------------- 3 files changed, 30 insertions(+), 76 deletions(-) delete mode 100644 src/Avatar/Avatar.mdx diff --git a/src/Avatar/Avatar.mdx b/src/Avatar/Avatar.mdx deleted file mode 100644 index b2788b41..00000000 --- a/src/Avatar/Avatar.mdx +++ /dev/null @@ -1,50 +0,0 @@ ---- -name: Avatar -menu: Components ---- - -import { Avatar } from './Avatar'; - -# Avatar - -## Usage - -#### Default - - - - - -#### No border - - - - - -#### Lettered - - - AK - - -#### Squared - - - - - 🚀 - - - - -## API - -### Import - -``` -import { Avatar } from 'react95' -``` - -### Props - - diff --git a/src/Avatar/Avatar.stories.tsx b/src/Avatar/Avatar.stories.tsx index f1cdd4e3..55bb1f00 100644 --- a/src/Avatar/Avatar.stories.tsx +++ b/src/Avatar/Avatar.stories.tsx @@ -12,7 +12,7 @@ const Wrapper = styled.div` `; export default { - title: 'Avatar', + title: 'Other/Avatar', component: Avatar, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/Avatar/Avatar.tsx b/src/Avatar/Avatar.tsx index 62f3b791..89990fd4 100644 --- a/src/Avatar/Avatar.tsx +++ b/src/Avatar/Avatar.tsx @@ -53,30 +53,34 @@ const StyledAvatarImg = styled.img` height: 100%; `; -const Avatar = forwardRef(function Avatar( - { - alt = '', - children, - noBorder = false, - size = 35, - square = false, - src, - ...otherProps - }, - ref -) { - return ( - - {src ? : children} - - ); -}); +const Avatar = forwardRef( + ( + { + alt = '', + children, + noBorder = false, + size = 35, + square = false, + src, + ...otherProps + }, + ref + ) => { + return ( + + {src ? : children} + + ); + } +); + +Avatar.displayName = 'Avatar'; export { Avatar, AvatarProps }; From c6028f1adf8a9bcb859998c0e6e70a44ab8900e0 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 20:23:27 -0400 Subject: [PATCH 04/29] refactor(handle): categorize under Controls, rename Bar to Handle --- src/Bar/Bar.mdx | 34 ------------------- .../Bar.spec.tsx => Handle/Handle.spec.tsx} | 14 ++++---- .../Handle.stories.tsx} | 12 +++---- src/{Bar/Bar.tsx => Handle/Handle.tsx} | 8 +++-- src/List/List.stories.tsx | 4 +-- src/index.ts | 5 ++- src/legacy/Bar.tsx | 7 ++++ 7 files changed, 31 insertions(+), 53 deletions(-) delete mode 100644 src/Bar/Bar.mdx rename src/{Bar/Bar.spec.tsx => Handle/Handle.spec.tsx} (71%) rename src/{Bar/Bar.stories.tsx => Handle/Handle.stories.tsx} (73%) rename src/{Bar/Bar.tsx => Handle/Handle.tsx} (85%) create mode 100644 src/legacy/Bar.tsx diff --git a/src/Bar/Bar.mdx b/src/Bar/Bar.mdx deleted file mode 100644 index d0f2f026..00000000 --- a/src/Bar/Bar.mdx +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: Bar -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'; - -# Bar - -## Usage - - - - - - - - - - - - -## API - -### Import - -### Props - - diff --git a/src/Bar/Bar.spec.tsx b/src/Handle/Handle.spec.tsx similarity index 71% rename from src/Bar/Bar.spec.tsx rename to src/Handle/Handle.spec.tsx index de79c49c..4455413b 100644 --- a/src/Bar/Bar.spec.tsx +++ b/src/Handle/Handle.spec.tsx @@ -2,11 +2,11 @@ import React from 'react'; import { renderWithTheme } from '../../test/utils'; -import { Bar } from './Bar'; +import { Handle } from './Handle'; -describe('', () => { +describe('', () => { it('should render bar', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const barEl = container.firstChild; expect(barEl).toBeInTheDocument(); @@ -14,7 +14,7 @@ describe('', () => { it('should handle custom style', () => { const { container } = renderWithTheme( - + ); const barEl = container.firstChild; @@ -23,7 +23,7 @@ describe('', () => { it('should handle custom props', () => { const customProps = { title: 'potatoe' }; - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const barEl = container.firstChild; expect(barEl).toHaveAttribute('title', 'potatoe'); @@ -31,14 +31,14 @@ describe('', () => { describe('prop: size', () => { it('should set proper size', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const barEl = container.firstChild; expect(barEl).toHaveStyleRule('height', '85%'); }); it('when passed a number, sets size in px', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const barEl = container.firstChild; expect(barEl).toHaveStyleRule('height', '25px'); diff --git a/src/Bar/Bar.stories.tsx b/src/Handle/Handle.stories.tsx similarity index 73% rename from src/Bar/Bar.stories.tsx rename to src/Handle/Handle.stories.tsx index 2e018b0b..a6a9fe04 100644 --- a/src/Bar/Bar.stories.tsx +++ b/src/Handle/Handle.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { AppBar, Bar, Button, Toolbar } from 'react95'; +import { AppBar, Button, Handle, Toolbar } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -9,21 +9,21 @@ const Wrapper = styled.div` `; export default { - title: 'Bar', - component: Bar, + title: 'Controls/Handle', + component: Handle, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { return ( - + - + ); diff --git a/src/Bar/Bar.tsx b/src/Handle/Handle.tsx similarity index 85% rename from src/Bar/Bar.tsx rename to src/Handle/Handle.tsx index 1adb0c32..fc8fd851 100644 --- a/src/Bar/Bar.tsx +++ b/src/Handle/Handle.tsx @@ -3,14 +3,14 @@ import styled from 'styled-components'; import { CommonStyledProps } from '../types'; import { getSize } from '../common/utils'; -type BarProps = { +type HandleProps = { size?: string | number; } & React.HTMLAttributes & CommonStyledProps; // TODO: add horizontal variant // TODO: allow user to specify number of bars (like 3 horizontal bars for drag handle) -const Bar = styled.div` +const Handle = styled.div` ${({ theme, size = '100%' }) => ` display: inline-block; box-sizing: border-box; @@ -24,4 +24,6 @@ const Bar = styled.div` `} `; -export { Bar, BarProps }; +Handle.displayName = 'Handle'; + +export { Handle, HandleProps }; diff --git a/src/List/List.stories.tsx b/src/List/List.stories.tsx index b365fcb6..bfd0d34c 100644 --- a/src/List/List.stories.tsx +++ b/src/List/List.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; import styled from 'styled-components'; -import { Bar, Divider, List, ListItem } from 'react95'; +import { Divider, List, ListItem, Handle } from 'react95'; const Wrapper = styled.div` padding: 5rem; @@ -44,7 +44,7 @@ export function Default() { 🌿 - + Tackle Growl Razor Leaf diff --git a/src/index.ts b/src/index.ts index 54e30e3c..a3908d89 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,6 @@ export { createScrollbars } from './common/index'; export * from './Anchor/Anchor'; export * from './AppBar/AppBar'; export * from './Avatar/Avatar'; -export * from './Bar/Bar'; export * from './Button/Button'; export * from './Checkbox/Checkbox'; export * from './ColorInput/ColorInput'; @@ -16,6 +15,7 @@ export * from './DatePicker/DatePicker'; export * from './Desktop/Desktop'; export * from './Divider/Divider'; export * from './Fieldset/Fieldset'; +export * from './Handle/Handle'; export * from './Hourglass/Hourglass'; export * from './List/List'; export * from './ListItem/ListItem'; @@ -42,3 +42,6 @@ export * from './Tree/Tree'; export * from './Window/Window'; export * from './WindowContent/WindowContent'; export * from './WindowHeader/WindowHeader'; + +/* deprecated components */ +export * from './legacy/Bar'; diff --git a/src/legacy/Bar.tsx b/src/legacy/Bar.tsx new file mode 100644 index 00000000..98562f2a --- /dev/null +++ b/src/legacy/Bar.tsx @@ -0,0 +1,7 @@ +import { Handle, HandleProps } from '../Handle/Handle'; + +/** @deprecated Use `HandleProps` */ +export type BarProps = HandleProps; + +/** @deprecated Use `Handle` */ +export const Bar = Handle; From 43fdc928f63881bfce46b1a5cf16d7c3489b9136 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 20:39:40 -0400 Subject: [PATCH 05/29] docs(button): categorize under Controls This also renames the menu variant to thin. --- src/Button/Button.mdx | 110 ---------------------------------- src/Button/Button.spec.tsx | 4 ++ src/Button/Button.stories.tsx | 86 +++++++++++++------------- src/Button/Button.tsx | 97 +++++++++++++++++------------- 4 files changed, 102 insertions(+), 195 deletions(-) delete mode 100644 src/Button/Button.mdx diff --git a/src/Button/Button.mdx b/src/Button/Button.mdx deleted file mode 100644 index ba6c19a2..00000000 --- a/src/Button/Button.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -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'; - -# Button - -## Usage - -#### Default - - - - - -#### Disabled - - - - - -#### Full Width - - - - - -#### Square - - - - - -#### Active - - - - - -#### Different sizes - - -
- - - -
-
- -#### Flat - - - - - -

- When you want to use Buttons on a light background (like scrollable - content), just use the flat variant: -

-
- - - - - -
-
-
-
-
- -## API - -### Import - -``` -import { Button } from 'react95' -``` - -### Props - - diff --git a/src/Button/Button.spec.tsx b/src/Button/Button.spec.tsx index a0f496f3..a980b3c1 100644 --- a/src/Button/Button.spec.tsx +++ b/src/Button/Button.spec.tsx @@ -55,6 +55,10 @@ describe(' + + + + + + + + ); +} + +Flat.story = { + name: 'flat' +}; + 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() { +export function Thin() { const [open, setOpen] = useState(false); return ( @@ -77,10 +113,10 @@ export function Menu() { Kiwi.app - -
- - - -
- - - - ); -} - -Flat.story = { - name: 'flat' +Thin.story = { + name: 'thin' }; diff --git a/src/Button/Button.tsx b/src/Button/Button.tsx index e74a2547..df0a9186 100644 --- a/src/Button/Button.tsx +++ b/src/Button/Button.tsx @@ -24,11 +24,19 @@ type ButtonProps = { size?: Sizes; square?: boolean; type?: string; - variant?: 'default' | 'menu' | 'flat'; -} & Omit< - React.ButtonHTMLAttributes, - 'disabled' | 'onClick' | 'onTouchStart' | 'type' -> & +} & ( + | { + variant?: 'default' | 'flat' | 'thin'; + } + | { + /** @deprecated Use `thin` */ + variant?: 'menu'; + } +) & + Omit< + React.ButtonHTMLAttributes, + 'disabled' | 'onClick' | 'onTouchStart' | 'type' + > & CommonStyledProps; type StyledButtonProps = Pick< @@ -93,7 +101,7 @@ export const StyledButton = styled.button` outline-offset: -4px; } ` - : variant === 'menu' + : variant === 'menu' || variant === 'thin' ? css` ${createBoxStyles()}; border: 2px solid transparent; @@ -156,41 +164,46 @@ export const StyledButton = styled.button` ${commonButtonStyles} `; -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} - - ); -}); +const Button = forwardRef( + ( + { + onClick, + disabled = false, + children, + type = 'button', + fullWidth = false, + size = 'md', + square = false, + active = false, + onTouchStart = noOp, + primary = false, + variant = 'default', + ...otherProps + }, + ref + ) => { + return ( + + {children} + + ); + } +); + +Button.displayName = 'Button'; export { Button, ButtonProps }; From fb0007b2d22772e69c4383cd1271a2942c2a95e9 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 20:42:21 -0400 Subject: [PATCH 06/29] docs(checkbox): categorize under Controls --- src/Checkbox/Checkbox.mdx | 180 ------------------------------ src/Checkbox/Checkbox.stories.tsx | 2 +- src/Checkbox/Checkbox.tsx | 112 ++++++++++--------- 3 files changed, 59 insertions(+), 235 deletions(-) delete mode 100644 src/Checkbox/Checkbox.mdx diff --git a/src/Checkbox/Checkbox.mdx b/src/Checkbox/Checkbox.mdx deleted file mode 100644 index 7c84413f..00000000 --- a/src/Checkbox/Checkbox.mdx +++ /dev/null @@ -1,180 +0,0 @@ ---- -name: Checkbox -menu: Components ---- - -import { Checkbox } from './Checkbox'; -import Fieldset from '../Fieldset/Fieldset'; -import { Button } from '../Button/Button'; -import { Cutout } from '../Cutout/Cutout'; -import List from '../List/List'; -import ListItem from '../ListItem/ListItem'; -import Divider from '../Divider/Divider'; - -# Checkbox - -## Usage - -#### Controlled group - - - {() => { - const [steak, setSteak] = React.useState(true); - const [tortilla, setTortilla] = React.useState(false); - const [pizza, setPizza] = React.useState(false); - const handleChange = event => { - const { - target: { value } - } = event; - if (value === 'steak') { - setSteak(!steak); - return; - } - if (value === 'tortilla') { - setTortilla(!tortilla); - return; - } - if (value === 'pizza') { - setPizza(!pizza); - return; - } - }; - const reset = () => { - setSteak(false); - setTortilla(false); - setPizza(false); - }; - return ( -
-
- -
- -
- -
- -
- ); - }} -
- -#### Uncontrolled - - - <> - -
- - -
- -#### Flat - - - -

- When you want to add input field on a light background (like scrollable - content), just use the flat variant: -

-
- - - -
-
-
- -#### Menu - - - - - - - - - - - - - - - - -## API - -### Import - -``` -import { Checkbox } from 'react95' -``` - -### Props - - diff --git a/src/Checkbox/Checkbox.stories.tsx b/src/Checkbox/Checkbox.stories.tsx index cfee5b07..437a71ff 100644 --- a/src/Checkbox/Checkbox.stories.tsx +++ b/src/Checkbox/Checkbox.stories.tsx @@ -19,7 +19,7 @@ const Wrapper = styled.div` `; export default { - title: 'Checkbox', + title: 'Controls/Checkbox', component: Checkbox, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/Checkbox/Checkbox.tsx b/src/Checkbox/Checkbox.tsx index 777d10d0..3047d233 100644 --- a/src/Checkbox/Checkbox.tsx +++ b/src/Checkbox/Checkbox.tsx @@ -189,64 +189,68 @@ const CheckboxComponents = { menu: StyledMenuCheckbox }; -const Checkbox = forwardRef(function Checkbox( - { - checked, - className = '', - defaultChecked = false, - disabled = false, - indeterminate = false, - label = '', - onChange = noOp, - style = {}, - value, - variant = 'default', - ...otherProps - }, - ref -) { - const [state, setState] = useControlledOrUncontrolled({ - value: checked, - defaultValue: defaultChecked - }); - - const handleChange = useCallback( - (e: React.ChangeEvent) => { - const newState = e.target.checked; - setState(newState); - onChange(e); +const Checkbox = forwardRef( + ( + { + checked, + className = '', + defaultChecked = false, + disabled = false, + indeterminate = false, + label = '', + onChange = noOp, + style = {}, + value, + variant = 'default', + ...otherProps }, - [onChange, setState] - ); + ref + ) => { + const [state, setState] = useControlledOrUncontrolled({ + value: checked, + defaultValue: defaultChecked + }); - const CheckboxComponent = CheckboxComponents[variant]; + const handleChange = useCallback( + (e: React.ChangeEvent) => { + const newState = e.target.checked; + setState(newState); + onChange(e); + }, + [onChange, setState] + ); - let Icon = null; - if (indeterminate) { - Icon = IndeterminateIcon; - } else if (state) { - Icon = CheckmarkIcon; + const CheckboxComponent = CheckboxComponents[variant]; + + let Icon = null; + if (indeterminate) { + Icon = IndeterminateIcon; + } else if (state) { + Icon = CheckmarkIcon; + } + + return ( + + + + {Icon && } + + {label && {label}} + + ); } +); - return ( - - - - {Icon && } - - {label && {label}} - - ); -}); +Checkbox.displayName = 'Checkbox'; export { Checkbox, CheckboxProps }; From 0b492f4957756e1b6e62ee8dbc94b08cb819db73 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 20:46:47 -0400 Subject: [PATCH 07/29] docs(colorinput): categorize under Controls --- src/ColorInput/ColorInput.stories.tsx | 2 +- src/ColorInput/ColorInput.tsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ColorInput/ColorInput.stories.tsx b/src/ColorInput/ColorInput.stories.tsx index 93ce49dd..5dc9aab8 100644 --- a/src/ColorInput/ColorInput.stories.tsx +++ b/src/ColorInput/ColorInput.stories.tsx @@ -28,7 +28,7 @@ const Wrapper = styled.div` `; export default { - title: 'ColorInput', + title: 'Controls/ColorInput', component: ColorInput, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/ColorInput/ColorInput.tsx b/src/ColorInput/ColorInput.tsx index bd98b407..c7234406 100644 --- a/src/ColorInput/ColorInput.tsx +++ b/src/ColorInput/ColorInput.tsx @@ -116,7 +116,7 @@ const ChevronIcon = styled.span< // TODO make sure all aria and role attributes are in place const ColorInput = forwardRef( - function ColorInput( + ( { value, defaultValue, @@ -126,7 +126,7 @@ const ColorInput = forwardRef( ...otherProps }, ref - ) { + ) => { const [valueDerived, setValueState] = useControlledOrUncontrolled({ value, defaultValue @@ -163,4 +163,6 @@ const ColorInput = forwardRef( } ); +ColorInput.displayName = 'ColorInput'; + export { ColorInput, ColorInputProps }; From 598ef728e4bccd34e8ecac8f72af3b2e4725ab9c Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 20:48:45 -0400 Subject: [PATCH 08/29] docs(counter): categorize under Other --- src/Counter/Counter.mdx | 22 ---------------------- src/Counter/Counter.stories.tsx | 2 +- src/Counter/Counter.tsx | 33 +++++++++++++++++---------------- 3 files changed, 18 insertions(+), 39 deletions(-) delete mode 100644 src/Counter/Counter.mdx diff --git a/src/Counter/Counter.mdx b/src/Counter/Counter.mdx deleted file mode 100644 index 0d8428b2..00000000 --- a/src/Counter/Counter.mdx +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Bar -menu: Components ---- - -import { Counter } from '../Counter/Counter'; - -# Counter - -## Usage - - - - - -## API - -### Import - -### Props - - diff --git a/src/Counter/Counter.stories.tsx b/src/Counter/Counter.stories.tsx index 63ed01dc..7890db93 100644 --- a/src/Counter/Counter.stories.tsx +++ b/src/Counter/Counter.stories.tsx @@ -20,7 +20,7 @@ const Wrapper = styled.div` `; export default { - title: 'Counter', + title: 'Other/Counter', component: Counter, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/Counter/Counter.tsx b/src/Counter/Counter.tsx index 9e468b2f..55dfec81 100644 --- a/src/Counter/Counter.tsx +++ b/src/Counter/Counter.tsx @@ -25,21 +25,22 @@ const pixelSizes = { xl: 4 }; -const Counter = forwardRef(function Counter( - { value = 0, minLength = 3, size = 'md', ...otherProps }, - ref -) { - const digits = useMemo( - () => value.toString().padStart(minLength, '0').split(''), - [minLength, value] - ); - return ( - - {digits.map((digit, i) => ( - - ))} - - ); -}); +const Counter = forwardRef( + ({ value = 0, minLength = 3, size = 'md', ...otherProps }, ref) => { + const digits = useMemo( + () => value.toString().padStart(minLength, '0').split(''), + [minLength, value] + ); + return ( + + {digits.map((digit, i) => ( + + ))} + + ); + } +); + +Counter.displayName = 'Counter'; export { Counter, CounterProps }; From 34902800fc3c3b11f69b6b8ba7d57917d5056151 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 21:14:25 -0400 Subject: [PATCH 09/29] refactor(separator): categorize under Layout, rename Divider to Separator --- README.md | 4 +- docs/Getting-Started.stories.mdx | 4 +- src/AppBar/AppBar.stories.tsx | 4 +- src/Button/Button.stories.tsx | 6 +- src/Checkbox/Checkbox.stories.tsx | 4 +- src/ColorInput/ColorInput.tsx | 6 +- src/Divider/Divider.mdx | 47 ------------ src/Divider/Divider.spec.tsx | 73 ------------------ src/List/List.stories.tsx | 6 +- src/Radio/Radio.stories.tsx | 4 +- src/Separator/Separator.spec.tsx | 74 +++++++++++++++++++ .../Separator.stories.tsx} | 16 ++-- .../Divider.tsx => Separator/Separator.tsx} | 9 ++- src/index.ts | 3 +- src/legacy/Divider.tsx | 7 ++ 15 files changed, 116 insertions(+), 151 deletions(-) delete mode 100644 src/Divider/Divider.mdx delete mode 100644 src/Divider/Divider.spec.tsx create mode 100644 src/Separator/Separator.spec.tsx rename src/{Divider/Divider.stories.tsx => Separator/Separator.stories.tsx} (69%) rename src/{Divider/Divider.tsx => Separator/Separator.tsx} (80%) create mode 100644 src/legacy/Divider.tsx diff --git a/README.md b/README.md index 68fdc7d2..18821cb9 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Apply style reset, wrap your app with ThemeProvider with theme of your choice... import React from 'react'; import { createGlobalStyle, ThemeProvider } from 'styled-components'; -import { Divider, List, ListItem, styleReset } from 'react95'; +import { List, ListItem, Separator, styleReset } from 'react95'; // pick a theme of your choice import original from 'react95/dist/themes/original'; // original Windows95 font (optionally) @@ -75,7 +75,7 @@ const App = () => ( 🎤 Sing 💃🏻 Dance - + 😴 Sleep diff --git a/docs/Getting-Started.stories.mdx b/docs/Getting-Started.stories.mdx index 71947108..bc243bd1 100644 --- a/docs/Getting-Started.stories.mdx +++ b/docs/Getting-Started.stories.mdx @@ -29,7 +29,7 @@ choice... and you are ready to go! 🚀 ```jsx import React from 'react'; -import { Divider, List, ListItem, styleReset } from 'react95'; +import { List, ListItem, Separator, styleReset } from 'react95'; import { createGlobalStyle, ThemeProvider } from 'styled-components'; /* Pick a theme of your choice */ @@ -65,7 +65,7 @@ const App = () => ( 🎤 Sing 💃🏻 Dance - + 😴 Sleep diff --git a/src/AppBar/AppBar.stories.tsx b/src/AppBar/AppBar.stories.tsx index 69b0e848..ecc73757 100644 --- a/src/AppBar/AppBar.stories.tsx +++ b/src/AppBar/AppBar.stories.tsx @@ -3,9 +3,9 @@ import React, { useState } from 'react'; import { AppBar, Button, - Divider, List, ListItem, + Separator, TextField, Toolbar } from 'react95'; @@ -63,7 +63,7 @@ export function Default() { My account - + 🔙 diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx index f28c609c..66cd9880 100644 --- a/src/Button/Button.stories.tsx +++ b/src/Button/Button.stories.tsx @@ -3,9 +3,9 @@ import React, { useState } from 'react'; import { Button, Cutout, - Divider, List, ListItem, + Separator, Toolbar, Window, WindowContent, @@ -145,11 +145,11 @@ export function Thin() { onClick={() => setOpen(false)} > Copy link - + Facebook Twitter Instagram - + MySpace diff --git a/src/Checkbox/Checkbox.stories.tsx b/src/Checkbox/Checkbox.stories.tsx index 437a71ff..2d7d92ae 100644 --- a/src/Checkbox/Checkbox.stories.tsx +++ b/src/Checkbox/Checkbox.stories.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import styled from 'styled-components'; -import { Checkbox, Fieldset, Cutout, List, ListItem, Divider } from 'react95'; +import { Checkbox, Fieldset, Cutout, List, ListItem, Separator } from 'react95'; import { ComponentMeta } from '@storybook/react'; const Wrapper = styled.div` @@ -253,7 +253,7 @@ export function Menu() { indeterminate /> - + ( color={valueDerived ?? '#008080'} role='presentation' /> - {variant === 'default' && } + {variant === 'default' && } ); diff --git a/src/Divider/Divider.mdx b/src/Divider/Divider.mdx deleted file mode 100644 index d3c29adb..00000000 --- a/src/Divider/Divider.mdx +++ /dev/null @@ -1,47 +0,0 @@ ---- - -name: Divider -menu: Components -import { Divider } from './Divider' -import List from '../List/List' -import ListItem from '../ListItem/ListItem' - -# Divider - -## Usage - -#### Default - - - - Item 1 - - Item 2 - - Item 3 - - - -#### vertical - - - - Item 1 - - Item 2 - - Item 3 - - - -## API - -### Import - -``` -import { Divider } from 'react95' -``` - -### Props - - diff --git a/src/Divider/Divider.spec.tsx b/src/Divider/Divider.spec.tsx deleted file mode 100644 index 7054c79e..00000000 --- a/src/Divider/Divider.spec.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; - -import { renderWithTheme } from '../../test/utils'; - -import { Divider } from './Divider'; - -describe('', () => { - it('should render Divider', () => { - const { container } = renderWithTheme(); - const divider = container.firstElementChild; - - expect(divider).toBeInTheDocument(); - }); - - describe('prop: size', () => { - it('defaults to 100%', () => { - const { container } = renderWithTheme(); - const divider = container.firstElementChild; - expect(divider).toHaveStyleRule('width', '100%'); - }); - it('sets size passed correctly', () => { - const size = '53px'; - const { container } = renderWithTheme(); - const divider = container.firstElementChild; - - expect(divider).toHaveStyleRule('width', size); - }); - }); - - describe('prop: orientation', () => { - it('renders horizontal line by default', () => { - const size = '53px'; - const { container } = renderWithTheme(); - const divider = container.firstElementChild; - - expect(divider).toHaveStyleRule('width', size); - }); - - it('renders vertical line when orientation="vertical"', () => { - const size = '53px'; - const { container } = renderWithTheme( - - ); - const divider = container.firstElementChild; - - expect(divider).toHaveStyleRule('height', size); - }); - }); - describe('prop: size', () => { - it('should set proper size', () => { - const { container } = renderWithTheme(); - const avatarEl = container.firstElementChild; - - expect(avatarEl).toHaveStyleRule('width', '85%'); - }); - - it('when passed a number, sets size in px', () => { - const { container } = renderWithTheme(); - const avatarEl = container.firstElementChild; - - expect(avatarEl).toHaveStyleRule('width', '25px'); - }); - - it('should set height when vertical', () => { - const { container } = renderWithTheme( - - ); - const avatarEl = container.firstElementChild; - - expect(avatarEl).toHaveStyleRule('height', '25px'); - }); - }); -}); diff --git a/src/List/List.stories.tsx b/src/List/List.stories.tsx index bfd0d34c..0bd48e94 100644 --- a/src/List/List.stories.tsx +++ b/src/List/List.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; import styled from 'styled-components'; -import { Divider, List, ListItem, Handle } from 'react95'; +import { Handle, List, ListItem, Separator } from 'react95'; const Wrapper = styled.div` padding: 5rem; @@ -53,11 +53,11 @@ export function Default() { View - + Paste Paste Shortcut Undo Copy - + Properties diff --git a/src/Radio/Radio.stories.tsx b/src/Radio/Radio.stories.tsx index 0abd89ae..a48ac2ef 100644 --- a/src/Radio/Radio.stories.tsx +++ b/src/Radio/Radio.stories.tsx @@ -2,11 +2,11 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; import { Cutout, - Divider, Fieldset, List, ListItem, Radio, + Separator, Window, WindowContent } from 'react95'; @@ -178,7 +178,7 @@ export function Menu() { name='tool' /> - + ', () => { + it('should render Separator', () => { + const { container } = renderWithTheme(); + const separator = container.firstElementChild; + + expect(separator).toBeInTheDocument(); + }); + + describe('prop: size', () => { + it('defaults to 100%', () => { + const { container } = renderWithTheme(); + const separator = container.firstElementChild; + expect(separator).toHaveStyleRule('width', '100%'); + }); + it('sets size passed correctly', () => { + const size = '53px'; + const { container } = renderWithTheme(); + const separator = container.firstElementChild; + + expect(separator).toHaveStyleRule('width', size); + }); + }); + + describe('prop: orientation', () => { + it('renders horizontal line by default', () => { + const size = '53px'; + const { container } = renderWithTheme(); + const separator = container.firstElementChild; + + expect(separator).toHaveStyleRule('width', size); + }); + + it('renders vertical line when orientation="vertical"', () => { + const size = '53px'; + const { container } = renderWithTheme( + + ); + const separator = container.firstElementChild; + + expect(separator).toHaveStyleRule('height', size); + }); + }); + + describe('prop: size', () => { + it('should set proper size', () => { + const { container } = renderWithTheme(); + const separator = container.firstElementChild; + + expect(separator).toHaveStyleRule('width', '85%'); + }); + + it('when passed a number, sets size in px', () => { + const { container } = renderWithTheme(); + const separator = container.firstElementChild; + + expect(separator).toHaveStyleRule('width', '25px'); + }); + + it('should set height when vertical', () => { + const { container } = renderWithTheme( + + ); + const separator = container.firstElementChild; + + expect(separator).toHaveStyleRule('height', '25px'); + }); + }); +}); diff --git a/src/Divider/Divider.stories.tsx b/src/Separator/Separator.stories.tsx similarity index 69% rename from src/Divider/Divider.stories.tsx rename to src/Separator/Separator.stories.tsx index 4f697e29..bb3178b2 100644 --- a/src/Divider/Divider.stories.tsx +++ b/src/Separator/Separator.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; import styled from 'styled-components'; -import { Divider, List, ListItem } from 'react95'; +import { Separator, List, ListItem } from 'react95'; const Wrapper = styled.div` padding: 5rem; @@ -10,26 +10,26 @@ const Wrapper = styled.div` `; export default { - title: 'Divider', - component: Divider, + title: 'Layout/Separator', + component: Separator, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { return ( <> Item 1 - + Item 2 - + Item 3 Item 1 - + Item 2 - + Item 3 diff --git a/src/Divider/Divider.tsx b/src/Separator/Separator.tsx similarity index 80% rename from src/Divider/Divider.tsx rename to src/Separator/Separator.tsx index 788a8213..1956a098 100644 --- a/src/Divider/Divider.tsx +++ b/src/Separator/Separator.tsx @@ -2,11 +2,12 @@ import styled from 'styled-components'; import { getSize } from '../common/utils'; import { Orientation } from '../types'; -type DividerProps = { +type SeparatorProps = { size?: string | number; orientation?: Orientation; }; -const Divider = styled.div` + +const Separator = styled.div` ${({ orientation, theme, size = '100%' }) => orientation === 'vertical' ? ` @@ -23,4 +24,6 @@ const Divider = styled.div` `} `; -export { Divider, DividerProps }; +Separator.displayName = 'Separator'; + +export { Separator, SeparatorProps }; diff --git a/src/index.ts b/src/index.ts index a3908d89..61da4ffb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,7 +13,6 @@ export * from './Counter/Counter'; export * from './Cutout/Cutout'; export * from './DatePicker/DatePicker'; export * from './Desktop/Desktop'; -export * from './Divider/Divider'; export * from './Fieldset/Fieldset'; export * from './Handle/Handle'; export * from './Hourglass/Hourglass'; @@ -25,6 +24,7 @@ export * from './Panel/Panel'; export * from './Progress/Progress'; export * from './Radio/Radio'; export * from './Select/Select'; +export * from './Separator/Separator'; export * from './Slider/Slider'; export * from './Tab/Tab'; export * from './TabBody/TabBody'; @@ -45,3 +45,4 @@ export * from './WindowHeader/WindowHeader'; /* deprecated components */ export * from './legacy/Bar'; +export * from './legacy/Separator'; diff --git a/src/legacy/Divider.tsx b/src/legacy/Divider.tsx new file mode 100644 index 00000000..d883663a --- /dev/null +++ b/src/legacy/Divider.tsx @@ -0,0 +1,7 @@ +import { Separator, SeparatorProps } from '../Separator/Separator'; + +/** @deprecated Use `SeparatorProps` */ +export type DividerProps = SeparatorProps; + +/** @deprecated Use `Separator` */ +export const Divider = Separator; From f8b0b08ba895b0ec91b6a21396edf11f949f957d Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sat, 30 Jul 2022 21:05:33 -0400 Subject: [PATCH 10/29] refactor(scrollview): categorize under Layout, rename Cutout to ScrollView --- src/Button/Button.stories.tsx | 10 ++--- src/Checkbox/Checkbox.stories.tsx | 13 ++++-- src/Checkbox/Checkbox.tsx | 4 +- src/ColorInput/ColorInput.stories.tsx | 6 +-- src/Cutout/Cutout.mdx | 43 ------------------ src/Cutout/Cutout.spec.tsx | 41 ----------------- src/DatePicker/DatePicker.tsx | 4 +- src/Desktop/Desktop.tsx | 4 +- src/Fieldset/Fieldset.stories.tsx | 6 +-- src/LoadingIndicator/LoadingIndicator.tsx | 4 +- src/NumberField/NumberField.mdx | 6 +-- src/NumberField/NumberField.stories.tsx | 6 +-- src/Progress/Progress.tsx | 4 +- src/Radio/Radio.stories.tsx | 6 +-- src/Radio/Radio.tsx | 4 +- src/ScrollView/ScrollView.spec.tsx | 44 +++++++++++++++++++ .../ScrollView.stories.tsx} | 12 ++--- .../Cutout.tsx => ScrollView/ScrollView.tsx} | 27 ++++++------ src/Select/Select.mdx | 10 ++--- src/Select/Select.stories.tsx | 6 +-- src/Select/Select.styles.tsx | 6 ++- src/Slider/Slider.stories.tsx | 6 +-- src/Slider/Slider.tsx | 6 +-- src/Table/Table.tsx | 4 +- src/TextField/TextField.mdx | 10 ++--- src/TextField/TextField.stories.tsx | 6 +-- src/TextField/TextField.tsx | 4 +- src/index.ts | 5 ++- src/legacy/Cutout.tsx | 7 +++ 29 files changed, 146 insertions(+), 168 deletions(-) delete mode 100644 src/Cutout/Cutout.mdx delete mode 100644 src/Cutout/Cutout.spec.tsx create mode 100644 src/ScrollView/ScrollView.spec.tsx rename src/{Cutout/Cutout.stories.tsx => ScrollView/ScrollView.stories.tsx} (82%) rename src/{Cutout/Cutout.tsx => ScrollView/ScrollView.tsx} (74%) create mode 100644 src/legacy/Cutout.tsx diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx index 66cd9880..8d299d79 100644 --- a/src/Button/Button.stories.tsx +++ b/src/Button/Button.stories.tsx @@ -2,9 +2,9 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; import { Button, - Cutout, List, ListItem, + ScrollView, Separator, Toolbar, Window, @@ -67,7 +67,7 @@ export function Flat() { return ( - +

When you want to use Buttons on a light background (like scrollable content), just use the flat variant: @@ -89,7 +89,7 @@ export function Flat() { - + ); @@ -158,13 +158,13 @@ export function Thin() { - + kiwi - + ); diff --git a/src/Checkbox/Checkbox.stories.tsx b/src/Checkbox/Checkbox.stories.tsx index 2d7d92ae..a594fba5 100644 --- a/src/Checkbox/Checkbox.stories.tsx +++ b/src/Checkbox/Checkbox.stories.tsx @@ -1,8 +1,15 @@ import React, { useState } from 'react'; import styled from 'styled-components'; -import { Checkbox, Fieldset, Cutout, List, ListItem, Separator } from 'react95'; import { ComponentMeta } from '@storybook/react'; +import { + Checkbox, + Fieldset, + List, + ListItem, + ScrollView, + Separator +} from 'react95'; const Wrapper = styled.div` background: ${({ theme }) => theme.material}; @@ -170,7 +177,7 @@ export function Flat() { }; return ( - +

-
+ ); } diff --git a/src/Checkbox/Checkbox.tsx b/src/Checkbox/Checkbox.tsx index 3047d233..0fd52f9f 100644 --- a/src/Checkbox/Checkbox.tsx +++ b/src/Checkbox/Checkbox.tsx @@ -4,7 +4,7 @@ import styled, { css } from 'styled-components'; import { createHatchedBackground } from '../common'; import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled'; import { noOp } from '../common/utils'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { StyledListItem } from '../ListItem/ListItem'; import { LabelText, @@ -52,7 +52,7 @@ const sharedCheckboxStyles = css` justify-content: space-around; margin-right: 0.5rem; `; -const StyledCheckbox = styled(StyledCutout)` +const StyledCheckbox = styled(StyledScrollView)` ${sharedCheckboxStyles} width: ${size}px; height: ${size}px; diff --git a/src/ColorInput/ColorInput.stories.tsx b/src/ColorInput/ColorInput.stories.tsx index 5dc9aab8..5ec6a981 100644 --- a/src/ColorInput/ColorInput.stories.tsx +++ b/src/ColorInput/ColorInput.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; import styled from 'styled-components'; -import { ColorInput, Cutout } from 'react95'; +import { ColorInput, ScrollView } from 'react95'; const Wrapper = styled.div` background: ${({ theme }) => theme.material}; @@ -50,7 +50,7 @@ Default.story = { export function Flat() { return ( - +
enabled: @@ -61,7 +61,7 @@ export function Flat() {
-
+ ); } diff --git a/src/Cutout/Cutout.mdx b/src/Cutout/Cutout.mdx deleted file mode 100644 index a29422ee..00000000 --- a/src/Cutout/Cutout.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -name: Cutout -menu: Components ---- - -import { Cutout } from './Cutout'; -import Window from '../Window/Window'; -import WindowContent from '../WindowContent/WindowContent'; - -# Cutout - -## Usage - - - - - -

- React95 -

-
-
-
-
- -## API - -### Import - -``` -import { Cutout } from 'react95' -``` - -### Props - - diff --git a/src/Cutout/Cutout.spec.tsx b/src/Cutout/Cutout.spec.tsx deleted file mode 100644 index 08681f7e..00000000 --- a/src/Cutout/Cutout.spec.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { render } from '@testing-library/react'; -import React from 'react'; - -import { Cutout } from './Cutout'; - -describe('', () => { - it('should render cutout', () => { - const { container } = render(); - const cutout = container.firstElementChild; - - expect(cutout).toBeInTheDocument(); - }); - - it('should render custom styles', () => { - const { container } = render( - - ); - const cutout = container.firstElementChild; - - expect(cutout).toHaveAttribute('style', 'background-color: papayawhip;'); - }); - - it('should render children', async () => { - const { findByText } = render( - - Cool cutout - - ); - const content = await findByText(/cool cutout/i); - - expect(content).toBeInTheDocument(); - }); - - it('should render custom props', () => { - const customProps = { title: 'cutout' }; - const { container } = render(); - const cutout = container.firstElementChild; - - expect(cutout).toHaveAttribute('title', 'cutout'); - }); -}); diff --git a/src/DatePicker/DatePicker.tsx b/src/DatePicker/DatePicker.tsx index 4b4521c2..a49dcbc8 100644 --- a/src/DatePicker/DatePicker.tsx +++ b/src/DatePicker/DatePicker.tsx @@ -2,8 +2,8 @@ import React, { forwardRef, useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; import { Button } from '../Button/Button'; -import { Cutout } from '../Cutout/Cutout'; import { NumberField } from '../NumberField/NumberField'; +import { ScrollView } from '../ScrollView/ScrollView'; import { Select } from '../Select/Select'; import { SelectChangeEvent } from '../Select/Select.types'; import { Toolbar } from '../Toolbar/Toolbar'; @@ -19,7 +19,7 @@ type DatePickerProps = { shadow?: boolean; }; -const Calendar = styled(Cutout)` +const Calendar = styled(ScrollView)` width: 234px; margin: 1rem 0; background: ${({ theme }) => theme.canvas}; diff --git a/src/Desktop/Desktop.tsx b/src/Desktop/Desktop.tsx index 22541bb0..80d38465 100644 --- a/src/Desktop/Desktop.tsx +++ b/src/Desktop/Desktop.tsx @@ -1,7 +1,7 @@ import React, { forwardRef } from 'react'; import styled from 'styled-components'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; type DesktopProps = { backgroundStyles?: React.CSSProperties; @@ -56,7 +56,7 @@ const Monitor = styled.div` } `; -const Background = styled(StyledCutout).attrs(() => ({ +const Background = styled(StyledScrollView).attrs(() => ({ 'data-testid': 'background' }))` width: 100%; diff --git a/src/Fieldset/Fieldset.stories.tsx b/src/Fieldset/Fieldset.stories.tsx index 819fcafa..04a264c1 100644 --- a/src/Fieldset/Fieldset.stories.tsx +++ b/src/Fieldset/Fieldset.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; -import { Checkbox, Cutout, Fieldset, Window, WindowContent } from 'react95'; +import { Checkbox, Fieldset, ScrollView, Window, WindowContent } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -44,7 +44,7 @@ export function Flat() { return ( -
@@ -60,7 +60,7 @@ export function Flat() { 😍
-
+
); diff --git a/src/LoadingIndicator/LoadingIndicator.tsx b/src/LoadingIndicator/LoadingIndicator.tsx index 78457d71..d280f012 100644 --- a/src/LoadingIndicator/LoadingIndicator.tsx +++ b/src/LoadingIndicator/LoadingIndicator.tsx @@ -1,6 +1,6 @@ import React, { forwardRef } from 'react'; import styled, { css, keyframes } from 'styled-components'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { CommonStyledProps } from '../types'; type LoadingIndicatorProps = { @@ -14,7 +14,7 @@ const Wrapper = styled.div` height: 15px; width: 100%; `; -const ProgressCutout = styled(StyledCutout)` +const ProgressCutout = styled(StyledScrollView)` width: 100%; height: 100%; width: 100%; diff --git a/src/NumberField/NumberField.mdx b/src/NumberField/NumberField.mdx index eeba5ce1..5f1659be 100644 --- a/src/NumberField/NumberField.mdx +++ b/src/NumberField/NumberField.mdx @@ -4,7 +4,7 @@ menu: Components --- import { NumberField } from './NumberField'; -import { Cutout } from '../Cutout/Cutout'; +import { ScrollView } from '../ScrollView/ScrollView'; # NumberField @@ -51,7 +51,7 @@ import { Cutout } from '../Cutout/Cutout'; #### Flat - +

When you want to use NumberField on a light background (like scrollable content), just use the flat variant: @@ -62,7 +62,7 @@ import { Cutout } from '../Cutout/Cutout'; value={1991} onChange={value => console.log(value)} /> - + ## API diff --git a/src/NumberField/NumberField.stories.tsx b/src/NumberField/NumberField.stories.tsx index 84f5b93e..e3678880 100644 --- a/src/NumberField/NumberField.stories.tsx +++ b/src/NumberField/NumberField.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { Cutout, NumberField } from 'react95'; +import { NumberField, ScrollView } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -44,7 +44,7 @@ Default.story = { export function Flat() { return ( - +

When you want to use NumberField on a light background (like scrollable content), just use the flat variant: @@ -60,7 +60,7 @@ export function Flat() {
- + ); } diff --git a/src/Progress/Progress.tsx b/src/Progress/Progress.tsx index 79ea5cd7..323c9532 100644 --- a/src/Progress/Progress.tsx +++ b/src/Progress/Progress.tsx @@ -8,7 +8,7 @@ import React, { import styled, { css } from 'styled-components'; import { blockSizes } from '../common/system'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { CommonStyledProps } from '../types'; type ProgressProps = { @@ -24,7 +24,7 @@ const Wrapper = styled.div` height: ${blockSizes.md}; width: 100%; `; -const ProgressCutout = styled(StyledCutout)` +const ProgressCutout = styled(StyledScrollView)` width: 100%; height: 100%; width: 100%; diff --git a/src/Radio/Radio.stories.tsx b/src/Radio/Radio.stories.tsx index a48ac2ef..91ffec38 100644 --- a/src/Radio/Radio.stories.tsx +++ b/src/Radio/Radio.stories.tsx @@ -1,11 +1,11 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; import { - Cutout, Fieldset, List, ListItem, Radio, + ScrollView, Separator, Window, WindowContent @@ -90,7 +90,7 @@ export function Flat() { return ( - +

When you want to use radio buttons on a light background (like scrollable content), just use the flat variant: @@ -134,7 +134,7 @@ export function Flat() { disabled /> - + ); diff --git a/src/Radio/Radio.tsx b/src/Radio/Radio.tsx index b1bee405..9ff3ee0a 100644 --- a/src/Radio/Radio.tsx +++ b/src/Radio/Radio.tsx @@ -2,8 +2,8 @@ import React, { forwardRef } from 'react'; import styled, { css, CSSProperties } from 'styled-components'; import { createFlatBoxStyles } from '../common'; -import { StyledCutout } from '../Cutout/Cutout'; import { StyledListItem } from '../ListItem/ListItem'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { LabelText, size, @@ -44,7 +44,7 @@ type StyledCheckboxProps = { $disabled: boolean; }; -const StyledCheckbox = styled(StyledCutout)` +const StyledCheckbox = styled(StyledScrollView)` ${sharedCheckboxStyles} background: ${({ $disabled, theme }) => $disabled ? theme.material : theme.canvas}; diff --git a/src/ScrollView/ScrollView.spec.tsx b/src/ScrollView/ScrollView.spec.tsx new file mode 100644 index 00000000..71593cde --- /dev/null +++ b/src/ScrollView/ScrollView.spec.tsx @@ -0,0 +1,44 @@ +import { render } from '@testing-library/react'; +import React from 'react'; + +import { ScrollView } from './ScrollView'; + +describe('', () => { + it('should render scrollview', () => { + const { container } = render(); + const scrollView = container.firstElementChild; + + expect(scrollView).toBeInTheDocument(); + }); + + it('should render custom styles', () => { + const { container } = render( + + ); + const scrollView = container.firstElementChild; + + expect(scrollView).toHaveAttribute( + 'style', + 'background-color: papayawhip;' + ); + }); + + it('should render children', async () => { + const { findByText } = render( + + Cool ScrollView + + ); + const content = await findByText(/cool scrollview/i); + + expect(content).toBeInTheDocument(); + }); + + it('should render custom props', () => { + const customProps = { title: 'scrollview' }; + const { container } = render(); + const scrollView = container.firstElementChild; + + expect(scrollView).toHaveAttribute('title', 'scrollview'); + }); +}); diff --git a/src/Cutout/Cutout.stories.tsx b/src/ScrollView/ScrollView.stories.tsx similarity index 82% rename from src/Cutout/Cutout.stories.tsx rename to src/ScrollView/ScrollView.stories.tsx index 5dc2b909..4d7964b5 100644 --- a/src/Cutout/Cutout.stories.tsx +++ b/src/ScrollView/ScrollView.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { Cutout, Window, WindowContent } from 'react95'; +import { ScrollView, Window, WindowContent } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -9,16 +9,16 @@ const Wrapper = styled.div` `; export default { - title: 'Cutout', - component: Cutout, + title: 'Layout/ScrollView', + component: ScrollView, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { return ( - +

React95 is the best UI library ever created @@ -32,7 +32,7 @@ export function Default() {

React95 is the best UI library ever created

React95 is the best UI library ever created

-
+
); diff --git a/src/Cutout/Cutout.tsx b/src/ScrollView/ScrollView.tsx similarity index 74% rename from src/Cutout/Cutout.tsx rename to src/ScrollView/ScrollView.tsx index 94c0ab7c..632ae1e3 100644 --- a/src/Cutout/Cutout.tsx +++ b/src/ScrollView/ScrollView.tsx @@ -3,13 +3,13 @@ import styled from 'styled-components'; import { insetShadow, createScrollbars } from '../common'; import { CommonStyledProps } from '../types'; -type CutoutProps = { +type ScrollViewProps = { children?: React.ReactNode; shadow?: boolean; } & React.HTMLAttributes & CommonStyledProps; -export const StyledCutout = styled.div>` +export const StyledScrollView = styled.div>` position: relative; box-sizing: border-box; padding: 2px; @@ -50,15 +50,16 @@ const Content = styled.div` ${createScrollbars()} `; -const Cutout = forwardRef(function Cutout( - { children, shadow = true, ...otherProps }, - ref -) { - return ( - - {children} - - ); -}); +const ScrollView = forwardRef( + ({ children, shadow = true, ...otherProps }, ref) => { + return ( + + {children} + + ); + } +); + +ScrollView.displayName = 'ScrollView'; -export { Cutout, CutoutProps }; +export { ScrollView, ScrollViewProps }; diff --git a/src/Select/Select.mdx b/src/Select/Select.mdx index 41086103..b4465bf9 100644 --- a/src/Select/Select.mdx +++ b/src/Select/Select.mdx @@ -4,9 +4,9 @@ menu: Components --- import { Select } from './Select'; -import Window from '../Window/Window'; -import WindowContent from '../WindowContent/WindowContent'; -import { Cutout } from '../Cutout/Cutout'; +import { ScrollView } from '../ScrollView/ScrollView'; +import { Window } from '../Window/Window'; +import { WindowContent } from '../WindowContent/WindowContent'; # Select @@ -98,7 +98,7 @@ import { Cutout } from '../Cutout/Cutout'; return ( - - + ); diff --git a/src/Select/Select.stories.tsx b/src/Select/Select.stories.tsx index 3184100a..20e8381a 100644 --- a/src/Select/Select.stories.tsx +++ b/src/Select/Select.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { Cutout, Fieldset, Select, Window, WindowContent } from 'react95'; +import { Fieldset, ScrollView, Select, Window, WindowContent } from 'react95'; import styled from 'styled-components'; import { SelectChangeEvent, SelectOption } from './Select.types'; @@ -106,7 +106,7 @@ export function Flat() { return ( - +

When you want to use Select on a light background (like scrollable content), just use the flat variant: @@ -144,7 +144,7 @@ export function Flat() { options={options} /> - + ); diff --git a/src/Select/Select.styles.tsx b/src/Select/Select.styles.tsx index 6855df2f..c3e679ea 100644 --- a/src/Select/Select.styles.tsx +++ b/src/Select/Select.styles.tsx @@ -8,7 +8,7 @@ import { shadow as commonShadow } from '../common'; import { blockSizes } from '../common/system'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { CommonThemeProps } from '../types'; import { SelectVariants } from './Select.types'; @@ -66,7 +66,9 @@ const sharedWrapperStyles = css` cursor: ${({ $disabled }) => ($disabled ? 'default' : 'pointer')}; `; -export const StyledSelectWrapper = styled(StyledCutout)` +export const StyledSelectWrapper = styled( + StyledScrollView +)` ${sharedWrapperStyles} background: ${({ $disabled = false, theme }) => $disabled ? theme.material : theme.canvas}; diff --git a/src/Slider/Slider.stories.tsx b/src/Slider/Slider.stories.tsx index 6f1f453d..dd3fc8eb 100644 --- a/src/Slider/Slider.stories.tsx +++ b/src/Slider/Slider.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { Cutout, Slider } from 'react95'; +import { ScrollView, Slider } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -116,7 +116,7 @@ Default.story = { export function Flat() { return ( - +

When you want to add input field on a light background (like scrollable content), just use the flat variant: @@ -146,7 +146,7 @@ export function Flat() { { value: 6, label: '6°C' } ]} /> - + ); } diff --git a/src/Slider/Slider.tsx b/src/Slider/Slider.tsx index 1f37168c..f1c6196a 100644 --- a/src/Slider/Slider.tsx +++ b/src/Slider/Slider.tsx @@ -20,7 +20,7 @@ import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontro import useForkRef from '../common/hooks/useForkRef'; import { useIsFocusVisible } from '../common/hooks/useIsFocusVisible'; import { clamp, getSize, roundValueToStep } from '../common/utils'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { CommonStyledProps } from '../types'; type SliderProps = { @@ -187,10 +187,10 @@ const sharedGrooveStyles = () => css` width: 100%; `} `; -const StyledGroove = styled(StyledCutout)` +const StyledGroove = styled(StyledScrollView)` ${sharedGrooveStyles()} `; -const StyledFlatGroove = styled(StyledCutout)` +const StyledFlatGroove = styled(StyledScrollView)` ${sharedGrooveStyles()} border-left-color: ${({ theme }) => theme.flatLight}; diff --git a/src/Table/Table.tsx b/src/Table/Table.tsx index 304cb0e2..b6ab5c9d 100644 --- a/src/Table/Table.tsx +++ b/src/Table/Table.tsx @@ -1,6 +1,6 @@ import React, { forwardRef } from 'react'; import styled from 'styled-components'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { CommonStyledProps } from '../types'; type TableProps = { @@ -16,7 +16,7 @@ const StyledTable = styled.table` font-size: 1rem; `; -const Wrapper = styled(StyledCutout)` +const Wrapper = styled(StyledScrollView)` &:before { box-shadow: none; } diff --git a/src/TextField/TextField.mdx b/src/TextField/TextField.mdx index 0ea168dd..b0a281bd 100644 --- a/src/TextField/TextField.mdx +++ b/src/TextField/TextField.mdx @@ -3,8 +3,8 @@ name: TextField menu: Components --- +import { ScrollView } from '../ScrollView/ScrollView'; import { TextField } from './TextField'; -import { Cutout } from '../Cutout/Cutout'; # TextField @@ -49,7 +49,7 @@ import { Cutout } from '../Cutout/Cutout'; #### Flat - +

When you want to add input field on a light background (like scrollable content), just use the flat variant: @@ -69,13 +69,13 @@ import { Cutout } from '../Cutout/Cutout'; onChange={e => console.log(e.target.value)} /> - + #### Flat disabled - +

When you want to add input field on a light background (like scrollable content), just use the flat variant: @@ -96,7 +96,7 @@ import { Cutout } from '../Cutout/Cutout'; disabled /> - + ## API diff --git a/src/TextField/TextField.stories.tsx b/src/TextField/TextField.stories.tsx index f9134231..6a715117 100644 --- a/src/TextField/TextField.stories.tsx +++ b/src/TextField/TextField.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; -import { Button, Cutout, TextField } from 'react95'; +import { Button, ScrollView, TextField } from 'react95'; import styled from 'styled-components'; const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sollicitudin, ante vel porttitor posuere, tellus nisi interdum ipsum, non bibendum ante risus ut purus. Curabitur vel posuere odio. Vivamus rutrum, nunc et ullamcorper sagittis, tellus ligula maximus quam, id dapibus sapien metus lobortis diam. Proin luctus, dolor in finibus feugiat, lacus enim gravida sem, quis aliquet tellus leo nec enim. Morbi varius bibendum augue quis venenatis. Curabitur ut elit augue. Pellentesque posuere enim a mattis interdum. Donec sodales convallis turpis, a vulputate elit. Suspendisse potenti.`; @@ -68,7 +68,7 @@ Default.story = { export function Flat() { return ( - +

When you want to add input field on a light background (like scrollable content), just use the flat variant: @@ -110,7 +110,7 @@ export function Flat() { onChange={onChange} fullWidth /> - + ); } diff --git a/src/TextField/TextField.tsx b/src/TextField/TextField.tsx index 8014c57f..37ee1511 100644 --- a/src/TextField/TextField.tsx +++ b/src/TextField/TextField.tsx @@ -7,7 +7,7 @@ import { } from '../common'; import { blockSizes } from '../common/system'; import { noOp } from '../common/utils'; -import { StyledCutout } from '../Cutout/Cutout'; +import { StyledScrollView } from '../ScrollView/ScrollView'; import { CommonStyledProps, CommonThemeProps } from '../types'; type TextFieldInputProps = { @@ -49,7 +49,7 @@ const sharedWrapperStyles = css` min-height: ${blockSizes.md}; `; -const Wrapper = styled(StyledCutout).attrs({ +const Wrapper = styled(StyledScrollView).attrs({ 'data-testid': 'variant-default' })` ${sharedWrapperStyles} diff --git a/src/index.ts b/src/index.ts index 61da4ffb..662d8d20 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,6 @@ export * from './Button/Button'; export * from './Checkbox/Checkbox'; export * from './ColorInput/ColorInput'; export * from './Counter/Counter'; -export * from './Cutout/Cutout'; export * from './DatePicker/DatePicker'; export * from './Desktop/Desktop'; export * from './Fieldset/Fieldset'; @@ -23,6 +22,7 @@ export * from './NumberField/NumberField'; export * from './Panel/Panel'; export * from './Progress/Progress'; export * from './Radio/Radio'; +export * from './ScrollView/ScrollView'; export * from './Select/Select'; export * from './Separator/Separator'; export * from './Slider/Slider'; @@ -45,4 +45,5 @@ export * from './WindowHeader/WindowHeader'; /* deprecated components */ export * from './legacy/Bar'; -export * from './legacy/Separator'; +export * from './legacy/Cutout'; +export * from './legacy/Divider'; diff --git a/src/legacy/Cutout.tsx b/src/legacy/Cutout.tsx new file mode 100644 index 00000000..a7d9aaf2 --- /dev/null +++ b/src/legacy/Cutout.tsx @@ -0,0 +1,7 @@ +import { ScrollView, ScrollViewProps } from '../ScrollView/ScrollView'; + +/** @deprecated Use `ScrollViewProps` */ +export type CutoutProps = ScrollViewProps; + +/** @deprecated Use `ScrollView` */ +export const Cutout = ScrollView; From b408e1e26751f598df0a982907d4020020cfc3c7 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 07:59:32 -0400 Subject: [PATCH 11/29] refactor(monitor): categorize under Other, rename Desktop to Monitor --- src/Desktop/Desktop.mdx | 22 ----------- .../Monitor.spec.tsx} | 20 +++++----- .../Monitor.stories.tsx} | 10 ++--- .../Desktop.tsx => Monitor/Monitor.tsx} | 37 ++++++++++--------- src/index.ts | 3 +- src/legacy/Desktop.tsx | 7 ++++ 6 files changed, 43 insertions(+), 56 deletions(-) delete mode 100644 src/Desktop/Desktop.mdx rename src/{Desktop/Desktop.spec.tsx => Monitor/Monitor.spec.tsx} (61%) rename src/{Desktop/Desktop.stories.tsx => Monitor/Monitor.stories.tsx} (66%) rename src/{Desktop/Desktop.tsx => Monitor/Monitor.tsx} (84%) create mode 100644 src/legacy/Desktop.tsx diff --git a/src/Desktop/Desktop.mdx b/src/Desktop/Desktop.mdx deleted file mode 100644 index a34d2aad..00000000 --- a/src/Desktop/Desktop.mdx +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Desktop -menu: Components ---- - -import { Desktop } from '../Desktop/Desktop'; - -# Desktop - -## Usage - - - - - -## API - -### Import - -### Props - - diff --git a/src/Desktop/Desktop.spec.tsx b/src/Monitor/Monitor.spec.tsx similarity index 61% rename from src/Desktop/Desktop.spec.tsx rename to src/Monitor/Monitor.spec.tsx index c7e239e0..43f01b08 100644 --- a/src/Desktop/Desktop.spec.tsx +++ b/src/Monitor/Monitor.spec.tsx @@ -2,30 +2,30 @@ import React from 'react'; import { renderWithTheme } from '../../test/utils'; -import { Desktop } from './Desktop'; +import { Monitor } from './Monitor'; -describe('', () => { +describe('', () => { it('should render', () => { - const { container } = renderWithTheme(); - const desktopElement = container.firstElementChild; + const { container } = renderWithTheme(); + const monitorElement = container.firstElementChild; - expect(desktopElement).toBeInTheDocument(); + expect(monitorElement).toBeInTheDocument(); }); it('should handle custom props', () => { const customProps: React.HTMLAttributes = { title: 'potatoe' }; - const { container } = renderWithTheme(); - const desktopElement = container.firstElementChild; + const { container } = renderWithTheme(); + const monitorElement = container.firstElementChild; - expect(desktopElement).toHaveAttribute('title', 'potatoe'); + expect(monitorElement).toHaveAttribute('title', 'potatoe'); }); describe('prop: backgroundStyles', () => { it('should forward styles to background element', () => { const { getByTestId } = renderWithTheme( - + ); const backgroundElement = getByTestId('background'); @@ -38,7 +38,7 @@ describe('', () => { describe('prop: children', () => { it('children should be rendered in background element', () => { - const { getByTestId } = renderWithTheme(Hi!); + const { getByTestId } = renderWithTheme(Hi!); const backgroundElement = getByTestId('background'); expect(backgroundElement.innerHTML).toBe('Hi!'); diff --git a/src/Desktop/Desktop.stories.tsx b/src/Monitor/Monitor.stories.tsx similarity index 66% rename from src/Desktop/Desktop.stories.tsx rename to src/Monitor/Monitor.stories.tsx index dfaa324f..2e3394fd 100644 --- a/src/Desktop/Desktop.stories.tsx +++ b/src/Monitor/Monitor.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { Desktop } from 'react95'; +import { Monitor } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -9,13 +9,13 @@ const Wrapper = styled.div` `; export default { - title: 'Desktop', - component: Desktop, + title: 'Other/Monitor', + component: Monitor, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { - return ; + return ; } Default.story = { diff --git a/src/Desktop/Desktop.tsx b/src/Monitor/Monitor.tsx similarity index 84% rename from src/Desktop/Desktop.tsx rename to src/Monitor/Monitor.tsx index 80d38465..8abfa45e 100644 --- a/src/Desktop/Desktop.tsx +++ b/src/Monitor/Monitor.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components'; import { StyledScrollView } from '../ScrollView/ScrollView'; -type DesktopProps = { +type MonitorProps = { backgroundStyles?: React.CSSProperties; children?: React.ReactNode; }; @@ -18,7 +18,7 @@ const Inner = styled.div` position: relative; `; -const Monitor = styled.div` +const MonitorBody = styled.div` position: relative; z-index: 1; box-sizing: border-box; @@ -106,20 +106,21 @@ const Stand = styled.div` } `; -const Desktop = forwardRef(function Desktop( - { backgroundStyles, children, ...otherProps }, - ref -) { - return ( - - - - {children} - - - - - ); -}); +const Monitor = forwardRef( + ({ backgroundStyles, children, ...otherProps }, ref) => { + return ( + + + + {children} + + + + + ); + } +); + +Monitor.displayName = 'Monitor'; -export { Desktop, DesktopProps }; +export { Monitor, MonitorProps }; diff --git a/src/index.ts b/src/index.ts index 662d8d20..50d66285 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,13 +11,13 @@ export * from './Checkbox/Checkbox'; export * from './ColorInput/ColorInput'; export * from './Counter/Counter'; export * from './DatePicker/DatePicker'; -export * from './Desktop/Desktop'; export * from './Fieldset/Fieldset'; export * from './Handle/Handle'; export * from './Hourglass/Hourglass'; export * from './List/List'; export * from './ListItem/ListItem'; export * from './LoadingIndicator/LoadingIndicator'; +export * from './Monitor/Monitor'; export * from './NumberField/NumberField'; export * from './Panel/Panel'; export * from './Progress/Progress'; @@ -46,4 +46,5 @@ export * from './WindowHeader/WindowHeader'; /* deprecated components */ export * from './legacy/Bar'; export * from './legacy/Cutout'; +export * from './legacy/Desktop'; export * from './legacy/Divider'; diff --git a/src/legacy/Desktop.tsx b/src/legacy/Desktop.tsx new file mode 100644 index 00000000..83069def --- /dev/null +++ b/src/legacy/Desktop.tsx @@ -0,0 +1,7 @@ +import { Monitor, MonitorProps } from '../Monitor/Monitor'; + +/** @deprecated Use `MonitorProps` */ +export type DesktopProps = MonitorProps; + +/** @deprecated Use `Monitor` */ +export const Desktop = Monitor; From b3e5158c980099f0619bd25106ee5ed461958b13 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 08:01:26 -0400 Subject: [PATCH 12/29] refactor(groupbox): categorize under Controls, rename Fieldset to GroupBox --- src/Checkbox/Checkbox.stories.tsx | 10 +- src/Fieldset/Fieldset.mdx | 103 ------------------ src/Fieldset/Fieldset.spec.tsx | 53 --------- src/GroupBox/GroupBox.spec.tsx | 53 +++++++++ .../GroupBox.stories.tsx} | 28 ++--- .../Fieldset.tsx => GroupBox/GroupBox.tsx} | 16 +-- src/Radio/Radio.stories.tsx | 10 +- src/Select/Select.stories.tsx | 18 +-- src/Tabs/Tabs.stories.tsx | 6 +- src/Tree/Tree.stories.tsx | 18 +-- src/index.ts | 3 +- src/legacy/Fieldset.tsx | 7 ++ 12 files changed, 116 insertions(+), 209 deletions(-) delete mode 100644 src/Fieldset/Fieldset.mdx delete mode 100644 src/Fieldset/Fieldset.spec.tsx create mode 100644 src/GroupBox/GroupBox.spec.tsx rename src/{Fieldset/Fieldset.stories.tsx => GroupBox/GroupBox.stories.tsx} (79%) rename src/{Fieldset/Fieldset.tsx => GroupBox/GroupBox.tsx} (84%) create mode 100644 src/legacy/Fieldset.tsx diff --git a/src/Checkbox/Checkbox.stories.tsx b/src/Checkbox/Checkbox.stories.tsx index a594fba5..75fb1734 100644 --- a/src/Checkbox/Checkbox.stories.tsx +++ b/src/Checkbox/Checkbox.stories.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import { ComponentMeta } from '@storybook/react'; import { Checkbox, - Fieldset, + GroupBox, List, ListItem, ScrollView, @@ -78,7 +78,7 @@ export function Default() { return (

-
+
- +
-
+
- + - - -
- Some content here - - 😍 - -
-
-
- - -#### With label - - - - -
- Some content here - - 😍 - -
-
-
-
- -#### Flat - - - {() => { - const [enabled, setEnabled] = React.useState(false) - return ( - - - - <> -

- When you want to use Fieldset on a light background (like scrollable - content), just use the flat variant: -

-
-
setEnabled(!enabled)} - /> - } - disabled={!enabled} - > - <> - Some content here - - 😍 - - -
-
- -
-
-
- ); - }} -
- -## API - -### Import - -``` -import { Fieldset } from 'react95' -``` - -### Props - - diff --git a/src/Fieldset/Fieldset.spec.tsx b/src/Fieldset/Fieldset.spec.tsx deleted file mode 100644 index da7a64e7..00000000 --- a/src/Fieldset/Fieldset.spec.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; - -import { renderWithTheme, theme } from '../../test/utils'; - -import { Fieldset } from './Fieldset'; - -describe('
', () => { - it('renders Fieldset', () => { - const { container } = renderWithTheme(
); - const fieldset = container.firstChild as HTMLFieldSetElement; - - expect(fieldset).toBeInTheDocument(); - }); - it('renders children', () => { - const textContent = 'Hi there!'; - const { getByText } = renderWithTheme( -
- {textContent} -
- ); - expect(getByText(textContent)).toBeInTheDocument(); - }); - - describe('prop: label', () => { - it('renders Label', () => { - const labelText = 'Name:'; - const { container } = renderWithTheme(
); - const fieldset = container.firstChild as HTMLFieldSetElement; - const legend = fieldset.querySelector('legend'); - expect(legend?.textContent).toBe(labelText); - }); - it('when not provided, element is not rendered', () => { - const { container } = renderWithTheme(
); - const fieldset = container.firstChild as HTMLFieldSetElement; - const legend = fieldset.querySelector('legend'); - expect(legend).not.toBeInTheDocument(); - }); - }); - describe('prop: disabled', () => { - it('renders with disabled text content', () => { - const { container } = renderWithTheme(
); - const fieldset = container.firstChild as HTMLFieldSetElement; - - expect(fieldset).toHaveAttribute('aria-disabled', 'true'); - - expect(fieldset).toHaveStyleRule('color', theme.materialTextDisabled); - expect(fieldset).toHaveStyleRule( - 'text-shadow', - `1px 1px ${theme.materialTextDisabledShadow}` - ); - }); - }); -}); diff --git a/src/GroupBox/GroupBox.spec.tsx b/src/GroupBox/GroupBox.spec.tsx new file mode 100644 index 00000000..168c58ad --- /dev/null +++ b/src/GroupBox/GroupBox.spec.tsx @@ -0,0 +1,53 @@ +import React from 'react'; + +import { renderWithTheme, theme } from '../../test/utils'; + +import { GroupBox } from './GroupBox'; + +describe('', () => { + it('renders GroupBox', () => { + const { container } = renderWithTheme(); + const groupBox = container.firstChild as HTMLFieldSetElement; + + expect(groupBox).toBeInTheDocument(); + }); + it('renders children', () => { + const textContent = 'Hi there!'; + const { getByText } = renderWithTheme( + + {textContent} + + ); + expect(getByText(textContent)).toBeInTheDocument(); + }); + + describe('prop: label', () => { + it('renders Label', () => { + const labelText = 'Name:'; + const { container } = renderWithTheme(); + const groupBox = container.firstChild as HTMLFieldSetElement; + const legend = groupBox.querySelector('legend'); + expect(legend?.textContent).toBe(labelText); + }); + it('when not provided, element is not rendered', () => { + const { container } = renderWithTheme(); + const groupBox = container.firstChild as HTMLFieldSetElement; + const legend = groupBox.querySelector('legend'); + expect(legend).not.toBeInTheDocument(); + }); + }); + describe('prop: disabled', () => { + it('renders with disabled text content', () => { + const { container } = renderWithTheme(); + const groupBox = container.firstChild as HTMLFieldSetElement; + + expect(groupBox).toHaveAttribute('aria-disabled', 'true'); + + expect(groupBox).toHaveStyleRule('color', theme.materialTextDisabled); + expect(groupBox).toHaveStyleRule( + 'text-shadow', + `1px 1px ${theme.materialTextDisabledShadow}` + ); + }); + }); +}); diff --git a/src/Fieldset/Fieldset.stories.tsx b/src/GroupBox/GroupBox.stories.tsx similarity index 79% rename from src/Fieldset/Fieldset.stories.tsx rename to src/GroupBox/GroupBox.stories.tsx index 04a264c1..0cba694b 100644 --- a/src/Fieldset/Fieldset.stories.tsx +++ b/src/GroupBox/GroupBox.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; -import { Checkbox, Fieldset, ScrollView, Window, WindowContent } from 'react95'; +import { Checkbox, GroupBox, ScrollView, Window, WindowContent } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -9,28 +9,28 @@ const Wrapper = styled.div` `; export default { - title: 'Fieldset', - component: Fieldset, + title: 'Controls/GroupBox', + component: GroupBox, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { return ( -
+ Some content here 😍 -
+

-
+ Some content here 😍 -
+
); @@ -47,19 +47,19 @@ export function Flat() { -
+ Some content here 😍 -
+

-
+ Some content here 😍 -
+
@@ -75,7 +75,7 @@ export function ToggleExample() { return ( -
😍 -
+
); diff --git a/src/Fieldset/Fieldset.tsx b/src/GroupBox/GroupBox.tsx similarity index 84% rename from src/Fieldset/Fieldset.tsx rename to src/GroupBox/GroupBox.tsx index 05ff72b4..a2d381c5 100644 --- a/src/Fieldset/Fieldset.tsx +++ b/src/GroupBox/GroupBox.tsx @@ -3,7 +3,7 @@ import styled, { css } from 'styled-components'; import { createDisabledTextStyles } from '../common'; import { CommonStyledProps } from '../types'; -type FieldsetProps = { +type GroupBoxProps = { label?: React.ReactNode; children?: React.ReactNode; disabled?: boolean; @@ -12,7 +12,7 @@ type FieldsetProps = { CommonStyledProps; const StyledFieldset = styled.fieldset< - Pick & { $disabled: boolean } + Pick & { $disabled: boolean } >` position: relative; border: 2px solid @@ -31,7 +31,7 @@ const StyledFieldset = styled.fieldset< ${props => props.$disabled && createDisabledTextStyles()} `; -const StyledLegend = styled.legend>` +const StyledLegend = styled.legend>` display: flex; position: absolute; top: 0; @@ -44,11 +44,11 @@ const StyledLegend = styled.legend>` variant === 'flat' ? theme.canvas : theme.material}; `; -const Fieldset = forwardRef( - function Fieldset( +const GroupBox = forwardRef( + ( { label, disabled = false, variant = 'default', children, ...otherProps }, ref - ) { + ) => { return ( ( } ); -export { Fieldset, FieldsetProps }; +GroupBox.displayName = 'GroupBox'; + +export { GroupBox, GroupBoxProps }; diff --git a/src/Radio/Radio.stories.tsx b/src/Radio/Radio.stories.tsx index 91ffec38..25c4e36b 100644 --- a/src/Radio/Radio.stories.tsx +++ b/src/Radio/Radio.stories.tsx @@ -1,7 +1,7 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; import { - Fieldset, + GroupBox, List, ListItem, Radio, @@ -39,7 +39,7 @@ export function Default() { return ( -
+ -
+
); @@ -96,7 +96,7 @@ export function Flat() { scrollable content), just use the flat variant:

-
+ -
+ diff --git a/src/Select/Select.stories.tsx b/src/Select/Select.stories.tsx index 20e8381a..29946074 100644 --- a/src/Select/Select.stories.tsx +++ b/src/Select/Select.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { Fieldset, ScrollView, Select, Window, WindowContent } from 'react95'; +import { GroupBox, ScrollView, Select, Window, WindowContent } from 'react95'; import styled from 'styled-components'; import { SelectChangeEvent, SelectOption } from './Select.types'; @@ -51,7 +51,7 @@ export default { export function Default() { return (
-
+ -
+
); } @@ -111,7 +111,7 @@ export function Flat() { When you want to use Select on a light background (like scrollable content), just use the flat variant:

-
+ -
+ diff --git a/src/Tabs/Tabs.stories.tsx b/src/Tabs/Tabs.stories.tsx index 5ba196d3..a910639e 100644 --- a/src/Tabs/Tabs.stories.tsx +++ b/src/Tabs/Tabs.stories.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { Anchor, Checkbox, - Fieldset, + GroupBox, NumberField, Tab, TabBody, @@ -49,7 +49,7 @@ export function Default() { {activeTab === 0 && (
-
+
Amount:

@@ -60,7 +60,7 @@ export function Default() { onChange={() => null} defaultChecked /> -
+
)} {activeTab === 1 && ( diff --git a/src/Tree/Tree.stories.tsx b/src/Tree/Tree.stories.tsx index 011214b5..c5e64250 100644 --- a/src/Tree/Tree.stories.tsx +++ b/src/Tree/Tree.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React, { useCallback, useState } from 'react'; -import { Fieldset, Tree, TreeLeaf } from 'react95'; +import { GroupBox, Tree, TreeLeaf } from 'react95'; import styled from 'styled-components'; import { Button } from '../Button/Button'; @@ -97,9 +97,9 @@ categories.forEach(getIds); export function Basic() { return (
-
+ -
+
); } @@ -124,7 +124,7 @@ export function Controlled() { -
+ setSelected(id)} @@ -132,7 +132,7 @@ export function Controlled() { expanded={expanded} selected={selected} /> -
+ ); } @@ -144,9 +144,9 @@ Controlled.story = { export function Disabled() { return (
-
+ -
+
); } @@ -167,9 +167,9 @@ export function DisabledTreeItems() { return (
-
+ -
+
); } diff --git a/src/index.ts b/src/index.ts index 50d66285..13c523ac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ export * from './Checkbox/Checkbox'; export * from './ColorInput/ColorInput'; export * from './Counter/Counter'; export * from './DatePicker/DatePicker'; -export * from './Fieldset/Fieldset'; +export * from './GroupBox/GroupBox'; export * from './Handle/Handle'; export * from './Hourglass/Hourglass'; export * from './List/List'; @@ -48,3 +48,4 @@ export * from './legacy/Bar'; export * from './legacy/Cutout'; export * from './legacy/Desktop'; export * from './legacy/Divider'; +export * from './legacy/Fieldset'; diff --git a/src/legacy/Fieldset.tsx b/src/legacy/Fieldset.tsx new file mode 100644 index 00000000..68a025f9 --- /dev/null +++ b/src/legacy/Fieldset.tsx @@ -0,0 +1,7 @@ +import { GroupBox, GroupBoxProps } from '../GroupBox/GroupBox'; + +/** @deprecated Use `GroupBoxProps` */ +export type FieldsetProps = GroupBoxProps; + +/** @deprecated Use `GroupBox` */ +export const Fieldset = GroupBox; From b3afb1ac89b39e68964b40516d8cfac3284670b1 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 08:03:46 -0400 Subject: [PATCH 13/29] docs(hourglass): categorize under Other --- src/Hourglass/Hourglass.mdx | 26 -------------------------- src/Hourglass/Hourglass.stories.tsx | 2 +- src/Hourglass/Hourglass.tsx | 4 +++- 3 files changed, 4 insertions(+), 28 deletions(-) delete mode 100644 src/Hourglass/Hourglass.mdx diff --git a/src/Hourglass/Hourglass.mdx b/src/Hourglass/Hourglass.mdx deleted file mode 100644 index e4ca81be..00000000 --- a/src/Hourglass/Hourglass.mdx +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Hourglass -menu: Components ---- - -import { Hourglass } from './Hourglass'; - -# Hourglass - -## Usage - - - - - -## API - -### Import - -``` -import { Hourglass } from 'react95' -``` - -### Props - - diff --git a/src/Hourglass/Hourglass.stories.tsx b/src/Hourglass/Hourglass.stories.tsx index 8657f775..14c73c31 100644 --- a/src/Hourglass/Hourglass.stories.tsx +++ b/src/Hourglass/Hourglass.stories.tsx @@ -9,7 +9,7 @@ const Wrapper = styled.div` `; export default { - title: 'Hourglass', + title: 'Other/Hourglass', component: Hourglass, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/Hourglass/Hourglass.tsx b/src/Hourglass/Hourglass.tsx index d20ae4f7..807bc28d 100644 --- a/src/Hourglass/Hourglass.tsx +++ b/src/Hourglass/Hourglass.tsx @@ -22,7 +22,7 @@ const StyledHourglass = styled.span` `; const Hourglass = forwardRef( - function Hourglass({ size = 30, ...otherProps }, ref) { + ({ size = 30, ...otherProps }, ref) => { return ( @@ -31,4 +31,6 @@ const Hourglass = forwardRef( } ); +Hourglass.displayName = 'Hourglass'; + export { Hourglass, HourglassProps }; From 9b7afa11efecf911f8bfa29c01f898edb113e24a Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 08:11:22 -0400 Subject: [PATCH 14/29] refactor(menulist): categorize under Controls, rename List to MenuList --- README.md | 12 +- docs/Getting-Started.stories.mdx | 12 +- src/AppBar/AppBar.stories.tsx | 20 ++-- src/Button/Button.stories.tsx | 20 ++-- src/Checkbox/Checkbox.stories.tsx | 20 ++-- src/Checkbox/Checkbox.tsx | 6 +- src/List/List.mdx | 69 ------------ src/List/List.spec.tsx | 47 -------- src/ListItem/ListItem.mdx | 104 ------------------ src/ListItem/ListItem.spec.tsx | 92 ---------------- src/MenuList/MenuList.spec.tsx | 47 ++++++++ .../MenuList.stories.tsx} | 69 ++++++------ src/{List/List.tsx => MenuList/MenuList.tsx} | 12 +- src/MenuList/MenuListItem.spec.tsx | 92 ++++++++++++++++ .../MenuListItem.tsx} | 78 ++++++------- src/Radio/Radio.stories.tsx | 24 ++-- src/Radio/Radio.tsx | 4 +- src/Separator/Separator.stories.tsx | 22 ++-- src/SwitchBase/SwitchBase.ts | 8 +- src/index.ts | 5 +- src/legacy/List.tsx | 7 ++ src/legacy/ListItem.tsx | 14 +++ 22 files changed, 320 insertions(+), 464 deletions(-) delete mode 100644 src/List/List.mdx delete mode 100644 src/List/List.spec.tsx delete mode 100644 src/ListItem/ListItem.mdx delete mode 100644 src/ListItem/ListItem.spec.tsx create mode 100644 src/MenuList/MenuList.spec.tsx rename src/{List/List.stories.tsx => MenuList/MenuList.stories.tsx} (50%) rename src/{List/List.tsx => MenuList/MenuList.tsx} (72%) create mode 100644 src/MenuList/MenuListItem.spec.tsx rename src/{ListItem/ListItem.tsx => MenuList/MenuListItem.tsx} (59%) create mode 100644 src/legacy/List.tsx create mode 100644 src/legacy/ListItem.tsx diff --git a/README.md b/README.md index 18821cb9..ebb747d9 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Apply style reset, wrap your app with ThemeProvider with theme of your choice... import React from 'react'; import { createGlobalStyle, ThemeProvider } from 'styled-components'; -import { List, ListItem, Separator, styleReset } from 'react95'; +import { MenuList, MenuListItem, Separator, styleReset } from 'react95'; // pick a theme of your choice import original from 'react95/dist/themes/original'; // original Windows95 font (optionally) @@ -72,12 +72,12 @@ const App = () => (
- - 🎤 Sing - 💃🏻 Dance + + 🎤 Sing + 💃🏻 Dance - 😴 Sleep - + 😴 Sleep +
); diff --git a/docs/Getting-Started.stories.mdx b/docs/Getting-Started.stories.mdx index bc243bd1..56cd9d8b 100644 --- a/docs/Getting-Started.stories.mdx +++ b/docs/Getting-Started.stories.mdx @@ -29,7 +29,7 @@ choice... and you are ready to go! 🚀 ```jsx import React from 'react'; -import { List, ListItem, Separator, styleReset } from 'react95'; +import { MenuList, MenuListItem, Separator, styleReset } from 'react95'; import { createGlobalStyle, ThemeProvider } from 'styled-components'; /* Pick a theme of your choice */ @@ -62,12 +62,12 @@ const App = () => (
- - 🎤 Sing - 💃🏻 Dance + + 🎤 Sing + 💃🏻 Dance - 😴 Sleep - + 😴 Sleep +
); diff --git a/src/AppBar/AppBar.stories.tsx b/src/AppBar/AppBar.stories.tsx index ecc73757..6e75a732 100644 --- a/src/AppBar/AppBar.stories.tsx +++ b/src/AppBar/AppBar.stories.tsx @@ -3,8 +3,8 @@ import React, { useState } from 'react'; import { AppBar, Button, - List, - ListItem, + MenuList, + MenuListItem, Separator, TextField, Toolbar @@ -43,7 +43,7 @@ export function Default() { Start {open && ( - setOpen(false)} > - + 👨‍💻 Profile - - + + 📁 My account - + - + 🔙 Logout - - + + )} diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx index 8d299d79..a952fc24 100644 --- a/src/Button/Button.stories.tsx +++ b/src/Button/Button.stories.tsx @@ -2,8 +2,8 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; import { Button, - List, - ListItem, + MenuList, + MenuListItem, ScrollView, Separator, Toolbar, @@ -135,7 +135,7 @@ export function Thin() { Share {open && ( - setOpen(false)} > - Copy link + Copy link - Facebook - Twitter - Instagram + Facebook + Twitter + Instagram - + MySpace - - + + )} diff --git a/src/Checkbox/Checkbox.stories.tsx b/src/Checkbox/Checkbox.stories.tsx index 75fb1734..b03326dc 100644 --- a/src/Checkbox/Checkbox.stories.tsx +++ b/src/Checkbox/Checkbox.stories.tsx @@ -5,8 +5,8 @@ import { ComponentMeta } from '@storybook/react'; import { Checkbox, GroupBox, - List, - ListItem, + MenuList, + MenuListItem, ScrollView, Separator } from 'react95'; @@ -240,8 +240,8 @@ Flat.story = { export function Menu() { return ( - - + + - - + + - + - + - - + + ); } diff --git a/src/Checkbox/Checkbox.tsx b/src/Checkbox/Checkbox.tsx index 0fd52f9f..c630dc9d 100644 --- a/src/Checkbox/Checkbox.tsx +++ b/src/Checkbox/Checkbox.tsx @@ -4,8 +4,8 @@ import styled, { css } from 'styled-components'; import { createHatchedBackground } from '../common'; import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled'; import { noOp } from '../common/utils'; +import { StyledMenuListItem } from '../MenuList/MenuList'; import { StyledScrollView } from '../ScrollView/ScrollView'; -import { StyledListItem } from '../ListItem/ListItem'; import { LabelText, size, @@ -129,7 +129,7 @@ const CheckmarkIcon = styled.span.attrs(() => ({ ? theme.checkmarkDisabled : theme.checkmark}; `} - ${StyledListItem}:hover & { + ${StyledMenuListItem}:hover & { ${({ $disabled, theme, variant }) => !$disabled && variant === 'menu' && @@ -170,7 +170,7 @@ const IndeterminateIcon = styled.span.attrs(() => ({ ${({ $disabled, theme, variant }) => variant === 'menu' && css` - ${StyledListItem}:hover & { + ${StyledMenuListItem}:hover & { ${createHatchedBackground({ mainColor: theme.materialTextInvert })} diff --git a/src/List/List.mdx b/src/List/List.mdx deleted file mode 100644 index b3d8546a..00000000 --- a/src/List/List.mdx +++ /dev/null @@ -1,69 +0,0 @@ ---- -name: List -menu: Components ---- - -import { List } from './List'; -import { ListItem } from '../ListItem/ListItem'; - -# List - -## Usage - -#### Default - - - - Photos - Videos - Other - - - -#### Inline - - - - - - 🌿 - - - - Tackle - Growl - Razor Leaf - - - -#### No shadow - - - - Photos - Videos - Other - - - -#### Full width - - - - Photos - Videos - Other - - - -## API - -### Import - -``` -import { List } from 'react95' -``` - -### Props - - diff --git a/src/List/List.spec.tsx b/src/List/List.spec.tsx deleted file mode 100644 index 48943d95..00000000 --- a/src/List/List.spec.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import React from 'react'; - -import { renderWithTheme } from '../../test/utils'; - -import { List } from './List'; - -describe('', () => { - it('renders List', () => { - const { container } = renderWithTheme(); - const list = container.firstElementChild; - - expect(list).toBeInTheDocument(); - }); - it('is an ul', () => { - const { container } = renderWithTheme(); - const list = container.firstElementChild; - - expect(list?.tagName).toBe('UL'); - }); - it('renders children', () => { - const textContent = 'Hi there!'; - const { getByText } = renderWithTheme( - - {textContent} - - ); - expect(getByText(textContent)).toBeInTheDocument(); - }); - - describe('prop: inline', () => { - it('renders inline', () => { - const { container } = renderWithTheme(); - const list = container.firstElementChild; - - expect(list).toHaveStyleRule('display', 'inline-flex'); - expect(list).toHaveStyleRule('align-items', 'center'); - }); - }); - describe('prop: fullWidth', () => { - it('has 100% width', () => { - const { container } = renderWithTheme(); - const list = container.firstElementChild; - - expect(list).toHaveStyleRule('width', '100%'); - }); - }); -}); diff --git a/src/ListItem/ListItem.mdx b/src/ListItem/ListItem.mdx deleted file mode 100644 index 7f398f56..00000000 --- a/src/ListItem/ListItem.mdx +++ /dev/null @@ -1,104 +0,0 @@ ---- -name: ListItem -menu: Components ---- - -import ListItem from './ListItem'; -import List from '../List/List'; -import Divider from '../Divider/Divider'; - -# ListItem - -## Usage - -#### Default - - - - Item 1 - Item 2 - Item 3 - - - -#### Disabled - - - - disabled - disabled - disabled - - - -#### Square - - - - - - 😎 - - - - - 🤖 - - - - - 🎁 - - - - - -#### Small size - - - - View - - Paste - Paste Shortcut - Undo Copy - - Properties - - - -#### Render as link - - - - Normal item - - - 🔗 - - Link! - - - - -#### Primary - - - - Item 1 - Item 2 - Item 3 - - - -## API - -### Import - -``` -import { ListItem } from 'react95' -``` - -### Props - - diff --git a/src/ListItem/ListItem.spec.tsx b/src/ListItem/ListItem.spec.tsx deleted file mode 100644 index 6adb7734..00000000 --- a/src/ListItem/ListItem.spec.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; - -import { renderWithTheme, theme } from '../../test/utils'; -import { blockSizes } from '../common/system'; -import { ListItem } from './ListItem'; - -const defaultSize = 'lg'; -describe('', () => { - it('renders ListItem', () => { - const { getByRole } = renderWithTheme(); - const listItem = getByRole('menuitem'); - expect(listItem).toBeInTheDocument(); - expect(listItem).not.toHaveAttribute('aria-disabled'); - }); - it('renders children', () => { - const textContent = 'Hi there!'; - const { getByText } = renderWithTheme( - - {textContent} - - ); - expect(getByText(textContent)).toBeInTheDocument(); - }); - it('should have a default role of menuitem', () => { - const { getByRole } = renderWithTheme(); - const listItem = getByRole('menuitem'); - expect(listItem).toHaveAttribute('role', 'menuitem'); - }); - - it('should render with custom role', () => { - const { getByRole } = renderWithTheme(); - const listItem = getByRole('option'); - expect(listItem).toHaveAttribute('role', 'option'); - }); - - // it('should have a tabIndex of -1 by default', () => { - // const { getByRole } = renderWithTheme(); - // const listItem = getByRole('menuitem'); - // expect(listItem).toHaveAttribute('tabIndex', '-1'); - // }); - describe('prop: disabled', () => { - it('should not trigger onClick callback', () => { - const clickHandler = jest.fn(); - const { getByRole } = renderWithTheme( - - ); - const listItem = getByRole('menuitem') as HTMLElement; - listItem.click(); - expect(clickHandler).not.toBeCalled(); - expect(listItem).toHaveAttribute('aria-disabled', 'true'); - }); - it('renders with disabled styles ', () => { - const { getByRole } = renderWithTheme(); - const listItem = getByRole('menuitem'); - expect(listItem).toHaveStyleRule('pointer-events', 'none'); - expect(listItem).toHaveStyleRule('color', theme.materialTextDisabled); - expect(listItem).toHaveStyleRule( - 'text-shadow', - `1px 1px ${theme.materialTextDisabledShadow}` - ); - }); - }); - describe('prop: onClick', () => { - it('should be called when clicked', () => { - const clickHandler = jest.fn(); - const { getByRole } = renderWithTheme( - - ); - const listItem = getByRole('menuitem') as HTMLElement; - listItem.click(); - expect(clickHandler).toHaveBeenCalledTimes(1); - }); - }); - describe('prop: square', () => { - it('should render square ListItem', () => { - const { getByRole } = renderWithTheme(); - const listItem = getByRole('menuitem'); - - expect(listItem).toHaveStyleRule('width', blockSizes[defaultSize]); - expect(listItem).toHaveStyleRule('height', blockSizes[defaultSize]); - }); - }); - describe('prop: size', () => { - it('should define ListItem height', () => { - const size = 'sm'; - const { getByRole } = renderWithTheme(); - const listItem = getByRole('menuitem'); - - expect(listItem).toHaveStyleRule('height', blockSizes[size]); - }); - }); -}); diff --git a/src/MenuList/MenuList.spec.tsx b/src/MenuList/MenuList.spec.tsx new file mode 100644 index 00000000..4bbae381 --- /dev/null +++ b/src/MenuList/MenuList.spec.tsx @@ -0,0 +1,47 @@ +import React from 'react'; + +import { renderWithTheme } from '../../test/utils'; + +import { MenuList } from './MenuList'; + +describe('', () => { + it('renders MenuList', () => { + const { container } = renderWithTheme(); + const menuList = container.firstElementChild; + + expect(menuList).toBeInTheDocument(); + }); + it('is an ul', () => { + const { container } = renderWithTheme(); + const menuList = container.firstElementChild; + + expect(menuList?.tagName).toBe('UL'); + }); + it('renders children', () => { + const textContent = 'Hi there!'; + const { getByText } = renderWithTheme( + + {textContent} + + ); + expect(getByText(textContent)).toBeInTheDocument(); + }); + + describe('prop: inline', () => { + it('renders inline', () => { + const { container } = renderWithTheme(); + const menuList = container.firstElementChild; + + expect(menuList).toHaveStyleRule('display', 'inline-flex'); + expect(menuList).toHaveStyleRule('align-items', 'center'); + }); + }); + describe('prop: fullWidth', () => { + it('has 100% width', () => { + const { container } = renderWithTheme(); + const menuList = container.firstElementChild; + + expect(menuList).toHaveStyleRule('width', '100%'); + }); + }); +}); diff --git a/src/List/List.stories.tsx b/src/MenuList/MenuList.stories.tsx similarity index 50% rename from src/List/List.stories.tsx rename to src/MenuList/MenuList.stories.tsx index 0bd48e94..05633a91 100644 --- a/src/List/List.stories.tsx +++ b/src/MenuList/MenuList.stories.tsx @@ -1,9 +1,8 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; +import { Handle, MenuList, MenuListItem, Separator } from 'react95'; import styled from 'styled-components'; -import { Handle, List, ListItem, Separator } from 'react95'; - const Wrapper = styled.div` padding: 5rem; background: ${({ theme }) => theme.desktopBackground}; @@ -15,18 +14,18 @@ const Wrapper = styled.div` `; export default { - title: 'List', - component: List, - subcomponents: { ListItem }, + title: 'Controls/MenuList', + component: MenuList, + subcomponents: { MenuListItem }, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { return ( <> - - Photos - + Photos + Link - - Other - - - + + Other + + + 🌿 - + - Tackle - Growl - Razor Leaf - - - + Tackle + Growl + Razor Leaf + + + View - + - Paste - Paste Shortcut - Undo Copy + Paste + Paste Shortcut + Undo Copy - Properties - - - + Properties + + + 😎 - - + + 🤖 - - + + 🎁 - - + + ); } diff --git a/src/List/List.tsx b/src/MenuList/MenuList.tsx similarity index 72% rename from src/List/List.tsx rename to src/MenuList/MenuList.tsx index 2a175c3f..9304c6e7 100644 --- a/src/List/List.tsx +++ b/src/MenuList/MenuList.tsx @@ -4,16 +4,16 @@ import styled from 'styled-components'; import { createBorderStyles, createBoxStyles } from '../common'; import { CommonStyledProps } from '../types'; -type ListProps = React.HTMLAttributes & { +type MenuListProps = React.HTMLAttributes & { fullWidth?: boolean; shadow?: boolean; inline?: boolean; } & CommonStyledProps; // TODO keyboard controls -const List = styled.ul.attrs(() => ({ +const MenuList = styled.ul.attrs(() => ({ role: 'menu' -}))` +}))` box-sizing: border-box; width: ${props => (props.fullWidth ? '100%' : 'auto')}; padding: 4px; @@ -29,4 +29,8 @@ const List = styled.ul.attrs(() => ({ position: relative; `; -export { List, ListProps }; +MenuList.displayName = 'MenuList'; + +export * from './MenuListItem'; + +export { MenuList, MenuListProps }; diff --git a/src/MenuList/MenuListItem.spec.tsx b/src/MenuList/MenuListItem.spec.tsx new file mode 100644 index 00000000..734d31d2 --- /dev/null +++ b/src/MenuList/MenuListItem.spec.tsx @@ -0,0 +1,92 @@ +import React from 'react'; + +import { renderWithTheme, theme } from '../../test/utils'; +import { blockSizes } from '../common/system'; +import { MenuListItem } from './MenuListItem'; + +const defaultSize = 'lg'; +describe('', () => { + it('renders MenuListItem', () => { + const { getByRole } = renderWithTheme(); + const menuListItem = getByRole('menuitem'); + expect(menuListItem).toBeInTheDocument(); + expect(menuListItem).not.toHaveAttribute('aria-disabled'); + }); + it('renders children', () => { + const textContent = 'Hi there!'; + const { getByText } = renderWithTheme( + + {textContent} + + ); + expect(getByText(textContent)).toBeInTheDocument(); + }); + it('should have a default role of menuitem', () => { + const { getByRole } = renderWithTheme(); + const menuListItem = getByRole('menuitem'); + expect(menuListItem).toHaveAttribute('role', 'menuitem'); + }); + + it('should render with custom role', () => { + const { getByRole } = renderWithTheme(); + const menuListItem = getByRole('option'); + expect(menuListItem).toHaveAttribute('role', 'option'); + }); + + // it('should have a tabIndex of -1 by default', () => { + // const { getByRole } = renderWithTheme(); + // const menuListItem = getByRole('menuitem'); + // expect(menuListItem).toHaveAttribute('tabIndex', '-1'); + // }); + describe('prop: disabled', () => { + it('should not trigger onClick callback', () => { + const clickHandler = jest.fn(); + const { getByRole } = renderWithTheme( + + ); + const menuListItem = getByRole('menuitem') as HTMLElement; + menuListItem.click(); + expect(clickHandler).not.toBeCalled(); + expect(menuListItem).toHaveAttribute('aria-disabled', 'true'); + }); + it('renders with disabled styles ', () => { + const { getByRole } = renderWithTheme(); + const menuListItem = getByRole('menuitem'); + expect(menuListItem).toHaveStyleRule('pointer-events', 'none'); + expect(menuListItem).toHaveStyleRule('color', theme.materialTextDisabled); + expect(menuListItem).toHaveStyleRule( + 'text-shadow', + `1px 1px ${theme.materialTextDisabledShadow}` + ); + }); + }); + describe('prop: onClick', () => { + it('should be called when clicked', () => { + const clickHandler = jest.fn(); + const { getByRole } = renderWithTheme( + + ); + const menuListItem = getByRole('menuitem') as HTMLElement; + menuListItem.click(); + expect(clickHandler).toHaveBeenCalledTimes(1); + }); + }); + describe('prop: square', () => { + it('should render square MenuListItem', () => { + const { getByRole } = renderWithTheme(); + const menuListItem = getByRole('menuitem'); + + expect(menuListItem).toHaveStyleRule('width', blockSizes[defaultSize]); + expect(menuListItem).toHaveStyleRule('height', blockSizes[defaultSize]); + }); + }); + describe('prop: size', () => { + it('should define MenuListItem height', () => { + const size = 'sm'; + const { getByRole } = renderWithTheme(); + const menuListItem = getByRole('menuitem'); + + expect(menuListItem).toHaveStyleRule('height', blockSizes[size]); + }); + }); +}); diff --git a/src/ListItem/ListItem.tsx b/src/MenuList/MenuListItem.tsx similarity index 59% rename from src/ListItem/ListItem.tsx rename to src/MenuList/MenuListItem.tsx index 31c47890..45c7e1f2 100644 --- a/src/ListItem/ListItem.tsx +++ b/src/MenuList/MenuListItem.tsx @@ -5,7 +5,7 @@ import { createDisabledTextStyles } from '../common'; import { blockSizes } from '../common/system'; import { CommonStyledProps, Sizes } from '../types'; -type ListItemProps = { +type MenuListItemProps = { disabled?: boolean; square?: boolean; primary?: boolean; @@ -13,7 +13,7 @@ type ListItemProps = { } & React.HTMLAttributes & CommonStyledProps; -export const StyledListItem = styled.li<{ +export const StyledMenuListItem = styled.li<{ $disabled?: boolean; square?: boolean; primary?: boolean; @@ -49,40 +49,44 @@ export const StyledListItem = styled.li<{ ${props => props.$disabled && createDisabledTextStyles()} `; -const ListItem = forwardRef(function ListItem( - { - size = 'lg', - disabled, - // tabIndex: tabIndexProp, - square, - children, - onClick, - primary, - ...otherProps - }, - ref -) { - // let tabIndex; - // if (!disabled) { - // tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1; - // } +const MenuListItem = forwardRef( + ( + { + size = 'lg', + disabled, + // tabIndex: tabIndexProp, + square, + children, + onClick, + primary, + ...otherProps + }, + ref + ) => { + // let tabIndex; + // if (!disabled) { + // tabIndex = tabIndexProp !== undefined ? tabIndexProp : -1; + // } - return ( - - {children} - - ); -}); + return ( + + {children} + + ); + } +); + +MenuListItem.displayName = 'MenuListItem'; -export { ListItem, ListItemProps }; +export { MenuListItem, MenuListItemProps }; diff --git a/src/Radio/Radio.stories.tsx b/src/Radio/Radio.stories.tsx index 25c4e36b..e4b37d08 100644 --- a/src/Radio/Radio.stories.tsx +++ b/src/Radio/Radio.stories.tsx @@ -2,8 +2,8 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; import { GroupBox, - List, - ListItem, + MenuList, + MenuListItem, Radio, ScrollView, Separator, @@ -157,8 +157,8 @@ export function Menu() { const { tool, color } = state; return ( - - + + - - + + - + - + - - + + - - + + ); } Menu.story = { diff --git a/src/Radio/Radio.tsx b/src/Radio/Radio.tsx index 9ff3ee0a..92ab2459 100644 --- a/src/Radio/Radio.tsx +++ b/src/Radio/Radio.tsx @@ -2,7 +2,7 @@ import React, { forwardRef } from 'react'; import styled, { css, CSSProperties } from 'styled-components'; import { createFlatBoxStyles } from '../common'; -import { StyledListItem } from '../ListItem/ListItem'; +import { StyledMenuListItem } from '../MenuList/MenuList'; import { StyledScrollView } from '../ScrollView/ScrollView'; import { LabelText, @@ -120,7 +120,7 @@ const Icon = styled.span.attrs(() => ({ : css` background: ${$disabled ? theme.checkmarkDisabled : theme.checkmark}; `} - ${StyledListItem}:hover & { + ${StyledMenuListItem}:hover & { ${({ $disabled, theme, variant }) => !$disabled && variant === 'menu' && diff --git a/src/Separator/Separator.stories.tsx b/src/Separator/Separator.stories.tsx index bb3178b2..030e95f9 100644 --- a/src/Separator/Separator.stories.tsx +++ b/src/Separator/Separator.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; import styled from 'styled-components'; -import { Separator, List, ListItem } from 'react95'; +import { MenuList, MenuListItem, Separator } from 'react95'; const Wrapper = styled.div` padding: 5rem; @@ -18,20 +18,20 @@ export default { export function Default() { return ( <> - - Item 1 + + Item 1 - Item 2 + Item 2 - Item 3 - - - Item 1 + Item 3 + + + Item 1 - Item 2 + Item 2 - Item 3 - + Item 3 + ); } diff --git a/src/SwitchBase/SwitchBase.ts b/src/SwitchBase/SwitchBase.ts index 9c7b7de9..885cdb72 100644 --- a/src/SwitchBase/SwitchBase.ts +++ b/src/SwitchBase/SwitchBase.ts @@ -1,7 +1,7 @@ import styled, { css } from 'styled-components'; -import { createDisabledTextStyles, focusOutline } from '../common'; -import { StyledListItem } from '../ListItem/ListItem'; +import { createDisabledTextStyles, focusOutline } from '../common'; +import { StyledMenuListItem } from '../MenuList/MenuList'; export const size = 20; @@ -26,11 +26,11 @@ export const StyledLabel = styled.label<{ $disabled: boolean }>` color: ${({ theme }) => theme.materialText}; ${props => props.$disabled && createDisabledTextStyles()} - ${StyledListItem} & { + ${StyledMenuListItem} & { margin: 0; height: 100%; } - ${StyledListItem}:hover & { + ${StyledMenuListItem}:hover & { ${({ $disabled, theme }) => !$disabled && css` diff --git a/src/index.ts b/src/index.ts index 13c523ac..300079ec 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,9 +14,8 @@ export * from './DatePicker/DatePicker'; export * from './GroupBox/GroupBox'; export * from './Handle/Handle'; export * from './Hourglass/Hourglass'; -export * from './List/List'; -export * from './ListItem/ListItem'; export * from './LoadingIndicator/LoadingIndicator'; +export * from './MenuList/MenuList'; export * from './Monitor/Monitor'; export * from './NumberField/NumberField'; export * from './Panel/Panel'; @@ -49,3 +48,5 @@ export * from './legacy/Cutout'; export * from './legacy/Desktop'; export * from './legacy/Divider'; export * from './legacy/Fieldset'; +export * from './legacy/List'; +export * from './legacy/ListItem'; diff --git a/src/legacy/List.tsx b/src/legacy/List.tsx new file mode 100644 index 00000000..55f863db --- /dev/null +++ b/src/legacy/List.tsx @@ -0,0 +1,7 @@ +import { MenuList, MenuListProps } from '../MenuList/MenuList'; + +/** @deprecated Use `MenuListProps` */ +export type ListProps = MenuListProps; + +/** @deprecated Use `MenuList` */ +export const List = MenuList; diff --git a/src/legacy/ListItem.tsx b/src/legacy/ListItem.tsx new file mode 100644 index 00000000..2eb6179f --- /dev/null +++ b/src/legacy/ListItem.tsx @@ -0,0 +1,14 @@ +import { + MenuListItem, + MenuListItemProps, + StyledMenuListItem +} from '../MenuList/MenuList'; + +/** @deprecated Use `MenuListItemProps` */ +export type ListItemProps = MenuListItemProps; + +/** @deprecated Use `MenuListItem` */ +export const ListItem = MenuListItem; + +/** @deprecated Use `StyledMenuListItem` */ +export const StyledListItem = StyledMenuListItem; From ad639ed1632a70a891a4a4722e5d753dfb82b112 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 09:11:03 -0400 Subject: [PATCH 15/29] docs(progressbar): categorize under Controls --- src/Progress/Progress.mdx | 49 ------ src/Progress/Progress.tsx | 156 ----------------- .../ProgressBar.spec.tsx} | 24 +-- .../ProgressBar.stories.tsx} | 14 +- src/ProgressBar/ProgressBar.tsx | 164 ++++++++++++++++++ src/index.ts | 3 +- src/legacy/Progress.tsx | 7 + 7 files changed, 194 insertions(+), 223 deletions(-) delete mode 100644 src/Progress/Progress.mdx delete mode 100644 src/Progress/Progress.tsx rename src/{Progress/Progress.spec.tsx => ProgressBar/ProgressBar.spec.tsx} (78%) rename src/{Progress/Progress.stories.tsx => ProgressBar/ProgressBar.stories.tsx} (83%) create mode 100644 src/ProgressBar/ProgressBar.tsx create mode 100644 src/legacy/Progress.tsx diff --git a/src/Progress/Progress.mdx b/src/Progress/Progress.mdx deleted file mode 100644 index 8965b107..00000000 --- a/src/Progress/Progress.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: Progress -menu: Components ---- - -import { Progress } from './Progress'; - -# Progress - -## Usage - -#### Default - - - {() => { - { - /* - @toDo - for some reason the value isn't being updated, check this later - */ - } - const [percent, setPercent] = React.useState(0); - React.useEffect(() => { - const timer = setInterval(() => { - setPercent(previousPercent => { - if (previousPercent === 100) { - return 0; - } - const diff = Math.random() * 10; - return Math.min(previousPercent + diff, 100); - }); - }, 1000); - return () => clearInterval(timer); - }, []); - return ; - }} - - -## API - -### Import - -``` -import { Progress } from 'react95' -``` - -### Props - - diff --git a/src/Progress/Progress.tsx b/src/Progress/Progress.tsx deleted file mode 100644 index 323c9532..00000000 --- a/src/Progress/Progress.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import React, { - forwardRef, - useCallback, - useEffect, - useRef, - useState -} from 'react'; -import styled, { css } from 'styled-components'; - -import { blockSizes } from '../common/system'; -import { StyledScrollView } from '../ScrollView/ScrollView'; -import { CommonStyledProps } from '../types'; - -type ProgressProps = { - hideValue?: boolean; - shadow?: boolean; - value?: number; - variant?: 'default' | 'tile'; -} & React.HTMLAttributes & - CommonStyledProps; - -const Wrapper = styled.div` - display: inline-block; - height: ${blockSizes.md}; - width: 100%; -`; -const ProgressCutout = styled(StyledScrollView)` - width: 100%; - height: 100%; - width: 100%; - position: relative; - text-align: center; - padding: 0; - overflow: hidden; - &:before { - z-index: 1; - } -`; -const commonBarStyles = css` - width: calc(100% - 4px); - height: calc(100% - 4px); - - display: flex; - align-items: center; - justify-content: space-around; -`; -const WhiteBar = styled.div` - position: relative; - top: 4px; - ${commonBarStyles} - background: ${({ theme }) => theme.canvas}; - color: #000; - margin-left: 2px; - margin-top: -2px; - color: ${({ theme }) => theme.materialText}; -`; - -const BlueBar = styled.div>>` - position: absolute; - top: 2px; - left: 2px; - ${commonBarStyles} - color: ${({ theme }) => theme.materialTextInvert}; - background: ${({ theme }) => theme.progress}; - clip-path: polygon( - 0 0, - ${({ value }) => value}% 0, - ${({ value }) => value}% 100%, - 0 100% - ); - transition: 0.4s linear clip-path; -`; - -const TilesWrapper = styled.div` - width: calc(100% - 6px); - height: calc(100% - 8px); - position: absolute; - left: 3px; - top: 4px; - box-sizing: border-box; - display: inline-flex; -`; -const tileWidth = 17; -const Tile = styled.span` - display: inline-block; - width: ${tileWidth}px; - box-sizing: border-box; - height: 100%; - background: ${({ theme }) => theme.progress}; - border-color: ${({ theme }) => theme.material}; - border-width: 0px 1px; - border-style: solid; -`; - -const Progress = forwardRef(function Progress( - { - hideValue = false, - shadow = true, - value = 0, - variant = 'default', - ...otherProps - }, - ref -) { - const displayValue = hideValue ? null : `${value}%`; - - const tilesWrapperRef = useRef(null); - const [tiles, setTiles] = useState([]); - - // TODO debounce this function - const updateTilesNumber = useCallback(() => { - if (!tilesWrapperRef.current) { - return; - } - const progressWidth = tilesWrapperRef.current.getBoundingClientRect().width; - const newTilesNumber = Math.round( - ((value / 100) * progressWidth) / tileWidth - ); - setTiles(Array.from({ length: newTilesNumber })); - }, [value]); - - useEffect(() => { - updateTilesNumber(); - - window.addEventListener('resize', updateTilesNumber); - return () => window.removeEventListener('resize', updateTilesNumber); - }, [updateTilesNumber]); - - return ( - - - {variant === 'default' ? ( - <> - {displayValue} - - {displayValue} - - - ) : ( - - {tiles.map((_, index) => ( - - ))} - - )} - - - ); -}); - -export { Progress, ProgressProps }; diff --git a/src/Progress/Progress.spec.tsx b/src/ProgressBar/ProgressBar.spec.tsx similarity index 78% rename from src/Progress/Progress.spec.tsx rename to src/ProgressBar/ProgressBar.spec.tsx index 3288e7a0..fb2c053d 100644 --- a/src/Progress/Progress.spec.tsx +++ b/src/ProgressBar/ProgressBar.spec.tsx @@ -1,24 +1,26 @@ import React from 'react'; import { renderWithTheme } from '../../test/utils'; -import { Progress } from './Progress'; +import { ProgressBar } from './ProgressBar'; -describe('', () => { - it('renders Progress', () => { +describe('', () => { + it('renders ProgressBar', () => { const value = 32; - const { getByRole } = renderWithTheme(); + const { getByRole } = renderWithTheme(); - const progress = getByRole('progressbar'); + const progressBar = getByRole('progressbar'); - expect(progress).toBeInTheDocument(); - expect(progress).toHaveAttribute('aria-valuenow', value.toString()); + expect(progressBar).toBeInTheDocument(); + expect(progressBar).toHaveAttribute('aria-valuenow', value.toString()); }); describe('prop: variant', () => { describe('variant: "default"', () => { it('displays current percentage value', () => { const value = 32; - const { queryByTestId } = renderWithTheme(); + const { queryByTestId } = renderWithTheme( + + ); expect(queryByTestId('defaultProgress1')?.textContent).toBe( `${value}%` @@ -38,7 +40,9 @@ describe('', () => { describe('variant: "tile"', () => { it('Renders "tile" progress', () => { - const { queryByTestId } = renderWithTheme(); + const { queryByTestId } = renderWithTheme( + + ); expect(queryByTestId('defaultProgress1')).not.toBeInTheDocument(); expect(queryByTestId('defaultProgress2')).not.toBeInTheDocument(); expect(queryByTestId('tileProgress')).toBeInTheDocument(); @@ -66,7 +70,7 @@ describe('', () => { it('renders progress bars, but does not show value', () => { const value = 32; const { queryByTestId } = renderWithTheme( - + ); expect(queryByTestId('defaultProgress1')).toBeInTheDocument(); expect(queryByTestId('defaultProgress2')).toBeInTheDocument(); diff --git a/src/Progress/Progress.stories.tsx b/src/ProgressBar/ProgressBar.stories.tsx similarity index 83% rename from src/Progress/Progress.stories.tsx rename to src/ProgressBar/ProgressBar.stories.tsx index 87e6a4b9..458cae26 100644 --- a/src/Progress/Progress.stories.tsx +++ b/src/ProgressBar/ProgressBar.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React, { useEffect, useState } from 'react'; -import { Progress } from 'react95'; +import { ProgressBar } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -9,10 +9,10 @@ const Wrapper = styled.div` `; export default { - title: 'Progress', - component: Progress, + title: 'Controls/ProgressBar', + component: ProgressBar, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { const [percent, setPercent] = useState(0); @@ -32,7 +32,7 @@ export function Default() { }; }, []); - return ; + return ; } Default.story = { @@ -57,7 +57,7 @@ export function Tile() { }; }, []); - return ; + return ; } Tile.story = { @@ -82,7 +82,7 @@ export function HideValue() { }; }, []); - return ; + return ; } HideValue.story = { diff --git a/src/ProgressBar/ProgressBar.tsx b/src/ProgressBar/ProgressBar.tsx new file mode 100644 index 00000000..349f8079 --- /dev/null +++ b/src/ProgressBar/ProgressBar.tsx @@ -0,0 +1,164 @@ +import React, { + forwardRef, + useCallback, + useEffect, + useRef, + useState +} from 'react'; +import styled, { css } from 'styled-components'; + +import { blockSizes } from '../common/system'; +import { StyledScrollView } from '../ScrollView/ScrollView'; +import { CommonStyledProps } from '../types'; + +type ProgressBarProps = { + hideValue?: boolean; + shadow?: boolean; + value?: number; + variant?: 'default' | 'tile'; +} & React.HTMLAttributes & + CommonStyledProps; + +const Wrapper = styled.div>>` + display: inline-block; + height: ${blockSizes.md}; + width: 100%; +`; + +const ProgressCutout = styled(StyledScrollView)< + Required> +>` + width: 100%; + height: 100%; + position: relative; + text-align: center; + padding: 0; + overflow: hidden; + &:before { + z-index: 1; + } +`; +const commonBarStyles = css` + width: calc(100% - 4px); + height: calc(100% - 4px); + + display: flex; + align-items: center; + justify-content: space-around; +`; +const WhiteBar = styled.div` + position: relative; + top: 4px; + ${commonBarStyles} + background: ${({ theme }) => theme.canvas}; + color: #000; + margin-left: 2px; + margin-top: -2px; + color: ${({ theme }) => theme.materialText}; +`; + +const BlueBar = styled.div>` + position: absolute; + top: 2px; + left: 2px; + ${commonBarStyles} + color: ${({ theme }) => theme.materialTextInvert}; + background: ${({ theme }) => theme.progress}; + clip-path: polygon( + 0 0, + ${({ value = 0 }) => value}% 0, + ${({ value = 0 }) => value}% 100%, + 0 100% + ); + transition: 0.4s linear clip-path; +`; + +const TilesWrapper = styled.div` + width: calc(100% - 6px); + height: calc(100% - 8px); + position: absolute; + left: 3px; + top: 4px; + box-sizing: border-box; + display: inline-flex; +`; +const tileWidth = 17; +const Tile = styled.span` + display: inline-block; + width: ${tileWidth}px; + box-sizing: border-box; + height: 100%; + background: ${({ theme }) => theme.progress}; + border-color: ${({ theme }) => theme.material}; + border-width: 0px 1px; + border-style: solid; +`; + +const ProgressBar = forwardRef( + ( + { + hideValue = false, + shadow = true, + value, + variant = 'default', + ...otherProps + }, + ref + ) => { + const displayValue = hideValue ? null : `${value}%`; + + const tilesWrapperRef = useRef(null); + const [tiles, setTiles] = useState([]); + + // TODO debounce this function + const updateTilesNumber = useCallback(() => { + if (!tilesWrapperRef.current || value === undefined) { + return; + } + const progressWidth = + tilesWrapperRef.current.getBoundingClientRect().width; + const newTilesNumber = Math.round( + ((value / 100) * progressWidth) / tileWidth + ); + setTiles(Array.from({ length: newTilesNumber })); + }, [value]); + + useEffect(() => { + updateTilesNumber(); + + window.addEventListener('resize', updateTilesNumber); + return () => window.removeEventListener('resize', updateTilesNumber); + }, [updateTilesNumber]); + + return ( + + + {variant === 'default' ? ( + <> + {displayValue} + + {displayValue} + + + ) : ( + + {tiles.map((_, index) => ( + + ))} + + )} + + + ); + } +); + +ProgressBar.displayName = 'ProgressBar'; + +export { ProgressBar, ProgressBarProps }; diff --git a/src/index.ts b/src/index.ts index 300079ec..7fbf45fa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,7 +19,7 @@ export * from './MenuList/MenuList'; export * from './Monitor/Monitor'; export * from './NumberField/NumberField'; export * from './Panel/Panel'; -export * from './Progress/Progress'; +export * from './ProgressBar/ProgressBar'; export * from './Radio/Radio'; export * from './ScrollView/ScrollView'; export * from './Select/Select'; @@ -50,3 +50,4 @@ export * from './legacy/Divider'; export * from './legacy/Fieldset'; export * from './legacy/List'; export * from './legacy/ListItem'; +export * from './legacy/Progress'; diff --git a/src/legacy/Progress.tsx b/src/legacy/Progress.tsx new file mode 100644 index 00000000..f72dc277 --- /dev/null +++ b/src/legacy/Progress.tsx @@ -0,0 +1,7 @@ +import { ProgressBar, ProgressBarProps } from '../ProgressBar/ProgressBar'; + +/** @deprecated Use `ProgressBarProps` */ +export type ProgressProps = ProgressBarProps; + +/** @deprecated Use `ProgressBar` */ +export const Progress = ProgressBar; From c5202e16afaa20e22b6b4a055972d4f1e9ad796e Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Thu, 4 Aug 2022 17:35:21 -0400 Subject: [PATCH 16/29] chore(loadingindicator): remove LoadingIndicator BREAKING CHANGE: LoadingIndicator was removed from the library. --- .../LoadingIndicator.spec.tsx | 26 --- .../LoadingIndicator.stories.tsx | 29 ---- src/LoadingIndicator/LoadingIndicator.tsx | 158 ------------------ src/index.ts | 1 - 4 files changed, 214 deletions(-) delete mode 100644 src/LoadingIndicator/LoadingIndicator.spec.tsx delete mode 100644 src/LoadingIndicator/LoadingIndicator.stories.tsx delete mode 100644 src/LoadingIndicator/LoadingIndicator.tsx diff --git a/src/LoadingIndicator/LoadingIndicator.spec.tsx b/src/LoadingIndicator/LoadingIndicator.spec.tsx deleted file mode 100644 index 929ec4d4..00000000 --- a/src/LoadingIndicator/LoadingIndicator.spec.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; - -import { renderWithTheme } from '../../test/utils'; -import { LoadingIndicator } from './LoadingIndicator'; - -describe('', () => { - it('renders LoadingIndicator', () => { - const { getByRole } = renderWithTheme(); - - const progress = getByRole('progressbar'); - - expect(progress).toBeInTheDocument(); - }); - - describe('prop: isLoading', () => { - it('when set to false, does not display progress bars', () => { - const { rerender, queryByTestId } = renderWithTheme(); - - expect(queryByTestId('loading-wrapper')).not.toBeNull(); - - rerender(); - - expect(queryByTestId('loading-wrapper')).toBeNull(); - }); - }); -}); diff --git a/src/LoadingIndicator/LoadingIndicator.stories.tsx b/src/LoadingIndicator/LoadingIndicator.stories.tsx deleted file mode 100644 index f200813a..00000000 --- a/src/LoadingIndicator/LoadingIndicator.stories.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { ComponentMeta } from '@storybook/react'; -import React from 'react'; -import styled from 'styled-components'; - -import { LoadingIndicator } from 'react95'; - -const Wrapper = styled.div` - background: ${({ theme }) => theme.material}; - padding: 5rem; -`; - -export default { - title: 'LoadingIndicator', - component: LoadingIndicator, - decorators: [story => {story()}] -} as ComponentMeta; - -export function Default() { - return ( - <> -

Loading...

- - - ); -} - -Default.story = { - name: 'default' -}; diff --git a/src/LoadingIndicator/LoadingIndicator.tsx b/src/LoadingIndicator/LoadingIndicator.tsx deleted file mode 100644 index d280f012..00000000 --- a/src/LoadingIndicator/LoadingIndicator.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import React, { forwardRef } from 'react'; -import styled, { css, keyframes } from 'styled-components'; -import { StyledScrollView } from '../ScrollView/ScrollView'; -import { CommonStyledProps } from '../types'; - -type LoadingIndicatorProps = { - isLoading?: boolean; - shadow?: boolean; -} & React.HTMLAttributes & - CommonStyledProps; - -const Wrapper = styled.div` - display: inline-block; - height: 15px; - width: 100%; -`; -const ProgressCutout = styled(StyledScrollView)` - width: 100%; - height: 100%; - width: 100%; - position: relative; - padding: 0; - overflow: hidden; -`; - -// animations taken from https://material.io/develop/web/ Linear Progress -const primaryTranslate = keyframes` - 0% { - transform: translateX(0); - } - 20% { - animation-timing-function: cubic-bezier(0.5, 0, 0.701732, 0.495819); - transform: translateX(0); - } - 59.15% { - animation-timing-function: cubic-bezier(0.302435, 0.381352, 0.55, 0.956352); - transform: translateX(83.67142%); - } - 100% { - transform: translateX(200.611057%); - } -`; -const primaryScale = keyframes` -0% { - transform: scaleX(0.08); - } - 36.65% { - animation-timing-function: cubic-bezier(0.334731, 0.12482, 0.785844, 1); - transform: scaleX(0.08); - } - 69.15% { - animation-timing-function: cubic-bezier(0.06, 0.11, 0.6, 1); - transform: scaleX(0.661479); - } - 100% { - transform: scaleX(0.08); - } -`; -const secondaryTranslate = keyframes` - 0% { - animation-timing-function: cubic-bezier(0.15, 0, 0.515058, 0.409685); - transform: translateX(0); - } - 25% { - animation-timing-function: cubic-bezier(0.31033, 0.284058, 0.8, 0.733712); - transform: translateX(37.651913%); - } - 48.35% { - animation-timing-function: cubic-bezier(0.4, 0.627035, 0.6, 0.902026); - transform: translateX(84.386165%); - } - 100% { - transform: translateX(160.277782%); - } -`; -const secondaryScale = keyframes` - 0% { - animation-timing-function: cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971); - transform: scaleX(0.08); - } - 19.15% { - animation-timing-function: cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315); - transform: scaleX(0.457104); - } - 44.15% { - animation-timing-function: cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179); - transform: scaleX(0.72796); - } - 100% { - transform: scaleX(0.08); - } -`; -const sharedIndeterminateStyles = css` - height: 100%; - width: 100%; - position: absolute; - transform-origin: top left; - transform: scaleX(0); -`; -const sharedIndeterminateInnerStyles = css` - height: 100%; - width: 100%; - display: inline-block; - background: ${({ theme }) => theme.progress}; - position: absolute; -`; -const IndeterminateWrapper = styled.div` - position: relative; - top: 2px; - left: 2px; - width: calc(100% - 4px); - height: calc(100% - 4px); - overflow: hidden; -`; -const IndeterminatePrimary = styled.div` - ${sharedIndeterminateStyles} - left: -145.166611%; - animation: ${primaryTranslate} 2s infinite linear; -`; -const IndeterminatePrimaryInner = styled.span` - ${sharedIndeterminateInnerStyles} - animation: ${primaryScale} 2s infinite linear; -`; -const IndeterminateSecondary = styled.div` - ${sharedIndeterminateStyles} - left: -54.888891%; - animation: ${secondaryTranslate} 2s infinite linear; -`; -const IndeterminateSecondaryInner = styled.span` - ${sharedIndeterminateInnerStyles} - animation: ${secondaryScale} 2s infinite linear; -`; - -const LoadingIndicator = forwardRef( - function LoadingIndicator( - { isLoading = true, shadow = false, ...otherProps }, - ref - ) { - return ( - - - {isLoading && ( - - - - - - - - - )} - - - ); - } -); - -export { LoadingIndicator, LoadingIndicatorProps }; diff --git a/src/index.ts b/src/index.ts index 7fbf45fa..83beff48 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,6 @@ export * from './DatePicker/DatePicker'; export * from './GroupBox/GroupBox'; export * from './Handle/Handle'; export * from './Hourglass/Hourglass'; -export * from './LoadingIndicator/LoadingIndicator'; export * from './MenuList/MenuList'; export * from './Monitor/Monitor'; export * from './NumberField/NumberField'; From 6ee09f1250f634acc44eb0b0e0090ef57eb911c3 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 09:36:08 -0400 Subject: [PATCH 17/29] refactor(numberinput): categorize under Controls, rename from NumberField to NumberInput --- src/DatePicker/DatePicker.tsx | 4 +- src/NumberField/NumberField.mdx | 78 ------------------- .../NumberInput.spec.tsx} | 30 +++---- .../NumberInput.stories.tsx} | 22 +++--- .../NumberInput.tsx} | 23 +++--- src/Tabs/Tabs.mdx | 4 +- src/Tabs/Tabs.stories.tsx | 4 +- src/index.ts | 3 +- src/legacy/NumberField.tsx | 7 ++ 9 files changed, 53 insertions(+), 122 deletions(-) delete mode 100644 src/NumberField/NumberField.mdx rename src/{NumberField/NumberField.spec.tsx => NumberInput/NumberInput.spec.tsx} (86%) rename src/{NumberField/NumberField.stories.tsx => NumberInput/NumberInput.stories.tsx} (64%) rename src/{NumberField/NumberField.tsx => NumberInput/NumberInput.tsx} (91%) create mode 100644 src/legacy/NumberField.tsx diff --git a/src/DatePicker/DatePicker.tsx b/src/DatePicker/DatePicker.tsx index a49dcbc8..b7ec857b 100644 --- a/src/DatePicker/DatePicker.tsx +++ b/src/DatePicker/DatePicker.tsx @@ -2,7 +2,7 @@ import React, { forwardRef, useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; import { Button } from '../Button/Button'; -import { NumberField } from '../NumberField/NumberField'; +import { NumberInput } from '../NumberInput/NumberInput'; import { ScrollView } from '../ScrollView/ScrollView'; import { Select } from '../Select/Select'; import { SelectChangeEvent } from '../Select/Select.types'; @@ -175,7 +175,7 @@ const DatePicker = forwardRef( width={128} menuMaxHeight={200} /> - + diff --git a/src/NumberField/NumberField.mdx b/src/NumberField/NumberField.mdx deleted file mode 100644 index 5f1659be..00000000 --- a/src/NumberField/NumberField.mdx +++ /dev/null @@ -1,78 +0,0 @@ ---- -name: NumberField -menu: Components ---- - -import { NumberField } from './NumberField'; -import { ScrollView } from '../ScrollView/ScrollView'; - -# NumberField - -## Usage - -#### Default - - - console.log(value)} /> - - -#### Fixed width - - - console.log(value)} /> - - -#### Disabled - - - console.log(value)} /> - - -#### Disabled keyboard input - - - console.log(value)} - /> - - -#### No shadow - - - console.log(value)} - /> - - -#### Flat - - - -

- When you want to use NumberField on a light background (like scrollable - content), just use the flat variant: -

- console.log(value)} - /> -
-
- -## API - -### Import - -``` -import { NumberField } from 'react95' -``` - -### Props - - diff --git a/src/NumberField/NumberField.spec.tsx b/src/NumberInput/NumberInput.spec.tsx similarity index 86% rename from src/NumberField/NumberField.spec.tsx rename to src/NumberInput/NumberInput.spec.tsx index ee3ee61a..486d193f 100644 --- a/src/NumberField/NumberField.spec.tsx +++ b/src/NumberInput/NumberInput.spec.tsx @@ -2,15 +2,15 @@ import { fireEvent } from '@testing-library/react'; import React from 'react'; import { renderWithTheme } from '../../test/utils'; -import { NumberField } from './NumberField'; +import { NumberInput } from './NumberInput'; // TODO: should we pass number or string to callbacks? -describe('', () => { +describe('', () => { it('should call onChange on spin buttons click', () => { const handleChange = jest.fn(); const { getByTestId } = renderWithTheme( - + ); const spinButton = getByTestId('increment'); spinButton.click(); @@ -21,7 +21,7 @@ describe('', () => { it('should call onChange on blur after keyboard input', () => { const handleChange = jest.fn(); const { container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; input.focus(); @@ -39,7 +39,7 @@ describe('', () => { const handleChange = jest.fn(); const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const incrementButton = getByTestId('increment'); @@ -55,7 +55,7 @@ describe('', () => { it('should give correct result after user changes input value and then clicks increment button', () => { const handleChange = jest.fn(); const { container, getByTestId } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const incrementButton = getByTestId('increment'); @@ -68,7 +68,7 @@ describe('', () => { it('should reach max value', () => { const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const incrementButton = getByTestId('increment'); @@ -79,7 +79,7 @@ describe('', () => { it('should reach min value', () => { const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const decrementButton = getByTestId('decrement'); @@ -91,7 +91,7 @@ describe('', () => { describe('prop: step', () => { it('should be 1 by default', () => { const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const incrementButton = getByTestId('increment'); @@ -102,7 +102,7 @@ describe('', () => { it('should change value by specified step', () => { const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const decrementButton = getByTestId('decrement'); @@ -113,7 +113,7 @@ describe('', () => { it('should handle decimal step', () => { const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const decrementButton = getByTestId('decrement'); @@ -126,7 +126,7 @@ describe('', () => { describe('prop: disabled', () => { it('should render disabled', () => { const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const incrementButton = getByTestId('increment'); @@ -139,7 +139,7 @@ describe('', () => { it('should not react to button clicks', () => { const { getByTestId, container } = renderWithTheme( - + ); const input = container.querySelector('input') as HTMLInputElement; const incrementButton = getByTestId('increment'); @@ -156,7 +156,7 @@ describe('', () => { describe('prop: width', () => { it('should render component of specified width', () => { const { container } = renderWithTheme( - + ); expect( getComputedStyle(container.firstElementChild as HTMLInputElement).width @@ -165,7 +165,7 @@ describe('', () => { it('should handle %', () => { const { container } = renderWithTheme( - + ); expect( getComputedStyle(container.firstElementChild as HTMLInputElement).width diff --git a/src/NumberField/NumberField.stories.tsx b/src/NumberInput/NumberInput.stories.tsx similarity index 64% rename from src/NumberField/NumberField.stories.tsx rename to src/NumberInput/NumberInput.stories.tsx index e3678880..d9f089c6 100644 --- a/src/NumberField/NumberField.stories.tsx +++ b/src/NumberInput/NumberInput.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { NumberField, ScrollView } from 'react95'; +import { ScrollView, NumberInput } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -21,19 +21,19 @@ const Wrapper = styled.div` `; export default { - title: 'NumberField', - component: NumberField, + title: 'Controls/NumberInput', + component: NumberInput, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { return ( <> - +
- +
- + ); } @@ -46,10 +46,10 @@ export function Flat() { return (

- When you want to use NumberField on a light background (like scrollable + When you want to use NumberInput on a light background (like scrollable content), just use the flat variant:

-
- +
- +
); } diff --git a/src/NumberField/NumberField.tsx b/src/NumberInput/NumberInput.tsx similarity index 91% rename from src/NumberField/NumberField.tsx rename to src/NumberInput/NumberInput.tsx index 76931564..3e85b8a6 100644 --- a/src/NumberField/NumberField.tsx +++ b/src/NumberInput/NumberInput.tsx @@ -8,7 +8,7 @@ import { clamp, getSize } from '../common/utils'; import { TextField } from '../TextField/TextField'; import { CommonStyledProps } from '../types'; -type NumberFieldProps = { +type NumberInputProps = { className?: string; defaultValue?: number; disabled?: boolean; @@ -22,12 +22,12 @@ type NumberFieldProps = { width?: string | number; } & CommonStyledProps; -const StyledNumberFieldWrapper = styled.div` +const StyledNumberInputWrapper = styled.div` display: inline-flex; align-items: center; `; -const StyledButton = styled(Button)>` +const StyledButton = styled(Button)>` width: 30px; padding: 0; flex-shrink: 0; @@ -49,7 +49,7 @@ const StyledButton = styled(Button)>` `} `; -const StyledButtonWrapper = styled.div>` +const StyledButtonWrapper = styled.div>` display: flex; flex-direction: column; flex-wrap: nowrap; @@ -96,9 +96,8 @@ const StyledButtonIcon = styled.span<{ invert?: boolean }>` `} } `; - -const NumberField = forwardRef( - function NumberField( +const NumberInput = forwardRef( + ( { className, defaultValue, @@ -113,7 +112,7 @@ const NumberField = forwardRef( width }, ref - ) { + ) => { const [valueDerived, setValueState] = useControlledOrUncontrolled({ value, defaultValue @@ -157,7 +156,7 @@ const NumberField = forwardRef( }, [handleClick, step]); return ( - ( - + ); } ); -export { NumberField, NumberFieldProps }; +NumberInput.displayName = 'NumberInput'; + +export { NumberInput, NumberInputProps }; diff --git a/src/Tabs/Tabs.mdx b/src/Tabs/Tabs.mdx index c39489aa..40e00141 100644 --- a/src/Tabs/Tabs.mdx +++ b/src/Tabs/Tabs.mdx @@ -9,7 +9,7 @@ import { TabBody } from '../TabBody/TabBody'; import Fieldset from '../Fieldset/Fieldset'; import Window from '../Window/Window'; import WindowHeader from '../WindowHeader/WindowHeader'; -import { NumberField } from '../NumberField/NumberField'; +import { NumberInput } from '../NumberInput/NumberInput'; import Checkbox from '../Checkbox/Checkbox'; import WindowContent from '../WindowContent/WindowContent'; @@ -64,7 +64,7 @@ import WindowContent from '../WindowContent/WindowContent';
Amount:
-
Amount:
- +
Date: Sun, 31 Jul 2022 09:45:38 -0400 Subject: [PATCH 18/29] docs(tabs): categorize under Controls This also moves TabBody and Tab inside Tabs --- src/{Tab => Tabs}/Tab.spec.tsx | 0 src/{Tab => Tabs}/Tab.tsx | 37 +++++---- src/{TabBody => Tabs}/TabBody.spec.tsx | 0 src/{TabBody => Tabs}/TabBody.tsx | 21 ++--- src/Tabs/Tabs.mdx | 106 ------------------------- src/Tabs/Tabs.stories.tsx | 2 +- src/Tabs/Tabs.tsx | 82 ++++++++++--------- src/index.ts | 2 - 8 files changed, 78 insertions(+), 172 deletions(-) rename src/{Tab => Tabs}/Tab.spec.tsx (100%) rename src/{Tab => Tabs}/Tab.tsx (79%) rename src/{TabBody => Tabs}/TabBody.spec.tsx (100%) rename src/{TabBody => Tabs}/TabBody.tsx (67%) delete mode 100644 src/Tabs/Tabs.mdx diff --git a/src/Tab/Tab.spec.tsx b/src/Tabs/Tab.spec.tsx similarity index 100% rename from src/Tab/Tab.spec.tsx rename to src/Tabs/Tab.spec.tsx diff --git a/src/Tab/Tab.tsx b/src/Tabs/Tab.tsx similarity index 79% rename from src/Tab/Tab.tsx rename to src/Tabs/Tab.tsx index 935d7232..17f0666f 100644 --- a/src/Tab/Tab.tsx +++ b/src/Tabs/Tab.tsx @@ -69,22 +69,25 @@ const StyledTab = styled.button` } `; -const Tab = forwardRef(function Tab( - { value, onClick, selected = false, children, ...otherProps }, - ref -) { - return ( - ) => onClick?.(e, value)} - ref={ref} - role='tab' - {...otherProps} - > - {children} - - ); -}); +const Tab = forwardRef( + ({ value, onClick, selected = false, children, ...otherProps }, ref) => { + return ( + ) => + onClick?.(e, value) + } + ref={ref} + role='tab' + {...otherProps} + > + {children} + + ); + } +); + +Tab.displayName = 'Tab'; export { Tab, TabProps }; diff --git a/src/TabBody/TabBody.spec.tsx b/src/Tabs/TabBody.spec.tsx similarity index 100% rename from src/TabBody/TabBody.spec.tsx rename to src/Tabs/TabBody.spec.tsx diff --git a/src/TabBody/TabBody.tsx b/src/Tabs/TabBody.tsx similarity index 67% rename from src/TabBody/TabBody.tsx rename to src/Tabs/TabBody.tsx index c27da639..1afb4f54 100644 --- a/src/TabBody/TabBody.tsx +++ b/src/Tabs/TabBody.tsx @@ -18,15 +18,16 @@ const StyledTabBody = styled.div` padding: 16px; font-size: 1rem; `; -const TabBody = forwardRef(function TabBody( - { children, ...otherProps }, - ref -) { - return ( - - {children} - - ); -}); +const TabBody = forwardRef( + ({ children, ...otherProps }, ref) => { + return ( + + {children} + + ); + } +); + +TabBody.displayName = 'TabBody'; export { TabBody, TabBodyProps }; diff --git a/src/Tabs/Tabs.mdx b/src/Tabs/Tabs.mdx deleted file mode 100644 index 40e00141..00000000 --- a/src/Tabs/Tabs.mdx +++ /dev/null @@ -1,106 +0,0 @@ ---- -name: Tabs -menu: Components ---- - -import { Tabs } from './Tabs'; -import { Tab } from '../Tab/Tab'; -import { TabBody } from '../TabBody/TabBody'; -import Fieldset from '../Fieldset/Fieldset'; -import Window from '../Window/Window'; -import WindowHeader from '../WindowHeader/WindowHeader'; -import { NumberInput } from '../NumberInput/NumberInput'; -import Checkbox from '../Checkbox/Checkbox'; -import WindowContent from '../WindowContent/WindowContent'; - -# Tabs - -## Usage - - - {() => { - const [activeTab, setActiveTab] = React.useState(0); - const handleChange = (event, value) => { - setActiveTab(value); - }; - const a11yProps = index => ({ - id: `tab-${index}`, - 'aria-controls': `tabpanel-${index}` - }); - const TabPanel = ({ children, value, activeTab, ...other }) => { - return ( - - ); - }; - return ( - - - - 👗 - - store.exe - - - - - Shoes - - - Accesories - - - Clothing - - - - -
-
Amount:
- null} - /> - null} - defaultChecked - /> -
-
- -
Accesories stuff here
-
- -
Clothing stuff here
-
-
-
-
- ); - }} -
- -## API - -### Import - -``` -import { Tabs } from 'react95' -``` - -### Props - - diff --git a/src/Tabs/Tabs.stories.tsx b/src/Tabs/Tabs.stories.tsx index 5c7d68f9..26a47afb 100644 --- a/src/Tabs/Tabs.stories.tsx +++ b/src/Tabs/Tabs.stories.tsx @@ -20,7 +20,7 @@ const Wrapper = styled.div` `; export default { - title: 'Tabs', + title: 'Controls/Tabs', component: Tabs, subcomponents: { Tab, TabBody }, decorators: [story => {story()}] diff --git a/src/Tabs/Tabs.tsx b/src/Tabs/Tabs.tsx index bc69f111..b0c95582 100644 --- a/src/Tabs/Tabs.tsx +++ b/src/Tabs/Tabs.tsx @@ -2,8 +2,8 @@ import React, { forwardRef, useMemo } from 'react'; import styled from 'styled-components'; import { noOp } from '../common/utils'; -import { TabProps } from '../Tab/Tab'; import { CommonStyledProps } from '../types'; +import { TabProps } from './Tab'; type TabsProps = { value?: TabProps['value']; @@ -56,45 +56,55 @@ function splitToChunks(array: T[], parts: number) { return result; } -const Tabs = forwardRef(function Tabs( - { value, onChange = noOp, children, rows = 1, ...otherProps }, - ref -) { - // split tabs into equal rows and assign key to each row - const tabRowsToRender = useMemo(() => { - const childrenWithProps = - React.Children.map(children, child => { - if (!React.isValidElement(child)) { - return null; - } - const tabProps = { - selected: child.props.value === value, - onClick: onChange - }; - return React.cloneElement(child, tabProps); - }) ?? []; +const Tabs = forwardRef( + ({ value, onChange = noOp, children, rows = 1, ...otherProps }, ref) => { + // split tabs into equal rows and assign key to each row + const tabRowsToRender = useMemo(() => { + const childrenWithProps = + React.Children.map(children, child => { + if (!React.isValidElement(child)) { + return null; + } + const tabProps = { + selected: child.props.value === value, + onClick: onChange + }; + return React.cloneElement(child, tabProps); + }) ?? []; - const tabRows = splitToChunks(childrenWithProps, rows).map((tabs, i) => ({ - key: i, - tabs - })); + const tabRows = splitToChunks(childrenWithProps, rows).map((tabs, i) => ({ + key: i, + tabs + })); - // move row containing currently selected tab to the bottom - const currentlySelectedRowIndex = tabRows.findIndex(tabRow => - tabRow.tabs.some(tab => tab.props.selected) + // move row containing currently selected tab to the bottom + const currentlySelectedRowIndex = tabRows.findIndex(tabRow => + tabRow.tabs.some(tab => tab.props.selected) + ); + tabRows.push(tabRows.splice(currentlySelectedRowIndex, 1)[0]); + + return tabRows; + }, [children, onChange, rows, value]); + + return ( + 1} + role='tablist' + ref={ref} + > + {tabRowsToRender.map(row => ( + {row.tabs} + ))} + ); - tabRows.push(tabRows.splice(currentlySelectedRowIndex, 1)[0]); + } +); + +Tabs.displayName = 'Tabs'; - return tabRows; - }, [children, onChange, rows, value]); +export * from './Tab'; - return ( - 1} role='tablist' ref={ref}> - {tabRowsToRender.map(row => ( - {row.tabs} - ))} - - ); -}); +export * from './TabBody'; export { Tabs, TabsProps }; diff --git a/src/index.ts b/src/index.ts index 10c2d56e..93e0ea68 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,8 +24,6 @@ export * from './ScrollView/ScrollView'; export * from './Select/Select'; export * from './Separator/Separator'; export * from './Slider/Slider'; -export * from './Tab/Tab'; -export * from './TabBody/TabBody'; export * from './Table/Table'; export * from './TableBody/TableBody'; export * from './TableDataCell/TableDataCell'; From d8f307d265ce8ee67ba9a5e6ce6d9a11d7a4272d Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 14:02:25 -0400 Subject: [PATCH 19/29] refactor(frame): categorize under Layout, rename Panel to Frame This also adds the field variant and refactors createBorderStyles to implement all border styles. --- src/Button/Button.tsx | 9 +- src/Counter/Counter.stories.tsx | 6 +- src/Counter/Counter.tsx | 4 +- src/Frame/Frame.spec.tsx | 41 ++++ .../Frame.stories.tsx} | 42 ++-- src/Frame/Frame.tsx | 58 ++++++ src/MenuList/MenuList.tsx | 2 +- src/Panel/Panel.spec.tsx | 41 ---- src/Panel/Panel.tsx | 52 ----- src/TableHeadCell/TableHeadCell.tsx | 2 +- src/Window/Window.stories.tsx | 6 +- src/Window/Window.tsx | 2 +- src/common/index.ts | 193 +++++++++++++----- src/index.ts | 3 +- src/legacy/Panel.tsx | 7 + 15 files changed, 286 insertions(+), 182 deletions(-) create mode 100644 src/Frame/Frame.spec.tsx rename src/{Panel/Panel.stories.tsx => Frame/Frame.stories.tsx} (54%) create mode 100644 src/Frame/Frame.tsx delete mode 100644 src/Panel/Panel.spec.tsx delete mode 100644 src/Panel/Panel.tsx create mode 100644 src/legacy/Panel.tsx diff --git a/src/Button/Button.tsx b/src/Button/Button.tsx index df0a9186..6cbf6aa0 100644 --- a/src/Button/Button.tsx +++ b/src/Button/Button.tsx @@ -6,7 +6,6 @@ import { createDisabledTextStyles, createFlatBoxStyles, createHatchedBackground, - createWellBorderStyles, focusOutline } from '../common'; import { blockSizes } from '../common/system'; @@ -107,12 +106,14 @@ export const StyledButton = styled.button` border: 2px solid transparent; &:hover, &:focus { - ${!disabled && !active && createWellBorderStyles(false)} + ${!disabled && + !active && + createBorderStyles({ style: 'buttonThin' })} } &:active { - ${!disabled && createWellBorderStyles(true)} + ${!disabled && createBorderStyles({ style: 'buttonThinPressed' })} } - ${active && createWellBorderStyles(true)} + ${active && createBorderStyles({ style: 'buttonThinPressed' })} ${disabled && createDisabledTextStyles()} ` : css` diff --git a/src/Counter/Counter.stories.tsx b/src/Counter/Counter.stories.tsx index 7890db93..a7553247 100644 --- a/src/Counter/Counter.stories.tsx +++ b/src/Counter/Counter.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; -import { Button, Counter, Panel } from 'react95'; +import { Button, Counter, Frame } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -29,14 +29,14 @@ export function Default() { const [count, setCount] = useState(13); const handleClick = () => setCount(count + 1); return ( - +
-
+ ); } diff --git a/src/Counter/Counter.tsx b/src/Counter/Counter.tsx index 55dfec81..7c2b5c2f 100644 --- a/src/Counter/Counter.tsx +++ b/src/Counter/Counter.tsx @@ -1,7 +1,7 @@ import React, { forwardRef, useMemo } from 'react'; import styled from 'styled-components'; -import { createWellBorderStyles } from '../common'; +import { createBorderStyles } from '../common'; import { CommonStyledProps, Sizes } from '../types'; import { Digit } from './Digit'; @@ -13,7 +13,7 @@ type CounterProps = { CommonStyledProps; const CounterWrapper = styled.div` - ${createWellBorderStyles(true)} + ${createBorderStyles({ style: 'status' })} display: inline-flex; background: #000000; `; diff --git a/src/Frame/Frame.spec.tsx b/src/Frame/Frame.spec.tsx new file mode 100644 index 00000000..2cabe125 --- /dev/null +++ b/src/Frame/Frame.spec.tsx @@ -0,0 +1,41 @@ +import { render } from '@testing-library/react'; +import React from 'react'; + +import { Frame } from './Frame'; + +describe('', () => { + it('should render frame', () => { + const { container } = render(); + const frame = container.firstElementChild; + + expect(frame).toBeInTheDocument(); + }); + + it('should render custom styles', () => { + const { container } = render( + + ); + const frame = container.firstElementChild; + + expect(frame).toHaveAttribute('style', 'background-color: papayawhip;'); + }); + + it('should render children', async () => { + const { findByText } = render( + + Cool frame + + ); + const content = await findByText(/cool frame/i); + + expect(content).toBeInTheDocument(); + }); + + it('should render custom props', () => { + const customProps = { title: 'frame' }; + const { container } = render(); + const frame = container.firstElementChild; + + expect(frame).toHaveAttribute('title', 'frame'); + }); +}); diff --git a/src/Panel/Panel.stories.tsx b/src/Frame/Frame.stories.tsx similarity index 54% rename from src/Panel/Panel.stories.tsx rename to src/Frame/Frame.stories.tsx index 930fb96c..dd19c232 100644 --- a/src/Panel/Panel.stories.tsx +++ b/src/Frame/Frame.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; -import { Panel } from 'react95'; +import { Frame } from 'react95'; import styled from 'styled-components'; const Wrapper = styled.div` @@ -19,28 +19,30 @@ const Wrapper = styled.div` `; export default { - title: 'Panel', - component: Panel, + title: 'Layout/Frame', + component: Frame, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { return ( -

- Notice the subtle difference in borders. The lightest border is not on - the edge of this panel. + This is a frame of the 'window' variant, the default. Notice + the subtle difference in borders. The lightest border is not on the edge + of this frame.

- - This panel on the other hand has the lightest border on the edge. Use - this panel inside 'outside' panels. + + This frame of the 'button' variant on the other hand has the + lightest border on the edge. Use this frame inside 'window' + frames.
- - Put some content here - -
- + + - The 'well' variant of a panel is often used as a window - footer. - -
+ The 'status' variant of a frame is often used as a status bar + at the end of the window. + + ); } diff --git a/src/Frame/Frame.tsx b/src/Frame/Frame.tsx new file mode 100644 index 00000000..440eddd9 --- /dev/null +++ b/src/Frame/Frame.tsx @@ -0,0 +1,58 @@ +import React, { forwardRef } from 'react'; +import styled, { css } from 'styled-components'; +import { createBorderStyles, createBoxStyles } from '../common'; +import { CommonStyledProps } from '../types'; + +type FrameProps = { + children?: React.ReactNode; + shadow?: boolean; + variant?: 'outside' | 'field' | 'inside' | 'well'; +} & React.HTMLAttributes & + CommonStyledProps; + +const createFrameStyles = (variant: FrameProps['variant']) => { + switch (variant) { + case 'well': + return css` + ${createBorderStyles({ style: 'status' })} + `; + case 'outside': + return css` + ${createBorderStyles({ style: 'window' })} + `; + case 'field': + return css` + ${createBorderStyles({ style: 'field' })} + `; + default: + return css` + ${createBorderStyles()} + `; + } +}; + +const StyledFrame = styled.div>>` + position: relative; + font-size: 1rem; + ${({ variant }) => createFrameStyles(variant)} + ${({ variant }) => + createBoxStyles( + variant === 'field' + ? { background: 'canvas', color: 'canvasText' } + : undefined + )} +`; + +const Frame = forwardRef( + ({ children, shadow = false, variant = 'window', ...otherProps }, ref) => { + return ( + + {children} + + ); + } +); + +Frame.displayName = 'Frame'; + +export { Frame, FrameProps }; diff --git a/src/MenuList/MenuList.tsx b/src/MenuList/MenuList.tsx index 9304c6e7..57b57848 100644 --- a/src/MenuList/MenuList.tsx +++ b/src/MenuList/MenuList.tsx @@ -17,7 +17,7 @@ const MenuList = styled.ul.attrs(() => ({ box-sizing: border-box; width: ${props => (props.fullWidth ? '100%' : 'auto')}; padding: 4px; - ${createBorderStyles({ windowBorders: true })} + ${createBorderStyles({ style: 'window' })} ${createBoxStyles()} ${props => props.inline && diff --git a/src/Panel/Panel.spec.tsx b/src/Panel/Panel.spec.tsx deleted file mode 100644 index 90d7e4a9..00000000 --- a/src/Panel/Panel.spec.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { render } from '@testing-library/react'; -import React from 'react'; - -import { Panel } from './Panel'; - -describe('', () => { - it('should render panel', () => { - const { container } = render(); - const panel = container.firstElementChild; - - expect(panel).toBeInTheDocument(); - }); - - it('should render custom styles', () => { - const { container } = render( - - ); - const panel = container.firstElementChild; - - expect(panel).toHaveAttribute('style', 'background-color: papayawhip;'); - }); - - it('should render children', async () => { - const { findByText } = render( - - Cool panel - - ); - const content = await findByText(/cool panel/i); - - expect(content).toBeInTheDocument(); - }); - - it('should render custom props', () => { - const customProps = { title: 'panel' }; - const { container } = render(); - const panel = container.firstElementChild; - - expect(panel).toHaveAttribute('title', 'panel'); - }); -}); diff --git a/src/Panel/Panel.tsx b/src/Panel/Panel.tsx deleted file mode 100644 index 58af24de..00000000 --- a/src/Panel/Panel.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { forwardRef } from 'react'; -import styled, { css } from 'styled-components'; -import { - createBorderStyles, - createBoxStyles, - createWellBorderStyles -} from '../common'; -import { CommonStyledProps } from '../types'; - -type PanelProps = { - children?: React.ReactNode; - shadow?: boolean; - variant?: 'outside' | 'inside' | 'well'; -} & React.HTMLAttributes & - CommonStyledProps; - -const createPanelStyles = (variant: PanelProps['variant']) => { - switch (variant) { - case 'well': - return css` - ${createWellBorderStyles(true)} - `; - case 'outside': - return css` - ${createBorderStyles({ windowBorders: true })} - `; - default: - return css` - ${createBorderStyles()} - `; - } -}; - -const StyledPanel = styled.div>>` - position: relative; - font-size: 1rem; - ${({ variant }) => createPanelStyles(variant)} - ${createBoxStyles()} -`; - -const Panel = forwardRef(function Panel( - { children, shadow = false, variant = 'outside', ...otherProps }, - ref -) { - return ( - - {children} - - ); -}); - -export { Panel, PanelProps }; diff --git a/src/TableHeadCell/TableHeadCell.tsx b/src/TableHeadCell/TableHeadCell.tsx index dd4c359d..81daf51f 100644 --- a/src/TableHeadCell/TableHeadCell.tsx +++ b/src/TableHeadCell/TableHeadCell.tsx @@ -37,7 +37,7 @@ const StyledHeadCell = styled.th<{ $disabled: boolean }>` css` &:active { &:before { - ${createBorderStyles({ invert: true, windowBorders: true })} + ${createBorderStyles({ invert: true, style: 'window' })} border-left: none; border-top: none; padding-top: 2px; diff --git a/src/Window/Window.stories.tsx b/src/Window/Window.stories.tsx index 050a044e..e27b4c62 100644 --- a/src/Window/Window.stories.tsx +++ b/src/Window/Window.stories.tsx @@ -2,7 +2,7 @@ import { ComponentMeta } from '@storybook/react'; import React from 'react'; import { Button, - Panel, + Frame, Toolbar, Window, WindowContent, @@ -97,9 +97,9 @@ export function Default() { you tho!)

- + Put some useful information here - + diff --git a/src/Window/Window.tsx b/src/Window/Window.tsx index a8b10eab..a1c2d6b0 100644 --- a/src/Window/Window.tsx +++ b/src/Window/Window.tsx @@ -15,7 +15,7 @@ const StyledWindow = styled.div` position: relative; padding: 4px; font-size: 1rem; - ${createBorderStyles({ windowBorders: true })} + ${createBorderStyles({ style: 'window' })} ${createBoxStyles()} `; diff --git a/src/common/index.ts b/src/common/index.ts index 9f90ae7b..6789ed15 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,5 +1,5 @@ import { css } from 'styled-components'; -import { Color, CommonThemeProps } from '../types'; +import { Color, CommonThemeProps, Theme } from '../types'; export const shadow = '4px 4px 10px 0 rgba(0, 0, 0, 0.35)'; export const insetShadow = 'inset 2px 2px 3px rgba(0,0,0,0.2)'; @@ -11,11 +11,17 @@ export const createDisabledTextStyles = () => css` /* filter: grayscale(100%); */ `; -export const createBoxStyles = () => css` +export const createBoxStyles = ({ + background = 'material', + color = 'materialText' +}: { + background?: keyof Theme; + color?: keyof Theme; +} = {}) => css` box-sizing: border-box; display: inline-block; - background: ${({ theme }) => theme.material}; - color: ${({ theme }) => theme.materialText}; + background: ${({ theme }) => theme[background]}; + color: ${({ theme }) => theme[color]}; `; // TODO for flat box styles add checkered background when disabled (not solid color) @@ -57,56 +63,137 @@ export const createFlatBoxStyles = () => css` outline-offset: -4px; `; +export type BorderStyles = + | 'button' + | 'buttonPressed' + | 'buttonThin' + | 'buttonThinPressed' + | 'field' + | 'grouping' + | 'status' + | 'window'; + +type BorderStyle = { + topLeftOuter: keyof Theme; + topLeftInner: keyof Theme | null; + bottomRightInner: keyof Theme | null; + bottomRightOuter: keyof Theme; +}; + +const borderStyles: Record = { + button: { + topLeftOuter: 'borderLightest', + topLeftInner: 'borderLight', + bottomRightInner: 'borderDark', + bottomRightOuter: 'borderDarkest' + }, + buttonPressed: { + topLeftOuter: 'borderDarkest', + topLeftInner: 'borderDark', + bottomRightInner: 'borderLight', + bottomRightOuter: 'borderLightest' + }, + buttonThin: { + topLeftOuter: 'borderLightest', + topLeftInner: null, + bottomRightInner: null, + bottomRightOuter: 'borderDark' + }, + buttonThinPressed: { + topLeftOuter: 'borderDark', + topLeftInner: null, + bottomRightInner: null, + bottomRightOuter: 'borderLightest' + }, + field: { + topLeftOuter: 'borderDark', + topLeftInner: 'borderDarkest', + bottomRightInner: 'borderLight', + bottomRightOuter: 'borderLightest' + }, + grouping: { + topLeftOuter: 'borderDark', + topLeftInner: 'borderLightest', + bottomRightInner: 'borderDark', + bottomRightOuter: 'borderLightest' + }, + status: { + topLeftOuter: 'borderDark', + topLeftInner: null, + bottomRightInner: null, + bottomRightOuter: 'borderLightest' + }, + window: { + topLeftOuter: 'borderLight', + topLeftInner: 'borderLightest', + bottomRightInner: 'borderDark', + bottomRightOuter: 'borderDarkest' + } +}; + +export const createInnerBorderWithShadow = ({ + theme, + topLeftInner, + bottomRightInner, + hasShadow = false, + hasInsetShadow = false +}: { + theme: Theme; + topLeftInner: keyof Theme | null; + bottomRightInner: keyof Theme | null; + hasShadow?: boolean; + hasInsetShadow?: boolean; +}) => + [ + hasShadow ? shadow : false, + hasInsetShadow ? insetShadow : false, + topLeftInner !== null + ? `inset 1px 1px 0px 1px ${theme[topLeftInner]}` + : false, + bottomRightInner !== null + ? `inset -1px -1px 0 1px ${theme[bottomRightInner]}` + : false + ] + .filter(Boolean) + .join(', '); + export const createBorderStyles = ({ invert = false, - windowBorders = false -} = {}) => - invert - ? css` - border-style: solid; - border-width: 2px; - border-left-color: ${({ theme }) => theme.borderDarkest}; - border-top-color: ${({ theme }) => theme.borderDarkest}; - border-right-color: ${({ theme }) => theme.borderLightest}; - border-bottom-color: ${({ theme }) => theme.borderLightest}; - box-shadow: ${props => props.shadow && `${shadow}, `} inset 1px 1px 0px - 1px ${({ theme }) => theme.borderDark}, - inset -1px -1px 0 1px ${({ theme }) => theme.borderLight}; - ` - : css` - border-style: solid; - border-width: 2px; - border-left-color: ${({ theme }) => - windowBorders ? theme.borderLight : theme.borderLightest}; - border-top-color: ${({ theme }) => - windowBorders ? theme.borderLight : theme.borderLightest}; - border-right-color: ${({ theme }) => theme.borderDarkest}; - border-bottom-color: ${({ theme }) => theme.borderDarkest}; - box-shadow: ${props => props.shadow && `${shadow}, `} inset 1px 1px 0px - 1px - ${({ theme }) => - windowBorders ? theme.borderLightest : theme.borderLight}, - inset -1px -1px 0 1px ${({ theme }) => theme.borderDark}; - `; + style = 'button' +}: { invert?: boolean; style?: BorderStyles } = {}) => { + const borders = { + topLeftOuter: invert ? 'bottomRightOuter' : 'topLeftOuter', + topLeftInner: invert ? 'bottomRightInner' : 'topLeftInner', + bottomRightInner: invert ? 'topLeftInner' : 'bottomRightInner', + bottomRightOuter: invert ? 'topLeftOuter' : 'bottomRightOuter' + } as const; + return css` + border-style: solid; + border-width: 2px; + border-left-color: ${({ theme }) => + theme[borderStyles[style][borders.topLeftOuter]]}; + border-top-color: ${({ theme }) => + theme[borderStyles[style][borders.topLeftOuter]]}; + border-right-color: ${({ theme }) => + theme[borderStyles[style][borders.bottomRightOuter]]}; + border-bottom-color: ${({ theme }) => + theme[borderStyles[style][borders.bottomRightOuter]]}; + box-shadow: ${({ theme, shadow: hasShadow }) => + createInnerBorderWithShadow({ + theme, + topLeftInner: borderStyles[style][borders.topLeftInner], + bottomRightInner: borderStyles[style][borders.bottomRightInner], + hasShadow + })}; + `; +}; +/** @deprecated Use `createBorderStyles` instead */ export const createWellBorderStyles = (invert = false) => - invert - ? css` - border-style: solid; - border-width: 2px; - border-left-color: ${({ theme }) => theme.borderDark}; - border-top-color: ${({ theme }) => theme.borderDark}; - border-right-color: ${({ theme }) => theme.borderLightest}; - border-bottom-color: ${({ theme }) => theme.borderLightest}; - ` - : css` - border-style: solid; - border-width: 2px; - border-left-color: ${({ theme }) => theme.borderLightest}; - border-top-color: ${({ theme }) => theme.borderLightest}; - border-right-color: ${({ theme }) => theme.borderDark}; - border-bottom-color: ${({ theme }) => theme.borderDark}; - `; + createBorderStyles({ + invert: !invert, + style: 'status' + }); export const focusOutline = () => css` outline: 2px dotted ${({ theme }) => theme.materialText}; @@ -141,7 +228,7 @@ export const createScrollbars = (variant = 'default') => css` ${createBoxStyles()} ${variant === 'flat' ? createFlatBoxStyles() - : createBorderStyles({ windowBorders: true })} + : createBorderStyles({ style: 'window' })} outline-offset: -2px; } @@ -152,7 +239,7 @@ export const createScrollbars = (variant = 'default') => css` ${createBoxStyles()} ${variant === 'flat' ? createFlatBoxStyles() - : createBorderStyles({ windowBorders: true })} + : createBorderStyles({ style: 'window' })} display: block; outline-offset: -2px; height: 26px; @@ -165,7 +252,7 @@ export const createScrollbars = (variant = 'default') => css` ::-webkit-scrollbar-button:active { background-position: 0 1px; ${variant === 'default' - ? createBorderStyles({ windowBorders: true, invert: true }) + ? createBorderStyles({ style: 'window', invert: true }) : ''} } diff --git a/src/index.ts b/src/index.ts index 93e0ea68..04e603e2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,13 +11,13 @@ export * from './Checkbox/Checkbox'; export * from './ColorInput/ColorInput'; export * from './Counter/Counter'; export * from './DatePicker/DatePicker'; +export * from './Frame/Frame'; export * from './GroupBox/GroupBox'; export * from './Handle/Handle'; export * from './Hourglass/Hourglass'; export * from './MenuList/MenuList'; export * from './Monitor/Monitor'; export * from './NumberInput/NumberInput'; -export * from './Panel/Panel'; export * from './ProgressBar/ProgressBar'; export * from './Radio/Radio'; export * from './ScrollView/ScrollView'; @@ -48,4 +48,5 @@ export * from './legacy/Fieldset'; export * from './legacy/List'; export * from './legacy/ListItem'; export * from './legacy/NumberField'; +export * from './legacy/Panel'; export * from './legacy/Progress'; diff --git a/src/legacy/Panel.tsx b/src/legacy/Panel.tsx new file mode 100644 index 00000000..b317f56f --- /dev/null +++ b/src/legacy/Panel.tsx @@ -0,0 +1,7 @@ +import { Frame, FrameProps } from '../Frame/Frame'; + +/** @deprecated Use `FrameProps` */ +export type PanelProps = FrameProps; + +/** @deprecated Use `Frame` */ +export const Panel = Frame; From 099ae3a609b0f6dcaa5d74b17429bf5ea821709c Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 18:45:12 -0400 Subject: [PATCH 20/29] docs(radio): categorize under Controls --- src/Radio/Radio.mdx | 33 ------------------ src/Radio/Radio.stories.tsx | 2 +- src/Radio/Radio.tsx | 68 ++++++++++++++++++++----------------- 3 files changed, 37 insertions(+), 66 deletions(-) delete mode 100644 src/Radio/Radio.mdx diff --git a/src/Radio/Radio.mdx b/src/Radio/Radio.mdx deleted file mode 100644 index a576344b..00000000 --- a/src/Radio/Radio.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Radio -menu: Components ---- - -import { Radio } from './Radio'; -import Fieldset from '../Fieldset/Fieldset'; -import Window from '../Window/Window'; -import WindowContent from '../WindowContent/WindowContent'; - -# Radio - -## Usage - - - - - - - - - -## API - -### Import - -``` -import { Radio } from 'react95' -``` - -### Props - - diff --git a/src/Radio/Radio.stories.tsx b/src/Radio/Radio.stories.tsx index e4b37d08..a36b1543 100644 --- a/src/Radio/Radio.stories.tsx +++ b/src/Radio/Radio.stories.tsx @@ -26,7 +26,7 @@ const Wrapper = styled.div` } `; export default { - title: 'Radio', + title: 'Controls/Radio', component: Radio, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/Radio/Radio.tsx b/src/Radio/Radio.tsx index 92ab2459..bfcbdda4 100644 --- a/src/Radio/Radio.tsx +++ b/src/Radio/Radio.tsx @@ -136,38 +136,42 @@ const CheckboxComponents = { menu: StyledMenuCheckbox }; -const Radio = forwardRef(function Radio( - { - checked, - className = '', - disabled = false, - label = '', - onChange, - style = {}, - variant = 'default', - ...otherProps - }, - ref -) { - const CheckboxComponent = CheckboxComponents[variant]; +const Radio = forwardRef( + ( + { + checked, + className = '', + disabled = false, + label = '', + onChange, + style = {}, + variant = 'default', + ...otherProps + }, + ref + ) => { + const CheckboxComponent = CheckboxComponents[variant]; - return ( - - - {checked && } - - - {label && {label}} - - ); -}); + return ( + + + {checked && } + + + {label && {label}} + + ); + } +); + +Radio.displayName = 'Radio'; export { Radio, RadioProps }; From b185b0c2d14b7fa8b5e243352d90907eff612391 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 19:36:00 -0400 Subject: [PATCH 21/29] docs(select): categorize under Controls --- src/Select/Select.mdx | 143 ---------------------------------- src/Select/Select.stories.tsx | 2 +- 2 files changed, 1 insertion(+), 144 deletions(-) delete mode 100644 src/Select/Select.mdx diff --git a/src/Select/Select.mdx b/src/Select/Select.mdx deleted file mode 100644 index b4465bf9..00000000 --- a/src/Select/Select.mdx +++ /dev/null @@ -1,143 +0,0 @@ ---- -name: Select -menu: Components ---- - -import { Select } from './Select'; -import { ScrollView } from '../ScrollView/ScrollView'; -import { Window } from '../Window/Window'; -import { WindowContent } from '../WindowContent/WindowContent'; - -# Select - -## Usage - -#### Fixed Width - - - {() => { - const items = [ - { value: 1, label: '⚡ Pikachu' }, - { value: 2, label: '🌿 Bulbasaur' }, - { value: 3, label: '💦 Squirtle' }, - { value: 4, label: '🔥 Charizard' }, - { value: 5, label: '🎤 Jigglypuff' }, - { value: 6, label: '🛌🏻 Snorlax' }, - { value: 7, label: '⛰ Geodude' } - ]; - return ( - console.log(value)} - height={100} - width={150} - /> - ); - }} - - -#### No shadow - - - {() => { - const items = [ - { value: 1, label: '⚡ Pikachu' }, - { value: 2, label: '🌿 Bulbasaur' }, - { value: 3, label: '💦 Squirtle' }, - { value: 4, label: '🔥 Charizard' }, - { value: 5, label: '🎤 Jigglypuff' }, - { value: 6, label: '🛌🏻 Snorlax' }, - { value: 7, label: '⛰ Geodude' } - ]; - return ( - console.log(value)} - height={100} - width={150} - /> - - - - - ); - }} - - -## API - -### Import - -``` -import { Select } from 'react95' -``` - -### Props - - diff --git a/src/Select/Select.stories.tsx b/src/Select/Select.stories.tsx index 29946074..a0621276 100644 --- a/src/Select/Select.stories.tsx +++ b/src/Select/Select.stories.tsx @@ -43,7 +43,7 @@ const onChange = (event: SelectChangeEvent, option: SelectOption) => console.log(event, option); export default { - title: 'Select', + title: 'Controls/Select', component: Select, decorators: [story => {story()}] } as ComponentMeta; From 0bddef05ca15192b457a84910ddf527a70dee3ca Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 19:49:39 -0400 Subject: [PATCH 22/29] docs(slider): categorize under Controls --- src/Slider/Slider.stories.tsx | 2 +- src/Slider/Slider.tsx | 658 +++++++++++++++++----------------- 2 files changed, 332 insertions(+), 328 deletions(-) diff --git a/src/Slider/Slider.stories.tsx b/src/Slider/Slider.stories.tsx index dd3fc8eb..b7b96466 100644 --- a/src/Slider/Slider.stories.tsx +++ b/src/Slider/Slider.stories.tsx @@ -35,7 +35,7 @@ const Wrapper = styled.div` `; export default { - title: 'Slider', + title: 'Controls/Slider', component: Slider, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/Slider/Slider.tsx b/src/Slider/Slider.tsx index f1c6196a..574229ad 100644 --- a/src/Slider/Slider.tsx +++ b/src/Slider/Slider.tsx @@ -290,352 +290,356 @@ const Mark = styled.div` `} `; -const Slider = forwardRef(function Slider( - { - defaultValue, - disabled = false, - marks: marksProp = false, - max = 100, - min = 0, - name, - onChange, - onChangeCommitted, - onMouseDown, - orientation = 'horizontal', - size = '100%', - step = 1, - value, - variant = 'default', - ...otherProps - }, - ref -) { - const Groove = variant === 'flat' ? StyledFlatGroove : StyledGroove; - const vertical = orientation === 'vertical'; - const [valueDerived, setValueState] = useControlledOrUncontrolled({ - value, - defaultValue: defaultValue ?? min - }); - - const { - isFocusVisible, - onBlurVisible, - ref: focusVisibleRef - } = useIsFocusVisible(); - const [focusVisible, setFocusVisible] = useState(false); - const sliderRef = useRef(); - const thumbRef = useRef(null); - const handleFocusRef = useForkRef(focusVisibleRef, sliderRef); - const handleRef = useForkRef(ref, handleFocusRef); - - const handleFocus = useCallback( - (event: React.FocusEvent) => { - if (isFocusVisible(event)) { - setFocusVisible(true); - } - }, - [isFocusVisible] - ); - - const handleBlur = useCallback(() => { - if (focusVisible !== false) { - setFocusVisible(false); - onBlurVisible(); - } - }, [focusVisible, onBlurVisible]); - - const touchId = useRef(); - - const marks = useMemo( - () => - marksProp === true && Number.isFinite(step) - ? [...Array(Math.round((max - min) / (step as number)) + 1)].map( - (_, index) => ({ - label: undefined, - value: min + (step as number) * index - }) - ) - : Array.isArray(marksProp) - ? marksProp - : [], - [marksProp, max, min, step] - ); - - const handleKeyDown = useCallback( - (event: React.KeyboardEvent) => { - const tenPercents = (max - min) / 10; - const marksValues = marks.map(mark => mark.value); - const marksIndex = marksValues.indexOf(valueDerived); - let newValue = 0; - - switch (event.key) { - case 'Home': - newValue = min; - break; - case 'End': - newValue = max; - break; - case 'PageUp': - if (step) { - newValue = valueDerived + tenPercents; - } - break; - case 'PageDown': - if (step) { - newValue = valueDerived - tenPercents; - } - break; - case 'ArrowRight': - case 'ArrowUp': - if (step) { - newValue = valueDerived + step; - } else { - newValue = - marksValues[marksIndex + 1] || - marksValues[marksValues.length - 1]; - } - break; - case 'ArrowLeft': - case 'ArrowDown': - if (step) { - newValue = valueDerived - step; - } else { - newValue = marksValues[marksIndex - 1] || marksValues[0]; - } - break; - default: - return; - } - - // Prevent scroll of the page - event.preventDefault(); - if (step) { - newValue = roundValueToStep(newValue, step, min); - } - - newValue = clamp(newValue, min, max); - - setValueState(newValue); - setFocusVisible(true); - - onChange?.(event, newValue); - onChangeCommitted?.(event, newValue); - }, - [ - marks, - max, - min, +const Slider = forwardRef( + ( + { + defaultValue, + disabled = false, + marks: marksProp = false, + max = 100, + min = 0, + name, onChange, onChangeCommitted, - setValueState, - step, - valueDerived - ] - ); - - const getNewValue = useCallback( - (finger: { x: number; y: number }) => { - if (!sliderRef.current) { - return 0; - } - const rect = sliderRef.current.getBoundingClientRect(); - - let percent; - if (vertical) { - percent = (rect.bottom - finger.y) / rect.height; - } else { - percent = (finger.x - rect.left) / rect.width; - } - let newValue; - - newValue = percentToValue(percent, min, max); - if (step) { - newValue = roundValueToStep(newValue, step, min); - } else { - const marksValues = marks.map(mark => mark.value); - const closestIndex = findClosest(marksValues, newValue); - newValue = marksValues[closestIndex]; - } - newValue = clamp(newValue, min, max); - return newValue; + onMouseDown, + orientation = 'horizontal', + size = '100%', + step = 1, + value, + variant = 'default', + ...otherProps }, - [marks, max, min, step, vertical] - ); - - const handleTouchMove = useCallback( - (event: MouseEvent | TouchEvent) => { - const finger = trackFinger(event, touchId.current); - - if (!finger) { - return; + ref + ) => { + const Groove = variant === 'flat' ? StyledFlatGroove : StyledGroove; + const vertical = orientation === 'vertical'; + const [valueDerived, setValueState] = useControlledOrUncontrolled({ + value, + defaultValue: defaultValue ?? min + }); + + const { + isFocusVisible, + onBlurVisible, + ref: focusVisibleRef + } = useIsFocusVisible(); + const [focusVisible, setFocusVisible] = useState(false); + const sliderRef = useRef(); + const thumbRef = useRef(null); + const handleFocusRef = useForkRef(focusVisibleRef, sliderRef); + const handleRef = useForkRef(ref, handleFocusRef); + + const handleFocus = useCallback( + (event: React.FocusEvent) => { + if (isFocusVisible(event)) { + setFocusVisible(true); + } + }, + [isFocusVisible] + ); + + const handleBlur = useCallback(() => { + if (focusVisible !== false) { + setFocusVisible(false); + onBlurVisible(); } - const newValue = getNewValue(finger); - - thumbRef.current?.focus(); - setValueState(newValue); - setFocusVisible(true); + }, [focusVisible, onBlurVisible]); + + const touchId = useRef(); + + const marks = useMemo( + () => + marksProp === true && Number.isFinite(step) + ? [...Array(Math.round((max - min) / (step as number)) + 1)].map( + (_, index) => ({ + label: undefined, + value: min + (step as number) * index + }) + ) + : Array.isArray(marksProp) + ? marksProp + : [], + [marksProp, max, min, step] + ); + + const handleKeyDown = useCallback( + (event: React.KeyboardEvent) => { + const tenPercents = (max - min) / 10; + const marksValues = marks.map(mark => mark.value); + const marksIndex = marksValues.indexOf(valueDerived); + let newValue = 0; + + switch (event.key) { + case 'Home': + newValue = min; + break; + case 'End': + newValue = max; + break; + case 'PageUp': + if (step) { + newValue = valueDerived + tenPercents; + } + break; + case 'PageDown': + if (step) { + newValue = valueDerived - tenPercents; + } + break; + case 'ArrowRight': + case 'ArrowUp': + if (step) { + newValue = valueDerived + step; + } else { + newValue = + marksValues[marksIndex + 1] || + marksValues[marksValues.length - 1]; + } + break; + case 'ArrowLeft': + case 'ArrowDown': + if (step) { + newValue = valueDerived - step; + } else { + newValue = marksValues[marksIndex - 1] || marksValues[0]; + } + break; + default: + return; + } + + // Prevent scroll of the page + event.preventDefault(); + if (step) { + newValue = roundValueToStep(newValue, step, min); + } + + newValue = clamp(newValue, min, max); - onChange?.(event, newValue); - }, - [getNewValue, onChange, setValueState] - ); + setValueState(newValue); + setFocusVisible(true); - const handleTouchEnd = useCallback( - (event: MouseEvent | TouchEvent) => { - const finger = trackFinger(event, touchId.current); + onChange?.(event, newValue); + onChangeCommitted?.(event, newValue); + }, + [ + marks, + max, + min, + onChange, + onChangeCommitted, + setValueState, + step, + valueDerived + ] + ); + + const getNewValue = useCallback( + (finger: { x: number; y: number }) => { + if (!sliderRef.current) { + return 0; + } + const rect = sliderRef.current.getBoundingClientRect(); + + let percent; + if (vertical) { + percent = (rect.bottom - finger.y) / rect.height; + } else { + percent = (finger.x - rect.left) / rect.width; + } + let newValue; + + newValue = percentToValue(percent, min, max); + if (step) { + newValue = roundValueToStep(newValue, step, min); + } else { + const marksValues = marks.map(mark => mark.value); + const closestIndex = findClosest(marksValues, newValue); + newValue = marksValues[closestIndex]; + } + newValue = clamp(newValue, min, max); + return newValue; + }, + [marks, max, min, step, vertical] + ); + + const handleTouchMove = useCallback( + (event: MouseEvent | TouchEvent) => { + const finger = trackFinger(event, touchId.current); + + if (!finger) { + return; + } + const newValue = getNewValue(finger); - if (!finger) { - return; - } + thumbRef.current?.focus(); + setValueState(newValue); + setFocusVisible(true); - const newValue = getNewValue(finger); + onChange?.(event, newValue); + }, + [getNewValue, onChange, setValueState] + ); - onChangeCommitted?.(event, newValue); + const handleTouchEnd = useCallback( + (event: MouseEvent | TouchEvent) => { + const finger = trackFinger(event, touchId.current); - touchId.current = undefined; + if (!finger) { + return; + } - const doc = ownerDocument(sliderRef.current); - doc.removeEventListener('mousemove', handleTouchMove); - doc.removeEventListener('mouseup', handleTouchEnd); - doc.removeEventListener('touchmove', handleTouchMove); - doc.removeEventListener('touchend', handleTouchEnd); - }, - [getNewValue, handleTouchMove, onChangeCommitted] - ); + const newValue = getNewValue(finger); - const handleMouseDown = useCallback( - (event: React.MouseEvent) => { - // TODO should we also pass event together with new value to callbacks? (same thing with other input components) - onMouseDown?.(event); + onChangeCommitted?.(event, newValue); - event.preventDefault(); - thumbRef.current?.focus(); - setFocusVisible(true); + touchId.current = undefined; - const finger = trackFinger(event, touchId.current); - if (finger) { - const newValue = getNewValue(finger); - setValueState(newValue); - onChange?.(event, newValue); - } + const doc = ownerDocument(sliderRef.current); + doc.removeEventListener('mousemove', handleTouchMove); + doc.removeEventListener('mouseup', handleTouchEnd); + doc.removeEventListener('touchmove', handleTouchMove); + doc.removeEventListener('touchend', handleTouchEnd); + }, + [getNewValue, handleTouchMove, onChangeCommitted] + ); - const doc = ownerDocument(sliderRef.current); - doc.addEventListener('mousemove', handleTouchMove); - doc.addEventListener('mouseup', handleTouchEnd); - }, - [ - getNewValue, - handleTouchEnd, - handleTouchMove, - onChange, - onMouseDown, - setValueState - ] - ); - - const handleTouchStart = useCallback( - (event: TouchEvent) => { - // Workaround as Safari has partial support for touchAction: 'none'. - event.preventDefault(); - const touch = event.changedTouches[0]; - if (touch != null) { - // A number that uniquely identifies the current finger in the touch session. - touchId.current = touch.identifier; - } + const handleMouseDown = useCallback( + (event: React.MouseEvent) => { + // TODO should we also pass event together with new value to callbacks? (same thing with other input components) + onMouseDown?.(event); - thumbRef.current?.focus(); - setFocusVisible(true); + event.preventDefault(); + thumbRef.current?.focus(); + setFocusVisible(true); - const finger = trackFinger(event, touchId.current); - if (finger) { - const newValue = getNewValue(finger); - setValueState(newValue); - onChange?.(event, newValue); - } + const finger = trackFinger(event, touchId.current); + if (finger) { + const newValue = getNewValue(finger); + setValueState(newValue); + onChange?.(event, newValue); + } + + const doc = ownerDocument(sliderRef.current); + doc.addEventListener('mousemove', handleTouchMove); + doc.addEventListener('mouseup', handleTouchEnd); + }, + [ + getNewValue, + handleTouchEnd, + handleTouchMove, + onChange, + onMouseDown, + setValueState + ] + ); + + const handleTouchStart = useCallback( + (event: TouchEvent) => { + // Workaround as Safari has partial support for touchAction: 'none'. + event.preventDefault(); + const touch = event.changedTouches[0]; + if (touch != null) { + // A number that uniquely identifies the current finger in the touch session. + touchId.current = touch.identifier; + } + + thumbRef.current?.focus(); + setFocusVisible(true); - const doc = ownerDocument(sliderRef.current); - doc.addEventListener('touchmove', handleTouchMove); - doc.addEventListener('touchend', handleTouchEnd); - }, - [getNewValue, handleTouchEnd, handleTouchMove, onChange, setValueState] - ); - - useEffect(() => { - const { current: slider } = sliderRef; - slider?.addEventListener('touchstart', handleTouchStart); - const doc = ownerDocument(slider); - - return () => { - slider?.removeEventListener('touchstart', handleTouchStart); - doc.removeEventListener('mousemove', handleTouchMove); - doc.removeEventListener('mouseup', handleTouchEnd); - doc.removeEventListener('touchmove', handleTouchMove); - doc.removeEventListener('touchend', handleTouchEnd); - }; - }, [handleTouchEnd, handleTouchMove, handleTouchStart]); - - return ( - - {/* should we keep the hidden input ? */} - - {marks && - marks.map(m => ( - - {m.label && ( - - {m.label} - - )} - - ))} - - { + const { current: slider } = sliderRef; + slider?.addEventListener('touchstart', handleTouchStart); + const doc = ownerDocument(slider); + + return () => { + slider?.removeEventListener('touchstart', handleTouchStart); + doc.removeEventListener('mousemove', handleTouchMove); + doc.removeEventListener('mouseup', handleTouchEnd); + doc.removeEventListener('touchmove', handleTouchMove); + doc.removeEventListener('touchend', handleTouchEnd); + }; + }, [handleTouchEnd, handleTouchMove, handleTouchStart]); + + return ( + - - ); -}); + ref={handleRef} + size={getSize(size)} + {...otherProps} + > + {/* should we keep the hidden input ? */} + + {marks && + marks.map(m => ( + + {m.label && ( + + {m.label} + + )} + + ))} + + + + ); + } +); + +Slider.displayName = 'Slider'; export { Slider, SliderProps }; From 0b73769f98568147b0dd84ff234d6efce9abdc45 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 19:55:56 -0400 Subject: [PATCH 23/29] docs(table): categorize under Controls This also moves the Table* subcomponents into the Table folder. --- src/Table/Table.mdx | 76 ------------------- src/Table/Table.stories.tsx | 2 +- src/Table/Table.tsx | 31 +++++--- src/{TableBody => Table}/TableBody.spec.tsx | 0 src/{TableBody => Table}/TableBody.tsx | 2 + .../TableDataCell.spec.tsx | 0 .../TableDataCell.tsx | 2 + src/{TableHead => Table}/TableHead.spec.tsx | 0 src/{TableHead => Table}/TableHead.tsx | 2 + .../TableHeadCell.spec.tsx | 0 .../TableHeadCell.tsx | 2 + src/{TableRow => Table}/TableRow.spec.tsx | 0 src/{TableRow => Table}/TableRow.tsx | 2 + src/index.ts | 5 -- 14 files changed, 30 insertions(+), 94 deletions(-) delete mode 100644 src/Table/Table.mdx rename src/{TableBody => Table}/TableBody.spec.tsx (100%) rename src/{TableBody => Table}/TableBody.tsx (95%) rename src/{TableDataCell => Table}/TableDataCell.spec.tsx (100%) rename src/{TableDataCell => Table}/TableDataCell.tsx (92%) rename src/{TableHead => Table}/TableHead.spec.tsx (100%) rename src/{TableHead => Table}/TableHead.tsx (94%) rename src/{TableHeadCell => Table}/TableHeadCell.spec.tsx (100%) rename src/{TableHeadCell => Table}/TableHeadCell.tsx (97%) rename src/{TableRow => Table}/TableRow.spec.tsx (100%) rename src/{TableRow => Table}/TableRow.tsx (96%) diff --git a/src/Table/Table.mdx b/src/Table/Table.mdx deleted file mode 100644 index 66276c24..00000000 --- a/src/Table/Table.mdx +++ /dev/null @@ -1,76 +0,0 @@ ---- -name: Table -menu: Components ---- - -import { Table } from './Table'; -import { TableBody } from '../TableBody/TableBody'; -import { TableHead } from '../TableHead/TableHead'; -import { TableRow } from '../TableRow/TableRow'; -import { TableHeadCell } from '../TableHeadCell/TableHeadCell'; -import { TableDataCell } from '../TableDataCell/TableDataCell'; -import Window from '../Window/Window'; -import WindowHeader from '../WindowHeader/WindowHeader'; -import WindowContent from '../WindowContent/WindowContent'; - -# Table - -## Usage - - - - Pokedex.exe - - - - - Type - Name - Level - - - - - - - 🌿 - - - Bulbasaur - 64 - - - - - 🔥 - - - Charizard - 209 - - - - - ⚡ - - - Pikachu - 82 - - -
-
-
-
- -## API - -### Import - -``` -import { Table } from 'react95' -``` - -### Props - - diff --git a/src/Table/Table.stories.tsx b/src/Table/Table.stories.tsx index 98713dfc..0b524b50 100644 --- a/src/Table/Table.stories.tsx +++ b/src/Table/Table.stories.tsx @@ -19,7 +19,7 @@ const Wrapper = styled.div` `; export default { - title: 'Table', + title: 'Controls/Table', component: Table, subcomponents: { Table, diff --git a/src/Table/Table.tsx b/src/Table/Table.tsx index b6ab5c9d..9f82c79b 100644 --- a/src/Table/Table.tsx +++ b/src/Table/Table.tsx @@ -22,17 +22,24 @@ const Wrapper = styled(StyledScrollView)` } `; -const Table = forwardRef(function Table( - { children, ...otherProps }, - ref -) { - return ( - - - {children} - - - ); -}); +const Table = forwardRef( + ({ children, ...otherProps }, ref) => { + return ( + + + {children} + + + ); + } +); + +Table.displayName = 'Table'; + +export * from './TableBody'; +export * from './TableDataCell'; +export * from './TableHead'; +export * from './TableHeadCell'; +export * from './TableRow'; export { Table, TableProps }; diff --git a/src/TableBody/TableBody.spec.tsx b/src/Table/TableBody.spec.tsx similarity index 100% rename from src/TableBody/TableBody.spec.tsx rename to src/Table/TableBody.spec.tsx diff --git a/src/TableBody/TableBody.tsx b/src/Table/TableBody.tsx similarity index 95% rename from src/TableBody/TableBody.tsx rename to src/Table/TableBody.tsx index 0c5ef687..542de3a0 100644 --- a/src/TableBody/TableBody.tsx +++ b/src/Table/TableBody.tsx @@ -25,4 +25,6 @@ const TableBody = forwardRef( } ); +TableBody.displayName = 'TableBody'; + export { TableBody, TableBodyProps }; diff --git a/src/TableDataCell/TableDataCell.spec.tsx b/src/Table/TableDataCell.spec.tsx similarity index 100% rename from src/TableDataCell/TableDataCell.spec.tsx rename to src/Table/TableDataCell.spec.tsx diff --git a/src/TableDataCell/TableDataCell.tsx b/src/Table/TableDataCell.tsx similarity index 92% rename from src/TableDataCell/TableDataCell.tsx rename to src/Table/TableDataCell.tsx index 764445fe..f97f8b76 100644 --- a/src/TableDataCell/TableDataCell.tsx +++ b/src/Table/TableDataCell.tsx @@ -21,4 +21,6 @@ const TableDataCell = forwardRef( } ); +TableDataCell.displayName = 'TableDataCell'; + export { TableDataCell, TableDataCellProps }; diff --git a/src/TableHead/TableHead.spec.tsx b/src/Table/TableHead.spec.tsx similarity index 100% rename from src/TableHead/TableHead.spec.tsx rename to src/Table/TableHead.spec.tsx diff --git a/src/TableHead/TableHead.tsx b/src/Table/TableHead.tsx similarity index 94% rename from src/TableHead/TableHead.tsx rename to src/Table/TableHead.tsx index 14afd6e3..368c4da5 100644 --- a/src/TableHead/TableHead.tsx +++ b/src/Table/TableHead.tsx @@ -20,4 +20,6 @@ const TableHead = forwardRef( } ); +TableHead.displayName = 'TableHead'; + export { TableHead, TableHeadProps }; diff --git a/src/TableHeadCell/TableHeadCell.spec.tsx b/src/Table/TableHeadCell.spec.tsx similarity index 100% rename from src/TableHeadCell/TableHeadCell.spec.tsx rename to src/Table/TableHeadCell.spec.tsx diff --git a/src/TableHeadCell/TableHeadCell.tsx b/src/Table/TableHeadCell.tsx similarity index 97% rename from src/TableHeadCell/TableHeadCell.tsx rename to src/Table/TableHeadCell.tsx index 81daf51f..e653d6b6 100644 --- a/src/TableHeadCell/TableHeadCell.tsx +++ b/src/Table/TableHeadCell.tsx @@ -88,4 +88,6 @@ const TableHeadCell = forwardRef( } ); +TableHeadCell.displayName = 'TableHeadCell'; + export { TableHeadCell, TableHeadCellProps }; diff --git a/src/TableRow/TableRow.spec.tsx b/src/Table/TableRow.spec.tsx similarity index 100% rename from src/TableRow/TableRow.spec.tsx rename to src/Table/TableRow.spec.tsx diff --git a/src/TableRow/TableRow.tsx b/src/Table/TableRow.tsx similarity index 96% rename from src/TableRow/TableRow.tsx rename to src/Table/TableRow.tsx index 3c30d8ca..b601c093 100644 --- a/src/TableRow/TableRow.tsx +++ b/src/Table/TableRow.tsx @@ -31,4 +31,6 @@ const TableRow = forwardRef( } ); +TableRow.displayName = 'TableRow'; + export { TableRow, TableRowProps }; diff --git a/src/index.ts b/src/index.ts index 04e603e2..7ad043b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,11 +25,6 @@ export * from './Select/Select'; export * from './Separator/Separator'; export * from './Slider/Slider'; export * from './Table/Table'; -export * from './TableBody/TableBody'; -export * from './TableDataCell/TableDataCell'; -export * from './TableHead/TableHead'; -export * from './TableHeadCell/TableHeadCell'; -export * from './TableRow/TableRow'; export * from './Tabs/Tabs'; export * from './TextField/TextField'; export * from './Toolbar/Toolbar'; From f5cdf4a3a1bcd29290fe04806e1ab01c841483b3 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 20:01:54 -0400 Subject: [PATCH 24/29] refactor(textinput): categorize under Controls, rename TextField to TextInput --- src/AppBar/AppBar.stories.tsx | 4 +- src/NumberInput/NumberInput.tsx | 4 +- src/TextField/TextField.mdx | 112 --------------- .../TextInout.stories.tsx} | 24 ++-- .../TextInput.spec.tsx} | 28 ++-- .../TextField.tsx => TextInput/TextInput.tsx} | 128 +++++++++--------- src/index.ts | 3 +- src/legacy/TextField.tsx | 7 + 8 files changed, 105 insertions(+), 205 deletions(-) delete mode 100644 src/TextField/TextField.mdx rename src/{TextField/TextField.stories.tsx => TextInput/TextInout.stories.tsx} (88%) rename src/{TextField/TextField.spec.tsx => TextInput/TextInput.spec.tsx} (81%) rename src/{TextField/TextField.tsx => TextInput/TextInput.tsx} (59%) create mode 100644 src/legacy/TextField.tsx diff --git a/src/AppBar/AppBar.stories.tsx b/src/AppBar/AppBar.stories.tsx index 6e75a732..c8fc80e9 100644 --- a/src/AppBar/AppBar.stories.tsx +++ b/src/AppBar/AppBar.stories.tsx @@ -6,7 +6,7 @@ import { MenuList, MenuListItem, Separator, - TextField, + TextInput, Toolbar } from 'react95'; import styled from 'styled-components'; @@ -74,7 +74,7 @@ export function Default() { )} - + ); diff --git a/src/NumberInput/NumberInput.tsx b/src/NumberInput/NumberInput.tsx index 3e85b8a6..7ef5d3f4 100644 --- a/src/NumberInput/NumberInput.tsx +++ b/src/NumberInput/NumberInput.tsx @@ -5,7 +5,7 @@ import { Button } from '../Button/Button'; import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled'; import { blockSizes } from '../common/system'; import { clamp, getSize } from '../common/utils'; -import { TextField } from '../TextField/TextField'; +import { TextInput } from '../TextInput/TextInput'; import { CommonStyledProps } from '../types'; type NumberInputProps = { @@ -163,7 +163,7 @@ const NumberInput = forwardRef( width: width !== undefined ? getSize(width) : 'auto' }} > - - console.log(e.target.value)} /> - - -#### No shadow - - - console.log(e.target.value)} - /> - - -#### Disabled - - - console.log(e.target.value)} - disabled - /> - - -#### Custom width - - - console.log(e.target.value)} - /> - - -#### Flat - - - -

- When you want to add input field on a light background (like scrollable - content), just use the flat variant: -

-
- - console.log(e.target.value)} - /> -
-
-
- -#### Flat disabled - - - -

- When you want to add input field on a light background (like scrollable - content), just use the flat variant: -

-
- - console.log(e.target.value)} - disabled - /> -
-
-
- -## API - -### Import - -``` -import { TextField } from 'react95' -``` - -### Props - - diff --git a/src/TextField/TextField.stories.tsx b/src/TextInput/TextInout.stories.tsx similarity index 88% rename from src/TextField/TextField.stories.tsx rename to src/TextInput/TextInout.stories.tsx index 6a715117..c7638eb1 100644 --- a/src/TextField/TextField.stories.tsx +++ b/src/TextInput/TextInout.stories.tsx @@ -1,6 +1,6 @@ import { ComponentMeta } from '@storybook/react'; import React, { useState } from 'react'; -import { Button, ScrollView, TextField } from 'react95'; +import { Button, ScrollView, TextInput } from 'react95'; import styled from 'styled-components'; const loremIpsum = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sollicitudin, ante vel porttitor posuere, tellus nisi interdum ipsum, non bibendum ante risus ut purus. Curabitur vel posuere odio. Vivamus rutrum, nunc et ullamcorper sagittis, tellus ligula maximus quam, id dapibus sapien metus lobortis diam. Proin luctus, dolor in finibus feugiat, lacus enim gravida sem, quis aliquet tellus leo nec enim. Morbi varius bibendum augue quis venenatis. Curabitur ut elit augue. Pellentesque posuere enim a mattis interdum. Donec sodales convallis turpis, a vulputate elit. Suspendisse potenti.`; @@ -19,10 +19,10 @@ const Wrapper = styled.div` `; export default { - title: 'TextField', - component: TextField, + title: 'Controls/TextInput', + component: TextInput, decorators: [story => {story()}] -} as ComponentMeta; +} as ComponentMeta; export function Default() { const [state, setState] = useState({ @@ -36,7 +36,7 @@ export function Default() { return (
-

- +
- +
-
-
-
-
- ', () => { +describe('', () => { it('should render an inside the div', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const input = container.querySelector('input'); expect(input).toHaveAttribute('type', 'text'); expect(input).not.toHaveAttribute('required'); @@ -21,7 +21,7 @@ describe('', () => { const handleKeyUp = jest.fn(); const handleKeyDown = jest.fn(); const { getByRole } = renderWithTheme( - ', () => { }); it('should considered [] as controlled', () => { - const { getByRole } = renderWithTheme(); + const { getByRole } = renderWithTheme(); const input = getByRole('textbox'); expect(input).toHaveProperty('value', ''); @@ -60,20 +60,20 @@ describe('', () => { it('should forwardRef to native input', () => { const inputRef = React.createRef(); - const { getByRole } = renderWithTheme(); + const { getByRole } = renderWithTheme(); const input = getByRole('textbox'); expect(inputRef.current).toBe(input); }); describe('multiline', () => { it('should render textarea when passed the multiline prop', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const textarea = container.querySelector('textarea'); expect(textarea).not.toBe(null); }); it('should forward rows prop', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const textarea = container.querySelector('textarea'); expect(textarea).toHaveAttribute('rows', '3'); }); @@ -81,13 +81,13 @@ describe('', () => { describe('prop: disabled', () => { it('should render a disabled ', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); const input = container.querySelector('input'); expect(input).toHaveAttribute('disabled'); }); it('should be overridden by props', () => { - const { getByRole, rerender } = renderWithTheme(); - rerender(); + const { getByRole, rerender } = renderWithTheme(); + rerender(); const input = getByRole('textbox'); expect(input).not.toHaveAttribute('disabled'); }); @@ -95,18 +95,18 @@ describe('', () => { describe('prop: variant', () => { it('should be "default" by default', () => { - const { getByTestId } = renderWithTheme(); + const { getByTestId } = renderWithTheme(); expect(getByTestId('variant-default')).toBeInTheDocument(); }); it('should handle "flat" variant', () => { - const { getByTestId } = renderWithTheme(); + const { getByTestId } = renderWithTheme(); expect(getByTestId('variant-flat')).toBeInTheDocument(); }); }); describe('prop: fullWidth', () => { it('should make component take 100% width', () => { - const { container } = renderWithTheme(); + const { container } = renderWithTheme(); expect( window.getComputedStyle(container.firstChild as HTMLInputElement).width ).toBe('100%'); diff --git a/src/TextField/TextField.tsx b/src/TextInput/TextInput.tsx similarity index 59% rename from src/TextField/TextField.tsx rename to src/TextInput/TextInput.tsx index 37ee1511..11f92999 100644 --- a/src/TextField/TextField.tsx +++ b/src/TextInput/TextInput.tsx @@ -10,7 +10,7 @@ import { noOp } from '../common/utils'; import { StyledScrollView } from '../ScrollView/ScrollView'; import { CommonStyledProps, CommonThemeProps } from '../types'; -type TextFieldInputProps = { +type TextInputInputProps = { multiline?: false | undefined; onChange?: React.ChangeEventHandler; /** @default text */ @@ -20,7 +20,7 @@ type TextFieldInputProps = { 'className' | 'disabled' | 'style' | 'type' >; -type TextFieldTextAreaProps = { +type TextInputTextAreaProps = { multiline: true; onChange?: React.ChangeEventHandler; } & Omit< @@ -28,7 +28,7 @@ type TextFieldTextAreaProps = { 'className' | 'disabled' | 'style' | 'type' >; -type TextFieldProps = { +type TextInputProps = { className?: string; disabled?: boolean; fullWidth?: boolean; @@ -36,10 +36,10 @@ type TextFieldProps = { shadow?: boolean; style?: React.CSSProperties; variant?: 'default' | 'flat'; -} & (TextFieldInputProps | TextFieldTextAreaProps) & +} & (TextInputInputProps | TextInputTextAreaProps) & CommonStyledProps; -type WrapperProps = Pick & +type WrapperProps = Pick & CommonThemeProps; const sharedWrapperStyles = css` @@ -65,7 +65,7 @@ const FlatWrapper = styled.div.attrs({ position: relative; `; -type InputProps = Pick; +type InputProps = Pick; const sharedInputStyles = css` display: block; @@ -95,60 +95,64 @@ const StyledTextArea = styled.textarea` ${({ variant }) => createScrollbars(variant)} `; -const TextField = forwardRef< +const TextInput = forwardRef< HTMLInputElement | HTMLTextAreaElement, - TextFieldProps ->(function TextField( - { - className, - disabled = false, - fullWidth, - onChange = noOp, - shadow = true, - style, - variant = 'default', - ...otherProps - }, - ref -) { - const WrapperComponent = variant === 'flat' ? FlatWrapper : Wrapper; - - const field = useMemo( - () => - otherProps.multiline ? ( - - ) : ( - - ), - [disabled, onChange, otherProps, ref, variant] - ); - - return ( - - {field} - - ); -}); - -export { TextField, TextFieldProps }; + TextInputProps +>( + ( + { + className, + disabled = false, + fullWidth, + onChange = noOp, + shadow = true, + style, + variant = 'default', + ...otherProps + }, + ref + ) => { + const WrapperComponent = variant === 'flat' ? FlatWrapper : Wrapper; + + const field = useMemo( + () => + otherProps.multiline ? ( + + ) : ( + + ), + [disabled, onChange, otherProps, ref, variant] + ); + + return ( + + {field} + + ); + } +); + +TextInput.displayName = 'TextInput'; + +export { TextInput, TextInputProps }; diff --git a/src/index.ts b/src/index.ts index 7ad043b8..ff4f7b92 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,7 +26,7 @@ export * from './Separator/Separator'; export * from './Slider/Slider'; export * from './Table/Table'; export * from './Tabs/Tabs'; -export * from './TextField/TextField'; +export * from './TextInput/TextInput'; export * from './Toolbar/Toolbar'; export * from './Tooltip/Tooltip'; export * from './Tree/Tree'; @@ -45,3 +45,4 @@ export * from './legacy/ListItem'; export * from './legacy/NumberField'; export * from './legacy/Panel'; export * from './legacy/Progress'; +export * from './legacy/TextField'; diff --git a/src/legacy/TextField.tsx b/src/legacy/TextField.tsx new file mode 100644 index 00000000..9a97a941 --- /dev/null +++ b/src/legacy/TextField.tsx @@ -0,0 +1,7 @@ +import { TextInput, TextInputProps } from '../TextInput/TextInput'; + +/** @deprecated Use `TextInputProps` */ +export type TextFieldProps = TextInputProps; + +/** @deprecated Use `TextInput` */ +export const TextField = TextInput; From 367e04f495a794c27bc58d433851e897ba7584ab Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 20:04:09 -0400 Subject: [PATCH 25/29] docs(tooltip): categorize under Controls --- src/Tooltip/Tooltip.mdx | 29 ---- src/Tooltip/Tooltip.stories.tsx | 2 +- src/Tooltip/Tooltip.tsx | 242 ++++++++++++++++---------------- 3 files changed, 124 insertions(+), 149 deletions(-) delete mode 100644 src/Tooltip/Tooltip.mdx diff --git a/src/Tooltip/Tooltip.mdx b/src/Tooltip/Tooltip.mdx deleted file mode 100644 index 2f18c020..00000000 --- a/src/Tooltip/Tooltip.mdx +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Tooltip -menu: Components ---- - -import { Tooltip } from './Tooltip'; -import { Button } from '../Button/Button'; - -# Tooltip - -## Usage - - - - - - - -## API - -### Import - -``` -import { Tooltip } from 'react95' -``` - -### Props - - diff --git a/src/Tooltip/Tooltip.stories.tsx b/src/Tooltip/Tooltip.stories.tsx index 2ad6f141..186af133 100644 --- a/src/Tooltip/Tooltip.stories.tsx +++ b/src/Tooltip/Tooltip.stories.tsx @@ -9,7 +9,7 @@ const Wrapper = styled.div` `; export default { - title: 'Tooltip', + title: 'Controls/Tooltip', component: Tooltip, decorators: [story => {story()}] } as ComponentMeta; diff --git a/src/Tooltip/Tooltip.tsx b/src/Tooltip/Tooltip.tsx index a71d894d..60cf5558 100644 --- a/src/Tooltip/Tooltip.tsx +++ b/src/Tooltip/Tooltip.tsx @@ -68,126 +68,130 @@ const Wrapper = styled.div` white-space: nowrap; `; -const Tooltip = forwardRef(function Tooltip( - { - className, - children, - disableFocusListener = false, - disableMouseListener = false, - enterDelay = 1000, - leaveDelay = 0, - onBlur, - onClose, - onFocus, - onMouseEnter, - onMouseLeave, - onOpen, - style, - text, - position = 'top', - ...otherProps - }, - ref -) { - const [show, setShow] = useState(false); - const [openTimer, setOpenTimer] = useState(); - const [closeTimer, setCloseTimer] = useState(); - - const isUsingFocus = !disableFocusListener; - const isUsingMouse = !disableMouseListener; - - const handleOpen = ( - event: React.FocusEvent | React.MouseEvent - ) => { - window.clearTimeout(openTimer); - window.clearTimeout(closeTimer); - - const timer = window.setTimeout(() => { - setShow(true); - - onOpen?.(event); - }, enterDelay); - - setOpenTimer(timer); - }; - - const handleEnter = ( - event: React.FocusEvent | React.MouseEvent - ) => { - event.persist(); - - if (isReactFocusEvent(event)) { - onFocus?.(event); - } else if (isReactMouseEvent(event)) { - onMouseEnter?.(event); - } - - handleOpen(event); - }; - - const handleClose = ( - event: React.FocusEvent | React.MouseEvent - ) => { - window.clearTimeout(openTimer); - window.clearTimeout(closeTimer); - - const timer = window.setTimeout(() => { - setShow(false); - - onClose?.(event); - }, leaveDelay); - - setCloseTimer(timer); - }; - - const handleLeave = ( - event: React.FocusEvent | React.MouseEvent +const Tooltip = forwardRef( + ( + { + className, + children, + disableFocusListener = false, + disableMouseListener = false, + enterDelay = 1000, + leaveDelay = 0, + onBlur, + onClose, + onFocus, + onMouseEnter, + onMouseLeave, + onOpen, + style, + text, + position = 'top', + ...otherProps + }, + ref ) => { - event.persist(); - - if (isReactFocusEvent(event)) { - onBlur?.(event); - } else if (isReactMouseEvent(event)) { - onMouseLeave?.(event); - } - - handleClose(event); - }; - - // set callbacks for onBlur and onFocus, unless disableFocusListener is true - const blurCb = isUsingFocus ? handleLeave : undefined; - const focusCb = isUsingFocus ? handleEnter : undefined; - - // set callbacks for onMouseEnter and onMouseLeave, unless disableMouseListener is true - const mouseEnterCb = isUsingMouse ? handleEnter : undefined; - const mouseLeaveCb = isUsingMouse ? handleLeave : undefined; - - // set the wrapper's tabIndex for focus events, unless disableFocusListener is true - const tabIndex = isUsingFocus ? 0 : undefined; - - return ( - - (); + const [closeTimer, setCloseTimer] = useState(); + + const isUsingFocus = !disableFocusListener; + const isUsingMouse = !disableMouseListener; + + const handleOpen = ( + event: React.FocusEvent | React.MouseEvent + ) => { + window.clearTimeout(openTimer); + window.clearTimeout(closeTimer); + + const timer = window.setTimeout(() => { + setShow(true); + + onOpen?.(event); + }, enterDelay); + + setOpenTimer(timer); + }; + + const handleEnter = ( + event: React.FocusEvent | React.MouseEvent + ) => { + event.persist(); + + if (isReactFocusEvent(event)) { + onFocus?.(event); + } else if (isReactMouseEvent(event)) { + onMouseEnter?.(event); + } + + handleOpen(event); + }; + + const handleClose = ( + event: React.FocusEvent | React.MouseEvent + ) => { + window.clearTimeout(openTimer); + window.clearTimeout(closeTimer); + + const timer = window.setTimeout(() => { + setShow(false); + + onClose?.(event); + }, leaveDelay); + + setCloseTimer(timer); + }; + + const handleLeave = ( + event: React.FocusEvent | React.MouseEvent + ) => { + event.persist(); + + if (isReactFocusEvent(event)) { + onBlur?.(event); + } else if (isReactMouseEvent(event)) { + onMouseLeave?.(event); + } + + handleClose(event); + }; + + // set callbacks for onBlur and onFocus, unless disableFocusListener is true + const blurCb = isUsingFocus ? handleLeave : undefined; + const focusCb = isUsingFocus ? handleEnter : undefined; + + // set callbacks for onMouseEnter and onMouseLeave, unless disableMouseListener is true + const mouseEnterCb = isUsingMouse ? handleEnter : undefined; + const mouseLeaveCb = isUsingMouse ? handleLeave : undefined; + + // set the wrapper's tabIndex for focus events, unless disableFocusListener is true + const tabIndex = isUsingFocus ? 0 : undefined; + + return ( + - {text} - - {children} - - ); -}); + + {text} + + {children} + + ); + } +); + +Tooltip.displayName = 'Tooltip'; export { Tooltip, TooltipProps }; From 5add98ce1c1ff279028eb9e00ca1aa87845ecf50 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 20:09:40 -0400 Subject: [PATCH 26/29] refactor(treeview): categorize under Controls, rename Tree to TreeView --- .../TreeView.spec.tsx} | 20 ++++++++++------- .../TreeView.stories.tsx} | 16 +++++++------- src/{Tree/Tree.tsx => TreeView/TreeView.tsx} | 22 +++++++++++-------- src/index.ts | 3 ++- src/legacy/Tree.tsx | 7 ++++++ 5 files changed, 42 insertions(+), 26 deletions(-) rename src/{Tree/Tree.spec.tsx => TreeView/TreeView.spec.tsx} (91%) rename src/{Tree/Tree.stories.tsx => TreeView/TreeView.stories.tsx} (93%) rename src/{Tree/Tree.tsx => TreeView/TreeView.tsx} (94%) create mode 100644 src/legacy/Tree.tsx diff --git a/src/Tree/Tree.spec.tsx b/src/TreeView/TreeView.spec.tsx similarity index 91% rename from src/Tree/Tree.spec.tsx rename to src/TreeView/TreeView.spec.tsx index 17ea298b..97600c11 100644 --- a/src/Tree/Tree.spec.tsx +++ b/src/TreeView/TreeView.spec.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { renderWithTheme } from '../../test/utils'; -import { Tree } from './Tree'; +import { TreeView } from './TreeView'; const categories = [ { @@ -59,13 +59,13 @@ const categories = [ } ]; -describe('', () => { +describe('', () => { describe('prop: onNodeSelect', () => { it('should call onNodeSelect when uncontrolled', () => { const onNodeSelect = jest.fn((_, id) => id); const { getByText } = renderWithTheme( - + ); getByText('Beverages').click(); @@ -78,7 +78,11 @@ describe('', () => { const onNodeSelect = jest.fn((_, id) => id); const { getByText } = renderWithTheme( - + ); getByText('Beverages').click(); @@ -93,7 +97,7 @@ describe('', () => { const onNodeToggle = jest.fn((_, ids) => ids); const { getByText } = renderWithTheme( - + ); getByText('Beverages').click(); @@ -106,7 +110,7 @@ describe('', () => { const onNodeToggle = jest.fn((_, ids) => ids); const { getByText } = renderWithTheme( - ', () => { const onNodeToggle = jest.fn((_, ids) => ids); const { getByText } = renderWithTheme( - ', () => { ); const { getByText } = renderWithTheme( - {story()}] -} as ComponentMeta; +} as ComponentMeta; const categories = [ { @@ -98,7 +98,7 @@ export function Basic() { return (
- +
); @@ -125,7 +125,7 @@ export function Controlled() { - setSelected(id)} onNodeToggle={(_, ids) => setExpanded(ids)} @@ -145,7 +145,7 @@ export function Disabled() { return (
- +
); @@ -168,7 +168,7 @@ export function DisabledTreeItems() { return (
- +
); diff --git a/src/Tree/Tree.tsx b/src/TreeView/TreeView.tsx similarity index 94% rename from src/Tree/Tree.tsx rename to src/TreeView/TreeView.tsx index 2b321c5b..60d3f43d 100644 --- a/src/Tree/Tree.tsx +++ b/src/TreeView/TreeView.tsx @@ -1,8 +1,8 @@ import React, { forwardRef, useCallback } from 'react'; import styled, { css } from 'styled-components'; -import { StyledLabel, LabelText } from '../SwitchBase/SwitchBase'; import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled'; +import { LabelText, StyledLabel } from '../common/SwitchBase'; import { CommonStyledProps } from '../types'; type TreeLeaf = { @@ -13,7 +13,7 @@ type TreeLeaf = { label?: string; }; -type TreeProps = { +type TreeViewProps = { className?: string; defaultExpanded?: T[]; defaultSelected?: T; @@ -66,7 +66,7 @@ const focusedElementStyles = css<{ $disabled: boolean }>` : `cursor: default;`} `; -const TreeView = styled.ul<{ isRootLevel: boolean }>` +const TreeWrapper = styled.ul<{ isRootLevel: boolean }>` position: relative; isolation: isolate; @@ -293,7 +293,7 @@ function TreeBranch({ ); return ( - ({ isRootLevel={isRootLevel} > {tree.map(renderLeaf)} - + ); } @@ -317,7 +317,7 @@ function TreeInner( selected, style, tree = [] - }: TreeProps, + }: TreeViewProps, ref: React.ForwardedRef ) { const [expandedInternal, setExpandedInternal] = useControlledOrUncontrolled({ @@ -381,9 +381,13 @@ function TreeInner( ); } -const Tree = forwardRef(TreeInner) as ( +const TreeView = forwardRef(TreeInner) as ( // eslint-disable-next-line no-use-before-define - props: TreeProps & { ref?: React.ForwardedRef } + props: TreeViewProps & { ref?: React.ForwardedRef } ) => ReturnType; -export { Tree, TreeLeaf, TreeProps }; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +TreeView.displayProps = 'TreeView'; + +export { TreeView, TreeViewProps, TreeLeaf }; diff --git a/src/index.ts b/src/index.ts index ff4f7b92..81b67e7c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,7 +29,7 @@ export * from './Tabs/Tabs'; export * from './TextInput/TextInput'; export * from './Toolbar/Toolbar'; export * from './Tooltip/Tooltip'; -export * from './Tree/Tree'; +export * from './TreeView/TreeView'; export * from './Window/Window'; export * from './WindowContent/WindowContent'; export * from './WindowHeader/WindowHeader'; @@ -46,3 +46,4 @@ export * from './legacy/NumberField'; export * from './legacy/Panel'; export * from './legacy/Progress'; export * from './legacy/TextField'; +export * from './legacy/Tree'; diff --git a/src/legacy/Tree.tsx b/src/legacy/Tree.tsx new file mode 100644 index 00000000..31178be2 --- /dev/null +++ b/src/legacy/Tree.tsx @@ -0,0 +1,7 @@ +import { TreeView, TreeViewProps } from '../TreeView/TreeView'; + +/** @deprecated Use `TreeViewProps` */ +export type TreeProps = TreeViewProps; + +/** @deprecated Use `TreeView` */ +export const Tree = TreeView; From b3f0eca74d4b23e7890e8cab92f0f312c0434b57 Mon Sep 17 00:00:00 2001 From: Wes Souza Date: Sun, 31 Jul 2022 20:23:13 -0400 Subject: [PATCH 27/29] docs(window): categorize under Environment This also moves Windows* subcomponents to the Windows folder. --- src/DatePicker/DatePicker.tsx | 4 +- src/Window/Window.mdx | 86 ------------------- src/Window/Window.stories.tsx | 8 +- src/Window/Window.tsx | 32 ++++--- .../WindowContent.spec.tsx | 0 .../WindowContent.tsx | 2 + .../WindowHeader.spec.tsx | 0 src/{WindowHeader => Window}/WindowHeader.tsx | 0 src/index.ts | 2 - 9 files changed, 28 insertions(+), 106 deletions(-) delete mode 100644 src/Window/Window.mdx rename src/{WindowContent => Window}/WindowContent.spec.tsx (100%) rename src/{WindowContent => Window}/WindowContent.tsx (93%) rename src/{WindowHeader => Window}/WindowHeader.spec.tsx (100%) rename src/{WindowHeader => Window}/WindowHeader.tsx (100%) diff --git a/src/DatePicker/DatePicker.tsx b/src/DatePicker/DatePicker.tsx index b7ec857b..54853c37 100644 --- a/src/DatePicker/DatePicker.tsx +++ b/src/DatePicker/DatePicker.tsx @@ -7,9 +7,7 @@ import { ScrollView } from '../ScrollView/ScrollView'; import { Select } from '../Select/Select'; import { SelectChangeEvent } from '../Select/Select.types'; import { Toolbar } from '../Toolbar/Toolbar'; -import { Window } from '../Window/Window'; -import { WindowContent } from '../WindowContent/WindowContent'; -import { WindowHeader } from '../WindowHeader/WindowHeader'; +import { Window, WindowContent, WindowHeader } from '../Window/Window'; type DatePickerProps = { className?: string; diff --git a/src/Window/Window.mdx b/src/Window/Window.mdx deleted file mode 100644 index 70c88c0c..00000000 --- a/src/Window/Window.mdx +++ /dev/null @@ -1,86 +0,0 @@ ---- -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'; - -# Window - -## Usage - -#### Default - - - - - react95.exe - - - - - - - - -
    -
  • something here
  • -
  • something here
  • -
  • something here
  • -
  • something here
  • -
-
-
-
- -#### Resizable - - - - react95.exe - - Resizable Window displays resize handle in bottom right corner - - - - -#### Not active - - - - react95.exe - I am not active - - - -## API - -### Import - -``` -import { Window } from 'react95' -``` - -### Props - - diff --git a/src/Window/Window.stories.tsx b/src/Window/Window.stories.tsx index e27b4c62..06c88960 100644 --- a/src/Window/Window.stories.tsx +++ b/src/Window/Window.stories.tsx @@ -13,7 +13,7 @@ import styled from 'styled-components'; const Wrapper = styled.div` padding: 5rem; background: ${({ theme }) => theme.desktopBackground}; - .window-header { + .window-title { display: flex; align-items: center; justify-content: space-between; @@ -63,7 +63,7 @@ const Wrapper = styled.div` `; export default { - title: 'Window', + title: 'Environment/Window', component: Window, subcomponents: { WindowHeader, WindowContent }, decorators: [story => {story()}] @@ -73,7 +73,7 @@ export function Default() { return ( <> - + react95.exe