diff --git a/README.md b/README.md
index 68fdc7d2..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 { Divider, List, ListItem, 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
-
- 😴 Sleep
-
+
+ 🎤 Sing
+ 💃🏻 Dance
+
+ 😴 Sleep
+
);
diff --git a/docs/Getting-Started.stories.mdx b/docs/Getting-Started.stories.mdx
index 71947108..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 { Divider, List, ListItem, 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
-
- 😴 Sleep
-
+
+ 🎤 Sing
+ 💃🏻 Dance
+
+ 😴 Sleep
+
);
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 };
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
-
-
- )}
-
- Start
-
-
- );
- };
- 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..c8fc80e9 100644
--- a/src/AppBar/AppBar.stories.tsx
+++ b/src/AppBar/AppBar.stories.tsx
@@ -3,10 +3,10 @@ import React, { useState } from 'react';
import {
AppBar,
Button,
- Divider,
- List,
- ListItem,
- TextField,
+ MenuList,
+ MenuListItem,
+ Separator,
+ TextInput,
Toolbar
} from 'react95';
import styled from 'styled-components';
@@ -18,7 +18,7 @@ const Wrapper = styled.div`
`;
export default {
- title: 'AppBar',
+ title: 'Environment/AppBar',
component: AppBar,
decorators: [story => {story()} ]
} as ComponentMeta;
@@ -43,7 +43,7 @@ export function Default() {
Start
{open && (
- setOpen(false)}
>
-
+
👨💻
Profile
-
-
+
+
📁
My account
-
-
-
+
+
+
🔙
Logout
-
-
+
+
)}
-
+
);
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 };
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 };
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
-
-
-
-
-
- Edit
-
- Save
-
-
-
-
-
-
-## API
-
-### Import
-
-### Props
-
-
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
-
-
- Default
-
-
-#### Disabled
-
-
- Disabled
-
-
-#### Full Width
-
-
- Full Width
-
-
-#### Square
-
-
-
-
- 🎂
-
-
-
-
-#### Active
-
-
- Default
-
-
-#### Different sizes
-
-
-
- small
- medium
- large
-
-
-
-#### Flat
-
-
-
-
-
-
- When you want to use Buttons on a light background (like scrollable
- content), just use the flat variant:
-
-
-
-
- Primary
-
-
- Regular
-
-
- Disabled
-
-
-
-
-
-
-
-
-## 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(' ', () => {
rerender( );
expect(button).toHaveStyleRule('color', theme.materialTextDisabled);
expect(button).toHaveStyleRule('text-shadow', disabledTextShadow);
+
+ rerender( );
+ expect(button).toHaveStyleRule('color', theme.materialTextDisabled);
+ expect(button).toHaveStyleRule('text-shadow', disabledTextShadow);
});
it('should handle fullWidth prop', () => {
diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx
index 3e6237a1..a952fc24 100644
--- a/src/Button/Button.stories.tsx
+++ b/src/Button/Button.stories.tsx
@@ -2,10 +2,10 @@ import { ComponentMeta } from '@storybook/react';
import React, { useState } from 'react';
import {
Button,
- Cutout,
- Divider,
- List,
- ListItem,
+ MenuList,
+ MenuListItem,
+ ScrollView,
+ Separator,
Toolbar,
Window,
WindowContent,
@@ -29,7 +29,7 @@ const Wrapper = styled.div`
`;
export default {
- title: 'Button',
+ title: 'Controls/Button',
component: Button,
decorators: [story => {story()} ]
} as ComponentMeta;
@@ -63,9 +63,45 @@ Default.story = {
name: 'default'
};
+export function Flat() {
+ return (
+
+
+
+
+ When you want to use Buttons on a light background (like scrollable
+ content), just use the flat variant:
+
+
+
+
+ Primary
+
+
+ Regular
+
+
+ Disabled
+
+
+
+
+
+
+ );
+}
+
+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
-
+
Upload
-
+
Save
setOpen(!open)}
size='sm'
active={open}
@@ -99,7 +135,7 @@ export function Menu() {
Share
{open && (
-
setOpen(false)}
>
- Copy link
-
- Facebook
- Twitter
- Instagram
-
-
+ Copy link
+
+ Facebook
+ Twitter
+ Instagram
+
+
MySpace
-
-
+
+
)}
-
+
-
+
);
}
-Menu.story = {
- name: 'menu'
-};
-
-export function Flat() {
- return (
-
-
-
-
- When you want to use Buttons on a light background (like scrollable
- content), just use the flat variant:
-
-
-
-
- Primary
-
-
- Regular
-
-
- Disabled
-
-
-
-
-
-
- );
-}
-
-Flat.story = {
- name: 'flat'
+Thin.story = {
+ name: 'thin'
};
diff --git a/src/Button/Button.tsx b/src/Button/Button.tsx
index e74a2547..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';
@@ -24,11 +23,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,18 +100,20 @@ export const StyledButton = styled.button`
outline-offset: -4px;
}
`
- : variant === 'menu'
+ : variant === 'menu' || variant === 'thin'
? css`
${createBoxStyles()};
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`
@@ -156,41 +165,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 };
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 (
-
-
-
-
-
-
-
-
-
- Diet mode
-
-
- );
- }}
-
-
-#### 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..b03326dc 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, Divider } from 'react95';
import { ComponentMeta } from '@storybook/react';
+import {
+ Checkbox,
+ GroupBox,
+ MenuList,
+ MenuListItem,
+ ScrollView,
+ Separator
+} from 'react95';
const Wrapper = styled.div`
background: ${({ theme }) => theme.material};
@@ -19,7 +26,7 @@ const Wrapper = styled.div`
`;
export default {
- title: 'Checkbox',
+ title: 'Controls/Checkbox',
component: Checkbox,
decorators: [story => {story()} ]
} as ComponentMeta;
@@ -71,7 +78,7 @@ export function Default() {
return (
-
+
-
+
+
-
+
-
+
-
+
);
}
@@ -233,8 +240,8 @@ Flat.story = {
export function Menu() {
return (
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
+
+
);
}
diff --git a/src/Checkbox/Checkbox.tsx b/src/Checkbox/Checkbox.tsx
index 777d10d0..1b245ebd 100644
--- a/src/Checkbox/Checkbox.tsx
+++ b/src/Checkbox/Checkbox.tsx
@@ -3,15 +3,15 @@ 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 { StyledListItem } from '../ListItem/ListItem';
import {
LabelText,
size,
StyledInput,
StyledLabel
-} from '../SwitchBase/SwitchBase';
+} from '../common/SwitchBase';
+import { noOp } from '../common/utils';
+import { StyledMenuListItem } from '../MenuList/MenuList';
+import { StyledScrollView } from '../ScrollView/ScrollView';
import { CommonThemeProps } from '../types';
type CheckboxProps = {
@@ -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;
@@ -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
})}
@@ -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 handleChange = useCallback(
+ (e: React.ChangeEvent) => {
+ const newState = e.target.checked;
+ setState(newState);
+ onChange(e);
+ },
+ [onChange, setState]
+ );
+
+ const CheckboxComponent = CheckboxComponents[variant];
- const CheckboxComponent = CheckboxComponents[variant];
+ let Icon = null;
+ if (indeterminate) {
+ Icon = IndeterminateIcon;
+ } else if (state) {
+ Icon = CheckmarkIcon;
+ }
- 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 };
diff --git a/src/ColorInput/ColorInput.stories.tsx b/src/ColorInput/ColorInput.stories.tsx
index 93ce49dd..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};
@@ -28,7 +28,7 @@ const Wrapper = styled.div`
`;
export default {
- title: 'ColorInput',
+ title: 'Controls/ColorInput',
component: ColorInput,
decorators: [story => {story()} ]
} as ComponentMeta;
@@ -50,7 +50,7 @@ Default.story = {
export function Flat() {
return (
-
+
enabled:
@@ -61,7 +61,7 @@ export function Flat() {
-
+
);
}
diff --git a/src/ColorInput/ColorInput.tsx b/src/ColorInput/ColorInput.tsx
index bd98b407..70adaeeb 100644
--- a/src/ColorInput/ColorInput.tsx
+++ b/src/ColorInput/ColorInput.tsx
@@ -4,7 +4,7 @@ import { StyledButton } from '../Button/Button';
import { focusOutline } from '../common';
import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled';
import { noOp } from '../common/utils';
-import { Divider } from '../Divider/Divider';
+import { Separator } from '../Separator/Separator';
import { CommonStyledProps } from '../types';
type ColorInputProps = {
@@ -23,7 +23,7 @@ const Trigger = styled(StyledButton)`
padding-left: 8px;
`;
-const StyledDivider = styled(Divider)`
+const StyledSeparator = styled(Separator)`
height: 21px;
position: relative;
top: 0;
@@ -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
@@ -156,11 +156,13 @@ const ColorInput = forwardRef(
color={valueDerived ?? '#008080'}
role='presentation'
/>
- {variant === 'default' && }
+ {variant === 'default' && }
);
}
);
+ColorInput.displayName = 'ColorInput';
+
export { ColorInput, ColorInputProps };
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..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`
@@ -20,7 +20,7 @@ const Wrapper = styled.div`
`;
export default {
- title: 'Counter',
+ title: 'Other/Counter',
component: Counter,
decorators: [story => {story()} ]
} as ComponentMeta;
@@ -29,14 +29,14 @@ export function Default() {
const [count, setCount] = useState(13);
const handleClick = () => setCount(count + 1);
return (
-
+
Click!
-
+
);
}
diff --git a/src/Counter/Counter.tsx b/src/Counter/Counter.tsx
index 9e468b2f..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;
`;
@@ -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 };
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.mdx b/src/DatePicker/DatePicker.mdx
deleted file mode 100644
index 259727d5..00000000
--- a/src/DatePicker/DatePicker.mdx
+++ /dev/null
@@ -1,26 +0,0 @@
----
-name: DatePicker
-menu: Components
----
-
-import { DatePicker } from './DatePicker';
-
-# DatePicker
-
-## Usage
-
-
- console.log(date)} />
-
-
-## API
-
-### Import
-
-```
-import { DatePicker } from 'react95'
-```
-
-### Props
-
-
diff --git a/src/DatePicker/DatePicker.tsx b/src/DatePicker/DatePicker.tsx
index 4b4521c2..a8aaaf10 100644
--- a/src/DatePicker/DatePicker.tsx
+++ b/src/DatePicker/DatePicker.tsx
@@ -2,14 +2,12 @@ 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 { NumberInput } from '../NumberInput/NumberInput';
+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;
@@ -19,7 +17,7 @@ type DatePickerProps = {
shadow?: boolean;
};
-const Calendar = styled(Cutout)`
+const Calendar = styled(ScrollView)`
width: 234px;
margin: 1rem 0;
background: ${({ theme }) => theme.canvas};
@@ -175,7 +173,7 @@ const DatePicker = forwardRef(
width={128}
menuMaxHeight={200}
/>
-
+
@@ -207,5 +205,7 @@ const DatePicker = forwardRef(
}
);
+DatePicker.displayName = 'DatePicker';
+
// eslint-disable-next-line camelcase
export { DatePicker as DatePicker__UNSTABLE, DatePickerProps };
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/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/Divider/Divider.stories.tsx b/src/Divider/Divider.stories.tsx
deleted file mode 100644
index 4f697e29..00000000
--- a/src/Divider/Divider.stories.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import { ComponentMeta } from '@storybook/react';
-import React from 'react';
-import styled from 'styled-components';
-
-import { Divider, List, ListItem } from 'react95';
-
-const Wrapper = styled.div`
- padding: 5rem;
- background: ${({ theme }) => theme.desktopBackground};
-`;
-
-export default {
- title: 'Divider',
- component: Divider,
- decorators: [story => {story()} ]
-} as ComponentMeta;
-
-export function Default() {
- return (
- <>
-
- Item 1
-
- Item 2
-
- Item 3
-
-
- Item 1
-
- Item 2
-
- Item 3
-
- >
- );
-}
-
-Default.story = {
- name: 'default'
-};
diff --git a/src/Fieldset/Fieldset.mdx b/src/Fieldset/Fieldset.mdx
deleted file mode 100644
index 2880426c..00000000
--- a/src/Fieldset/Fieldset.mdx
+++ /dev/null
@@ -1,103 +0,0 @@
----
-name: Fieldset
-menu: Components
----
-
-import Fieldset from './Fieldset'
-import Window from '../Window/Window'
-import WindowContent from '../WindowContent/WindowContent'
-import Checkbox from '../Checkbox/Checkbox'
-import { Cutout } from '../Cutout/Cutout';
-
-# Fieldset
-
-## Usage
-
-#### Default
-
-
-
-
-
- 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/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/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 76%
rename from src/Fieldset/Fieldset.stories.tsx
rename to src/GroupBox/GroupBox.stories.tsx
index 819fcafa..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, Cutout, Fieldset, 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
😍
-
+
);
@@ -44,23 +44,23 @@ export function Flat() {
return (
-
-
+
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/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 (
-
+
Edit
Save
-
+
);
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/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 };
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/List/List.stories.tsx b/src/List/List.stories.tsx
deleted file mode 100644
index b365fcb6..00000000
--- a/src/List/List.stories.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { ComponentMeta } from '@storybook/react';
-import React from 'react';
-import styled from 'styled-components';
-
-import { Bar, Divider, List, ListItem } from 'react95';
-
-const Wrapper = styled.div`
- padding: 5rem;
- background: ${({ theme }) => theme.desktopBackground};
- display: flex;
- align-items: center;
- & > * {
- margin-right: 1rem;
- }
-`;
-
-export default {
- title: 'List',
- component: List,
- subcomponents: { ListItem },
- decorators: [story => {story()} ]
-} as ComponentMeta;
-
-export function Default() {
- return (
- <>
-
- Photos
-
- Link
-
- Other
-
-
-
-
- 🌿
-
-
-
- Tackle
- Growl
- Razor Leaf
-
-
-
- View
-
-
- Paste
- Paste Shortcut
- Undo Copy
-
- Properties
-
-
-
-
- 😎
-
-
-
-
- 🤖
-
-
-
-
- 🎁
-
-
-
- >
- );
-}
-
-Default.story = {
- name: 'default'
-};
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/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 78457d71..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 { StyledCutout } from '../Cutout/Cutout';
-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(StyledCutout)`
- 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/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/MenuList/MenuList.stories.tsx b/src/MenuList/MenuList.stories.tsx
new file mode 100644
index 00000000..05633a91
--- /dev/null
+++ b/src/MenuList/MenuList.stories.tsx
@@ -0,0 +1,85 @@
+import { ComponentMeta } from '@storybook/react';
+import React from 'react';
+import { Handle, MenuList, MenuListItem, Separator } from 'react95';
+import styled from 'styled-components';
+
+const Wrapper = styled.div`
+ padding: 5rem;
+ background: ${({ theme }) => theme.desktopBackground};
+ display: flex;
+ align-items: center;
+ & > * {
+ margin-right: 1rem;
+ }
+`;
+
+export default {
+ title: 'Controls/MenuList',
+ component: MenuList,
+ subcomponents: { MenuListItem },
+ decorators: [story => {story()} ]
+} as ComponentMeta;
+
+export function Default() {
+ return (
+ <>
+
+ Photos
+
+ Link
+
+ Other
+
+
+
+
+ 🌿
+
+
+
+ Tackle
+ Growl
+ Razor Leaf
+
+
+
+ View
+
+
+ Paste
+ Paste Shortcut
+ Undo Copy
+
+ Properties
+
+
+
+
+ 😎
+
+
+
+
+ 🤖
+
+
+
+
+ 🎁
+
+
+
+ >
+ );
+}
+
+Default.story = {
+ name: 'default'
+};
diff --git a/src/List/List.tsx b/src/MenuList/MenuList.tsx
similarity index 67%
rename from src/List/List.tsx
rename to src/MenuList/MenuList.tsx
index 2a175c3f..57b57848 100644
--- a/src/List/List.tsx
+++ b/src/MenuList/MenuList.tsx
@@ -4,20 +4,20 @@ 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;
- ${createBorderStyles({ windowBorders: true })}
+ ${createBorderStyles({ style: 'window' })}
${createBoxStyles()}
${props =>
props.inline &&
@@ -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/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 81%
rename from src/Desktop/Desktop.tsx
rename to src/Monitor/Monitor.tsx
index 22541bb0..8abfa45e 100644
--- a/src/Desktop/Desktop.tsx
+++ b/src/Monitor/Monitor.tsx
@@ -1,9 +1,9 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
-import { StyledCutout } from '../Cutout/Cutout';
+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;
@@ -56,7 +56,7 @@ const Monitor = styled.div`
}
`;
-const Background = styled(StyledCutout).attrs(() => ({
+const Background = styled(StyledScrollView).attrs(() => ({
'data-testid': 'background'
}))`
width: 100%;
@@ -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/NumberField/NumberField.mdx b/src/NumberField/NumberField.mdx
deleted file mode 100644
index eeba5ce1..00000000
--- a/src/NumberField/NumberField.mdx
+++ /dev/null
@@ -1,78 +0,0 @@
----
-name: NumberField
-menu: Components
----
-
-import { NumberField } from './NumberField';
-import { Cutout } from '../Cutout/Cutout';
-
-# 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 61%
rename from src/NumberField/NumberField.stories.tsx
rename to src/NumberInput/NumberInput.stories.tsx
index 84f5b93e..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 { Cutout, NumberField } 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 (
<>
-
+
-
+
-
+
>
);
}
@@ -44,12 +44,12 @@ Default.story = {
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 90%
rename from src/NumberField/NumberField.tsx
rename to src/NumberInput/NumberInput.tsx
index 76931564..7ef5d3f4 100644
--- a/src/NumberField/NumberField.tsx
+++ b/src/NumberInput/NumberInput.tsx
@@ -5,10 +5,10 @@ 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 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,14 +156,14 @@ const NumberField = forwardRef(
}, [handleClick, step]);
return (
-
- (
-
+
);
}
);
-export { NumberField, NumberFieldProps };
+NumberInput.displayName = 'NumberInput';
+
+export { NumberInput, NumberInputProps };
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/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 79ea5cd7..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 { StyledCutout } from '../Cutout/Cutout';
-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(StyledCutout)`
- 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/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 0abd89ae..a36b1543 100644
--- a/src/Radio/Radio.stories.tsx
+++ b/src/Radio/Radio.stories.tsx
@@ -1,12 +1,12 @@
import { ComponentMeta } from '@storybook/react';
import React, { useState } from 'react';
import {
- Cutout,
- Divider,
- Fieldset,
- List,
- ListItem,
+ GroupBox,
+ MenuList,
+ MenuListItem,
Radio,
+ ScrollView,
+ Separator,
Window,
WindowContent
} from 'react95';
@@ -26,7 +26,7 @@ const Wrapper = styled.div`
}
`;
export default {
- title: 'Radio',
+ title: 'Controls/Radio',
component: Radio,
decorators: [story => {story()} ]
} as ComponentMeta;
@@ -39,7 +39,7 @@ export function Default() {
return (
-
+
-
+
);
@@ -90,13 +90,13 @@ export function Flat() {
return (
-
+
When you want to use radio buttons on a light background (like
scrollable content), just use the flat variant:
-
+
-
-
+
+
);
@@ -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 b1bee405..f49b51ca 100644
--- a/src/Radio/Radio.tsx
+++ b/src/Radio/Radio.tsx
@@ -2,14 +2,14 @@ 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 {
LabelText,
size,
StyledInput,
StyledLabel
-} from '../SwitchBase/SwitchBase';
+} from '../common/SwitchBase';
+import { StyledMenuListItem } from '../MenuList/MenuList';
+import { StyledScrollView } from '../ScrollView/ScrollView';
import { CommonStyledProps } from '../types';
type RadioVariant = 'default' | 'flat' | 'menu';
@@ -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};
@@ -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' &&
@@ -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 };
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
deleted file mode 100644
index 41086103..00000000
--- a/src/Select/Select.mdx
+++ /dev/null
@@ -1,143 +0,0 @@
----
-name: Select
-menu: Components
----
-
-import { Select } from './Select';
-import Window from '../Window/Window';
-import WindowContent from '../WindowContent/WindowContent';
-import { Cutout } from '../Cutout/Cutout';
-
-# 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)}
- width={150}
- />
- );
- }}
-
-
-#### Fixed Height
-
-
- {() => {
- 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)}
- />
- );
- }}
-
-
-#### Flat
-
-
- {() => {
- 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 (
-
-
-
-
- When you want to use Select on a light background (like scrollable
- content), just use the flat variant:
-
-
- 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 3184100a..a0621276 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 { GroupBox, ScrollView, Select, Window, WindowContent } from 'react95';
import styled from 'styled-components';
import { SelectChangeEvent, SelectOption } from './Select.types';
@@ -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;
@@ -51,7 +51,7 @@ export default {
export function Default() {
return (
-
+
-
-
+
+
-
+
);
}
@@ -106,12 +106,12 @@ export function Flat() {
return (
-
+
When you want to use Select on a light background (like scrollable
content), just use the flat variant:
-
+
-
-
+
+
-
-
+
+
);
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/Separator/Separator.spec.tsx b/src/Separator/Separator.spec.tsx
new file mode 100644
index 00000000..2e8c8e86
--- /dev/null
+++ b/src/Separator/Separator.spec.tsx
@@ -0,0 +1,74 @@
+import React from 'react';
+
+import { renderWithTheme } from '../../test/utils';
+
+import { Separator } from './Separator';
+
+describe(' ', () => {
+ 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/Separator/Separator.stories.tsx b/src/Separator/Separator.stories.tsx
new file mode 100644
index 00000000..030e95f9
--- /dev/null
+++ b/src/Separator/Separator.stories.tsx
@@ -0,0 +1,41 @@
+import { ComponentMeta } from '@storybook/react';
+import React from 'react';
+import styled from 'styled-components';
+
+import { MenuList, MenuListItem, Separator } from 'react95';
+
+const Wrapper = styled.div`
+ padding: 5rem;
+ background: ${({ theme }) => theme.desktopBackground};
+`;
+
+export default {
+ title: 'Layout/Separator',
+ component: Separator,
+ decorators: [story => {story()} ]
+} as ComponentMeta;
+
+export function Default() {
+ return (
+ <>
+
+ Item 1
+
+ Item 2
+
+ Item 3
+
+
+ Item 1
+
+ Item 2
+
+ Item 3
+
+ >
+ );
+}
+
+Default.story = {
+ name: 'default'
+};
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/Slider/Slider.stories.tsx b/src/Slider/Slider.stories.tsx
index 6f1f453d..b7b96466 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`
@@ -35,7 +35,7 @@ const Wrapper = styled.div`
`;
export default {
- title: 'Slider',
+ title: 'Controls/Slider',
component: Slider,
decorators: [story => {story()} ]
} as ComponentMeta;
@@ -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..574229ad 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};
@@ -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 };
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 304cb0e2..9f82c79b 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,23 +16,30 @@ const StyledTable = styled.table`
font-size: 1rem;
`;
-const Wrapper = styled(StyledCutout)`
+const Wrapper = styled(StyledScrollView)`
&:before {
box-shadow: none;
}
`;
-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 95%
rename from src/TableHeadCell/TableHeadCell.tsx
rename to src/Table/TableHeadCell.tsx
index dd4c359d..e653d6b6 100644
--- a/src/TableHeadCell/TableHeadCell.tsx
+++ b/src/Table/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;
@@ -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/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 c39489aa..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 { NumberField } from '../NumberField/NumberField';
-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 (
-
- {value === activeTab &&
{children}
}
-
- );
- };
- 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 5ba196d3..26a47afb 100644
--- a/src/Tabs/Tabs.stories.tsx
+++ b/src/Tabs/Tabs.stories.tsx
@@ -3,8 +3,8 @@ import React, { useState } from 'react';
import {
Anchor,
Checkbox,
- Fieldset,
- NumberField,
+ GroupBox,
+ NumberInput,
Tab,
TabBody,
Tabs,
@@ -20,7 +20,7 @@ const Wrapper = styled.div`
`;
export default {
- title: 'Tabs',
+ title: 'Controls/Tabs',
component: Tabs,
subcomponents: { Tab, TabBody },
decorators: [story => {story()} ]
@@ -49,9 +49,9 @@ export function Default() {
{activeTab === 0 && (
-
+
Amount:
-
+
null}
defaultChecked
/>
-
+
)}
{activeTab === 1 && (
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/TextField/TextField.mdx b/src/TextField/TextField.mdx
deleted file mode 100644
index 0ea168dd..00000000
--- a/src/TextField/TextField.mdx
+++ /dev/null
@@ -1,112 +0,0 @@
----
-name: TextField
-menu: Components
----
-
-import { TextField } from './TextField';
-import { Cutout } from '../Cutout/Cutout';
-
-# TextField
-
-## Usage
-
-#### Default
-
-
- 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:
-
-
-
- Name:
-
- 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:
-
-
-
- Name:
-
- 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 86%
rename from src/TextField/TextField.stories.tsx
rename to src/TextInput/TextInout.stories.tsx
index f9134231..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, Cutout, 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 (
-
-
+
-
+
-
+
When you want to add input field on a light background (like scrollable
content), just use the flat variant:
-
-
-
-
-
+
);
}
diff --git a/src/TextField/TextField.spec.tsx b/src/TextInput/TextInput.spec.tsx
similarity index 81%
rename from src/TextField/TextField.spec.tsx
rename to src/TextInput/TextInput.spec.tsx
index be6cf9ab..ad647f81 100644
--- a/src/TextField/TextField.spec.tsx
+++ b/src/TextInput/TextInput.spec.tsx
@@ -4,11 +4,11 @@ import React from 'react';
import { fireEvent } from '@testing-library/react';
import { renderWithTheme } from '../../test/utils';
-import { TextField } from './TextField';
+import { TextInput } from './TextInput';
-describe(' ', () => {
+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 57%
rename from src/TextField/TextField.tsx
rename to src/TextInput/TextInput.tsx
index 8014c57f..11f92999 100644
--- a/src/TextField/TextField.tsx
+++ b/src/TextInput/TextInput.tsx
@@ -7,10 +7,10 @@ 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 = {
+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`
@@ -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}
@@ -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/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
-
-
-
- Whad do I do?
-
-
-
-## 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 };
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 = [
{
@@ -97,9 +97,9 @@ categories.forEach(getIds);
export function Basic() {
return (
-
-
-
+
+
+
);
}
@@ -124,15 +124,15 @@ export function Controlled() {
-
-
+ setSelected(id)}
onNodeToggle={(_, ids) => setExpanded(ids)}
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/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/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
-
-
- X
-
-
-
-
-
- File
-
-
- Edit
-
-
- Save
-
-
-
-
- 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 050a044e..06c88960 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,
@@ -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
@@ -97,13 +97,13 @@ export function Default() {
you tho!)
-
+
Put some useful information here
-
+
-
+
not-active.exe
diff --git a/src/Window/Window.tsx b/src/Window/Window.tsx
index a8b10eab..79c003dd 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()}
`;
@@ -47,16 +47,26 @@ const ResizeHandle = styled.span`
`}
`;
-const Window = forwardRef(function Window(
- { children, resizable = false, resizeRef, shadow = true, ...otherProps },
- ref
-) {
- return (
-
- {children}
- {resizable && }
-
- );
-});
+const Window = forwardRef(
+ (
+ { children, resizable = false, resizeRef, shadow = true, ...otherProps },
+ ref
+ ) => {
+ return (
+
+ {children}
+ {resizable && (
+
+ )}
+
+ );
+ }
+);
+
+Window.displayName = 'Window';
+
+export * from './WindowContent';
+
+export * from './WindowHeader';
export { Window, WindowProps };
diff --git a/src/WindowContent/WindowContent.spec.tsx b/src/Window/WindowContent.spec.tsx
similarity index 100%
rename from src/WindowContent/WindowContent.spec.tsx
rename to src/Window/WindowContent.spec.tsx
diff --git a/src/WindowContent/WindowContent.tsx b/src/Window/WindowContent.tsx
similarity index 93%
rename from src/WindowContent/WindowContent.tsx
rename to src/Window/WindowContent.tsx
index 96123ef1..7206ef7a 100644
--- a/src/WindowContent/WindowContent.tsx
+++ b/src/Window/WindowContent.tsx
@@ -21,4 +21,6 @@ const WindowContent = forwardRef(
}
);
+WindowContent.displayName = 'WindowContent';
+
export { WindowContent, WindowContentProps };
diff --git a/src/WindowHeader/WindowHeader.spec.tsx b/src/Window/WindowHeader.spec.tsx
similarity index 100%
rename from src/WindowHeader/WindowHeader.spec.tsx
rename to src/Window/WindowHeader.spec.tsx
diff --git a/src/WindowHeader/WindowHeader.tsx b/src/Window/WindowHeader.tsx
similarity index 100%
rename from src/WindowHeader/WindowHeader.tsx
rename to src/Window/WindowHeader.tsx
diff --git a/src/SwitchBase/SwitchBase.ts b/src/common/SwitchBase.ts
similarity index 85%
rename from src/SwitchBase/SwitchBase.ts
rename to src/common/SwitchBase.ts
index 9c7b7de9..717e268f 100644
--- a/src/SwitchBase/SwitchBase.ts
+++ b/src/common/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 '.';
+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/common/hooks/useForkRef.spec.tsx b/src/common/hooks/useForkRef.spec.tsx
index 2e3395ee..9218a225 100644
--- a/src/common/hooks/useForkRef.spec.tsx
+++ b/src/common/hooks/useForkRef.spec.tsx
@@ -36,10 +36,7 @@ describe('useForkRef', () => {
});
it('forks if only one of the branches requires a ref', () => {
- const Component = React.forwardRef(function Component(
- _,
- ref
- ) {
+ const Component = React.forwardRef((_, ref) => {
const [hasRef, setHasRef] = useState(false);
const handleOwnRef = useCallback(() => setHasRef(true), []);
const handleRef = useForkRef(handleOwnRef, ref);
@@ -60,10 +57,7 @@ describe('useForkRef', () => {
children: React.ReactElement;
};
- const Outer = React.forwardRef(function Outer(
- props,
- ref
- ) {
+ const Outer = React.forwardRef((props, ref) => {
const { children } = props;
// TODO: Fix this test as reading ref from children is not allowed so not available on React types
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 54e30e3c..4e6b18a0 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -6,39 +6,42 @@ 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';
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 './Frame/Frame';
+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 './NumberField/NumberField';
-export * from './Panel/Panel';
-export * from './Progress/Progress';
+export * from './MenuList/MenuList';
+export * from './Monitor/Monitor';
+export * from './NumberInput/NumberInput';
+export * from './ProgressBar/ProgressBar';
export * from './Radio/Radio';
+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';
-export * from './TableHead/TableHead';
-export * from './TableHeadCell/TableHeadCell';
-export * from './TableRow/TableRow';
export * from './Tabs/Tabs';
-export * from './TextField/TextField';
+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';
+
+/* deprecated components */
+export * from './legacy/Bar';
+export * from './legacy/Cutout';
+export * from './legacy/Desktop';
+export * from './legacy/Divider';
+export * from './legacy/Fieldset';
+export * from './legacy/List';
+export * from './legacy/ListItem';
+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/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;
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;
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;
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;
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;
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;
diff --git a/src/legacy/NumberField.tsx b/src/legacy/NumberField.tsx
new file mode 100644
index 00000000..54f015b8
--- /dev/null
+++ b/src/legacy/NumberField.tsx
@@ -0,0 +1,7 @@
+import { NumberInput, NumberInputProps } from '../NumberInput/NumberInput';
+
+/** @deprecated Use `NumberInputProps` */
+export type NumberFieldProps = NumberInputProps;
+
+/** @deprecated Use `NumberInput` */
+export const NumberField = NumberInput;
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;
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;
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;
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;