diff --git a/.storybook/main.ts b/.storybook/main.ts
index e3d6d47a..a60e41f5 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -15,7 +15,7 @@ const storybookConfig: StorybookConfig = {
}
},
'@storybook/addon-storysource',
- './theme-picker/register.ts'
+ './theme-settings/register.ts'
],
core: {
builder: 'webpack5'
diff --git a/.storybook/preview.ts b/.storybook/preview.ts
index 088dfca6..70151b31 100644
--- a/.storybook/preview.ts
+++ b/.storybook/preview.ts
@@ -1,8 +1,8 @@
import { DecoratorFn, Parameters } from '@storybook/react';
import { withGlobalStyle } from './decorators/withGlobalStyle';
-import { withThemesProvider } from './theme-picker/ThemeProvider';
+import { withThemeSettings } from './theme-settings/ThemeProvider';
-export const decorators: DecoratorFn[] = [withGlobalStyle, withThemesProvider];
+export const decorators: DecoratorFn[] = [withGlobalStyle, withThemeSettings];
export const parameters: Parameters = {
layout: 'fullscreen',
diff --git a/.storybook/theme-picker/ThemeList.tsx b/.storybook/theme-picker/ThemeList.tsx
deleted file mode 100644
index 87e111b7..00000000
--- a/.storybook/theme-picker/ThemeList.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import { useAddonState } from '@storybook/api';
-import React, { useCallback } from 'react';
-import styled from 'styled-components';
-
-import themes from '../../src/common/themes';
-import { Theme } from '../../src/types';
-import { THEMES_ID } from './constants';
-import { ThemeButton } from './ThemeButton';
-
-const {
- original,
- rainyDay,
- vaporTeal,
- theSixtiesUSA,
- olive,
- tokyoDark,
- rose,
- plum,
- matrix,
- travel,
- ...otherThemes
-} = themes;
-
-const themeList = [
- original,
- rainyDay,
- vaporTeal,
- theSixtiesUSA,
- olive,
- tokyoDark,
- rose,
- plum,
- matrix,
- travel,
- ...Object.values(otherThemes)
-];
-
-type ThemesProps = {
- active?: boolean;
-};
-
-const Wrapper = styled.div<{ theme: Theme }>`
- display: grid;
- padding: 1em;
- gap: 1em;
- grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
- grid-template-rows: repeat(auto-fill, 40px);
- background-color: ${({ theme }) => theme.material};
-`;
-
-export function ThemeList({ active }: ThemesProps) {
- const [themeName, setThemeName] = useAddonState(THEMES_ID, 'original');
-
- const handleChoose = useCallback(
- (newThemeName: string) => {
- setThemeName(newThemeName);
- },
- [setThemeName]
- );
-
- if (!active) {
- return <>>;
- }
-
- return (
-
- {themeList.map(theme => (
-
- ))}
-
- );
-}
diff --git a/.storybook/theme-picker/ThemeProvider.tsx b/.storybook/theme-picker/ThemeProvider.tsx
deleted file mode 100644
index e8dd4e2a..00000000
--- a/.storybook/theme-picker/ThemeProvider.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { useAddonState } from '@storybook/client-api';
-import { DecoratorFn } from '@storybook/react';
-import React from 'react';
-import { ThemeProvider } from 'styled-components';
-
-import themes from '../../src/common/themes/index';
-import { THEMES_ID } from './constants';
-
-export const withThemesProvider: DecoratorFn = story => {
- const [themeName] = useAddonState(THEMES_ID, 'original');
-
- return (
-
- {story()}
-
- );
-};
diff --git a/.storybook/theme-picker/ThemeButton.tsx b/.storybook/theme-settings/ThemeButton.tsx
similarity index 79%
rename from .storybook/theme-picker/ThemeButton.tsx
rename to .storybook/theme-settings/ThemeButton.tsx
index 87c57329..53844113 100644
--- a/.storybook/theme-picker/ThemeButton.tsx
+++ b/.storybook/theme-settings/ThemeButton.tsx
@@ -1,6 +1,6 @@
import React, { useCallback } from 'react';
import { ThemeProvider } from 'styled-components';
-import { Button } from '../../src/Button/Button';
+import { Button } from '../../src/index';
import { Theme } from '../../src/types';
export function ThemeButton({
@@ -9,11 +9,11 @@ export function ThemeButton({
theme
}: {
active: boolean;
- onChoose: (themeName: string) => void;
+ onChoose: (theme: Theme) => void;
theme: Theme;
}) {
const handleClick = useCallback(() => {
- onChoose(theme.name);
+ onChoose(theme);
}, []);
return (
diff --git a/.storybook/theme-settings/ThemeProvider.tsx b/.storybook/theme-settings/ThemeProvider.tsx
new file mode 100644
index 00000000..a537d3c9
--- /dev/null
+++ b/.storybook/theme-settings/ThemeProvider.tsx
@@ -0,0 +1,41 @@
+import { useAddonState } from '@storybook/client-api';
+import { DecoratorFn } from '@storybook/react';
+import React from 'react';
+import { createGlobalStyle, ThemeProvider } from 'styled-components';
+
+import themes from '../../src/common/themes/index';
+import { SCALE } from '../../src/common/constants';
+import { Theme } from '../../src/common/themes/types';
+import { THEMES_ID } from './constants';
+
+const GlobalScaledFont = createGlobalStyle`
+ html {
+ font-size: ${({ theme }: { theme: Theme }) =>
+ (theme?.scale ?? SCALE) * 2 + 12}px;
+ }
+`;
+
+export const withThemeSettings: DecoratorFn = story => {
+ const [themeName] = useAddonState(`${THEMES_ID}/themeName`, 'original');
+ const [themeScale] = useAddonState(
+ `${THEMES_ID}/themeScale`,
+ themes.original.scale
+ );
+ const [themeShadow] = useAddonState(
+ `${THEMES_ID}/themeShadow`,
+ themes.original.shadow
+ );
+
+ const theme: Theme = {
+ ...themes[themeName],
+ scale: themeScale,
+ shadow: themeShadow
+ };
+
+ return (
+
+
+ {story()}
+
+ );
+};
diff --git a/.storybook/theme-settings/ThemeSettings.tsx b/.storybook/theme-settings/ThemeSettings.tsx
new file mode 100644
index 00000000..4f1f6b18
--- /dev/null
+++ b/.storybook/theme-settings/ThemeSettings.tsx
@@ -0,0 +1,135 @@
+import { useAddonState } from '@storybook/api';
+import React, { useCallback } from 'react';
+import styled, { ThemeProvider } from 'styled-components';
+import { SCALE } from '../../src/common/constants';
+
+import themes from '../../src/common/themes';
+import { Checkbox, GroupBox, Slider } from '../../src/index';
+import { Theme } from '../../src/types';
+import { THEMES_ID } from './constants';
+import { ThemeButton } from './ThemeButton';
+
+const {
+ original,
+ rainyDay,
+ vaporTeal,
+ theSixtiesUSA,
+ olive,
+ tokyoDark,
+ rose,
+ plum,
+ matrix,
+ travel,
+ ...otherThemes
+} = themes;
+
+const themeList = [
+ original,
+ rainyDay,
+ vaporTeal,
+ theSixtiesUSA,
+ olive,
+ tokyoDark,
+ rose,
+ plum,
+ matrix,
+ travel,
+ ...Object.values(otherThemes)
+];
+
+type ThemesProps = {
+ active?: boolean;
+};
+
+const Wrapper = styled.div<{ theme: Theme }>`
+ padding: 1em;
+ background-color: ${({ theme }) => theme.material};
+`;
+
+const ThemesGrid = styled.div`
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
+ grid-template-rows: repeat(auto-fill, 40px);
+ gap: 1em;
+ margin-bottom: 1em;
+`;
+
+const marks = [
+ { label: '1', value: 1 },
+ { label: '2', value: 2 },
+ { label: '3', value: 3 },
+ { label: '4', value: 4 },
+ { label: '5', value: 5 }
+];
+
+export function ThemeSettings({ active }: ThemesProps) {
+ const [themeName, setThemeName] = useAddonState(
+ `${THEMES_ID}/themeName`,
+ 'original'
+ );
+ const [themeScale, setThemeScale] = useAddonState(
+ `${THEMES_ID}/themeScale`,
+ themes.original.scale
+ );
+ const [themeShadow, setThemeShadow] = useAddonState(
+ `${THEMES_ID}/themeShadow`,
+ themes.original.shadow
+ );
+
+ const handleChoose = useCallback(
+ (newTheme: Theme) => {
+ setThemeName(newTheme.name);
+ },
+ [setThemeName]
+ );
+
+ const handleShadowChange = useCallback(
+ (event: React.ChangeEvent) => {
+ const checked = (event.target as HTMLInputElement).checked;
+ setThemeShadow(checked);
+ },
+ []
+ );
+
+ const handleScaleChange = useCallback(
+ (_: Event | React.SyntheticEvent, value: number) => {
+ setThemeScale(value);
+ },
+ []
+ );
+
+ if (!active) {
+ return <>>;
+ }
+
+ return (
+
+
+ {themeList.map(theme => (
+
+ ))}
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/.storybook/theme-picker/constants.ts b/.storybook/theme-settings/constants.ts
similarity index 100%
rename from .storybook/theme-picker/constants.ts
rename to .storybook/theme-settings/constants.ts
diff --git a/.storybook/theme-picker/register.ts b/.storybook/theme-settings/register.ts
similarity index 70%
rename from .storybook/theme-picker/register.ts
rename to .storybook/theme-settings/register.ts
index 6c5d1834..60154c71 100644
--- a/.storybook/theme-picker/register.ts
+++ b/.storybook/theme-settings/register.ts
@@ -1,17 +1,17 @@
import addons, { makeDecorator, types } from '@storybook/addons';
import { THEMES_ID } from './constants';
-import { ThemeList } from './ThemeList';
+import { ThemeSettings } from './ThemeSettings';
addons.register(THEMES_ID, () => {
addons.addPanel(`${THEMES_ID}/panel`, {
- title: 'Themes',
+ title: 'Theme Settings',
type: types.PANEL,
- render: ThemeList
+ render: ThemeSettings
});
});
export default makeDecorator({
- name: 'withThemesProvider',
+ name: 'withThemeSettingsProvider',
parameterName: 'theme',
wrapper: (getStory, context) => getStory(context)
});
diff --git a/src/Avatar/Avatar.tsx b/src/Avatar/Avatar.tsx
index 89990fd4..c88ab53f 100644
--- a/src/Avatar/Avatar.tsx
+++ b/src/Avatar/Avatar.tsx
@@ -1,5 +1,6 @@
import React, { forwardRef } from 'react';
-import styled from 'styled-components';
+import styled, { css } from 'styled-components';
+import { styledDimension } from '../common';
import { getSize } from '../common/utils';
import { CommonStyledProps } from '../types';
@@ -28,13 +29,13 @@ const StyledAvatar = styled.div<
overflow: hidden;
${({ noBorder, theme }) =>
!noBorder &&
- `
- border-top: 2px solid ${theme.borderDark};
- border-left: 2px solid ${theme.borderDark};
- border-bottom: 2px solid ${theme.borderLightest};
- border-right: 2px solid ${theme.borderLightest};
- background: ${theme.material};
- `}
+ css`
+ border-top: ${styledDimension(1)} solid ${theme.borderDark};
+ border-left: ${styledDimension(1)} solid ${theme.borderDark};
+ border-bottom: ${styledDimension(1)} solid ${theme.borderLightest};
+ border-right: ${styledDimension(1)} solid ${theme.borderLightest};
+ background: ${theme.material};
+ `}
${({ src }) =>
!src &&
`
diff --git a/src/Button/Button.spec.tsx b/src/Button/Button.spec.tsx
index a980b3c1..963df13d 100644
--- a/src/Button/Button.spec.tsx
+++ b/src/Button/Button.spec.tsx
@@ -3,6 +3,7 @@ import React from 'react';
import { renderWithTheme, theme } from '../../test/utils';
import { blockSizes } from '../common/system';
+import { SCALE } from '../common/constants';
import { Button } from './Button';
@@ -10,6 +11,12 @@ const defaultProps = {
children: 'click me'
};
+const expectedBlockSizes = {
+ sm: `${blockSizes.sm * SCALE}px`,
+ md: `${blockSizes.md * SCALE}px`,
+ lg: `${blockSizes.lg * SCALE}px`
+};
+
describe('', () => {
it('should render button', () => {
const { getByRole } = render();
@@ -80,11 +87,11 @@ describe('', () => {
);
const button = getByRole('button');
- expect(button).toHaveStyleRule('height', blockSizes.sm);
+ expect(button).toHaveStyleRule('height', expectedBlockSizes.sm);
rerender();
- expect(button).toHaveStyleRule('height', blockSizes.lg);
+ expect(button).toHaveStyleRule('height', expectedBlockSizes.lg);
});
it('should handle square prop', () => {
@@ -92,7 +99,7 @@ describe('', () => {
const button = getByRole('button');
expect(button).toHaveStyleRule('padding', '0');
- expect(button).toHaveStyleRule('width', blockSizes.md);
+ expect(button).toHaveStyleRule('width', expectedBlockSizes.md);
});
it('should render children', () => {
diff --git a/src/Button/Button.tsx b/src/Button/Button.tsx
index 6cbf6aa0..d84cd564 100644
--- a/src/Button/Button.tsx
+++ b/src/Button/Button.tsx
@@ -6,9 +6,10 @@ import {
createDisabledTextStyles,
createFlatBoxStyles,
createHatchedBackground,
- focusOutline
+ focusOutline,
+ styledDimension
} from '../common';
-import { blockSizes } from '../common/system';
+import { styledBlockSize } from '../common/system';
import { noOp } from '../common/utils';
import { CommonStyledProps, Sizes } from '../types';
@@ -54,16 +55,17 @@ const commonButtonStyles = css`
display: inline-flex;
align-items: center;
justify-content: center;
- height: ${({ size = 'md' }) => blockSizes[size]};
+ height: ${({ size = 'md' }) => styledBlockSize(size)};
width: ${({ fullWidth, size = 'md', square }) =>
- fullWidth ? '100%' : square ? blockSizes[size] : 'auto'};
- padding: ${({ square }) => (square ? 0 : `0 10px`)};
+ fullWidth ? '100%' : square ? styledBlockSize(size) : 'auto'};
+ padding: ${({ square }) => (square ? 0 : css`0 ${styledDimension(5)}`)};
font-size: 1rem;
user-select: none;
&:active {
- padding-top: ${({ disabled }) => !disabled && '2px'};
+ padding-top: ${({ disabled }) => !disabled && styledDimension(1)};
}
- padding-top: ${({ active, disabled }) => active && !disabled && '2px'};
+ padding-top: ${({ active, disabled }) =>
+ active && !disabled && styledDimension(1)};
&:after {
content: '';
position: absolute;
@@ -85,25 +87,25 @@ export const StyledButton = styled.button`
? css`
${createFlatBoxStyles()}
${primary
- ? `
- border: 2px solid ${theme.checkmark};
- outline: 2px solid ${theme.flatDark};
- outline-offset: -4px;
- `
- : `
- border: 2px solid ${theme.flatDark};
- outline: 2px solid transparent;
- outline-offset: -4px;
- `}
+ ? css`
+ border: ${styledDimension(1)} solid ${theme.checkmark};
+ outline: ${styledDimension(1)} solid ${theme.flatDark};
+ outline-offset: -${styledDimension(2)};
+ `
+ : css`
+ border: ${styledDimension(1)} solid ${theme.flatDark};
+ outline: ${styledDimension(1)} solid transparent;
+ outline-offset: -${styledDimension(2)};
+ `}
&:focus:after, &:active:after {
${!active && !disabled && focusOutline}
- outline-offset: -4px;
+ outline-offset: -${styledDimension(2)};
}
`
: variant === 'menu' || variant === 'thin'
? css`
${createBoxStyles()};
- border: 2px solid transparent;
+ border: ${styledDimension(1)} solid transparent;
&:hover,
&:focus {
${!disabled &&
@@ -132,13 +134,13 @@ export const StyledButton = styled.button`
position: absolute;
${primary
? css`
- left: 2px;
- top: 2px;
- width: calc(100% - 4px);
- height: calc(100% - 4px);
- outline: 2px solid ${theme.borderDarkest};
+ left: ${styledDimension(1)};
+ top: ${styledDimension(1)};
+ width: calc(100% - ${styledDimension(2)});
+ height: calc(100% - ${styledDimension(2)});
+ outline: ${styledDimension(1)} solid ${theme.borderDarkest};
`
- : css`
+ : `
left: 0;
top: 0;
width: 100%;
@@ -155,11 +157,11 @@ export const StyledButton = styled.button`
&:focus:after,
&:active:after {
${!active && !disabled && focusOutline}
- outline-offset: -8px;
+ outline-offset: ${styledDimension(-4)};
}
&:active:focus:after,
&:active:after {
- top: ${active ? '0' : '1px'};
+ top: ${active ? '0' : styledDimension(0.5)};
}
`}
${commonButtonStyles}
diff --git a/src/Checkbox/Checkbox.tsx b/src/Checkbox/Checkbox.tsx
index 1b245ebd..8ea06c87 100644
--- a/src/Checkbox/Checkbox.tsx
+++ b/src/Checkbox/Checkbox.tsx
@@ -1,7 +1,7 @@
import React, { forwardRef, useCallback } from 'react';
import styled, { css } from 'styled-components';
-import { createHatchedBackground } from '../common';
+import { createHatchedBackground, styledDimension } from '../common';
import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled';
import {
LabelText,
@@ -45,8 +45,8 @@ type CheckmarkProps = {
};
const sharedCheckboxStyles = css`
- width: ${size}px;
- height: ${size}px;
+ width: ${styledDimension(size)};
+ height: ${styledDimension(size)};
display: flex;
align-items: center;
justify-content: space-around;
@@ -54,8 +54,8 @@ const sharedCheckboxStyles = css`
`;
const StyledCheckbox = styled(StyledScrollView)`
${sharedCheckboxStyles}
- width: ${size}px;
- height: ${size}px;
+ width: ${styledDimension(size)};
+ height: ${styledDimension(size)};
background: ${({ $disabled, theme }) =>
$disabled ? theme.material : theme.canvas};
&:before {
@@ -69,10 +69,10 @@ const StyledFlatCheckbox = styled.div`
background: ${({ $disabled, theme }) =>
$disabled ? theme.flatLight : theme.canvas};
${sharedCheckboxStyles}
- width: ${size - 4}px;
- height: ${size - 4}px;
+ width: ${styledDimension(size, { delta: -4 })};
+ height: ${styledDimension(size, { delta: -4 })};
outline: none;
- border: 2px solid ${({ theme }) => theme.flatDark};
+ border: ${styledDimension(1)} solid ${({ theme }) => theme.flatDark};
background: ${({ $disabled, theme }) =>
$disabled ? theme.flatLight : theme.canvas};
`;
@@ -84,8 +84,8 @@ const StyledMenuCheckbox = styled.div`
background: ${({ $disabled, theme }) =>
$disabled ? theme.flatLight : theme.canvas};
${sharedCheckboxStyles}
- width: ${size - 4}px;
- height: ${size - 4}px;
+ width: ${styledDimension(size, { delta: -4 })};
+ height: ${styledDimension(size, { delta: -4 })};
background: none;
border: none;
outline: none;
@@ -103,14 +103,14 @@ const CheckmarkIcon = styled.span.attrs(() => ({
display: block;
position: absolute;
left: 50%;
- top: calc(50% - 1px);
- width: 3px;
- height: 7px;
+ top: calc(50% - ${styledDimension(0.5)});
+ width: ${styledDimension(1.5)};
+ height: ${styledDimension(3.5)};
border: solid
${({ $disabled, theme }) =>
$disabled ? theme.checkmarkDisabled : theme.checkmark};
- border-width: 0 3px 3px 0;
+ border-width: 0 ${styledDimension(1.5)} ${styledDimension(1.5)} 0;
transform: translate(-50%, -50%) rotate(45deg);
${({ $disabled, theme, variant }) =>
@@ -120,7 +120,7 @@ const CheckmarkIcon = styled.span.attrs(() => ({
? theme.materialTextDisabled
: theme.materialText};
filter: drop-shadow(
- 1px 1px 0px
+ ${styledDimension(0.5)} ${styledDimension(0.5)} 0px
${$disabled ? theme.materialTextDisabledShadow : 'transparent'}
);
`
@@ -147,8 +147,8 @@ const IndeterminateIcon = styled.span.attrs(() => ({
${({ variant }) =>
variant === 'menu'
? css`
- height: calc(100% - 4px);
- width: calc(100% - 4px);
+ height: calc(100% - ${styledDimension(2)});
+ width: calc(100% - ${styledDimension(2)});
`
: css`
width: 100%;
@@ -165,7 +165,7 @@ const IndeterminateIcon = styled.span.attrs(() => ({
createHatchedBackground({
mainColor: $disabled ? theme.checkmarkDisabled : theme.checkmark
})}
- background-position: 0px 0px, 2px 2px;
+ background-position: 0px 0px, ${styledDimension(1)} ${styledDimension(1)};
${({ $disabled, theme, variant }) =>
variant === 'menu' &&
@@ -176,7 +176,7 @@ const IndeterminateIcon = styled.span.attrs(() => ({
})}
}
filter: drop-shadow(
- 1px 1px 0px
+ ${styledDimension(0.5)} ${styledDimension(0.5)} 0px
${$disabled ? theme.materialTextDisabledShadow : 'transparent'}
);
`};
diff --git a/src/ColorInput/ColorInput.tsx b/src/ColorInput/ColorInput.tsx
index 70adaeeb..46b9e5d3 100644
--- a/src/ColorInput/ColorInput.tsx
+++ b/src/ColorInput/ColorInput.tsx
@@ -1,7 +1,7 @@
import React, { forwardRef } from 'react';
import styled, { css } from 'styled-components';
import { StyledButton } from '../Button/Button';
-import { focusOutline } from '../common';
+import { focusOutline, styledDimension } from '../common';
import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled';
import { noOp } from '../common/utils';
import { Separator } from '../Separator/Separator';
@@ -20,11 +20,11 @@ type ColorInputProps = {
CommonStyledProps;
const Trigger = styled(StyledButton)`
- padding-left: 8px;
+ padding-left: ${styledDimension(4)};
`;
const StyledSeparator = styled(Separator)`
- height: 21px;
+ height: ${styledDimension(10.5)};
position: relative;
top: 0;
`;
@@ -50,23 +50,26 @@ const ColorPreview = styled.div<{
$disabled: boolean;
}>`
box-sizing: border-box;
- height: 19px;
+ height: ${styledDimension(9.5)};
display: inline-block;
- width: 35px;
- margin-right: 5px;
+ width: ${styledDimension(17.5)};
+ margin-right: ${styledDimension(2.5)};
background: ${({ color }) => color};
${({ $disabled }) =>
$disabled
? css`
- border: 2px solid ${({ theme }) => theme.materialTextDisabled};
+ border: ${styledDimension(1)} solid
+ ${({ theme }) => theme.materialTextDisabled};
filter: drop-shadow(
- 1px 1px 0px ${({ theme }) => theme.materialTextDisabledShadow}
+ ${styledDimension(0.5)} ${styledDimension(0.5)} 0px
+ ${({ theme }) => theme.materialTextDisabledShadow}
);
`
: css`
- border: 2px solid ${({ theme }) => theme.materialText};
+ border: ${styledDimension(1)} solid
+ ${({ theme }) => theme.materialText};
`}
${StyledColorInput}:focus:not(:active) + &:after {
content: '';
@@ -76,7 +79,7 @@ const ColorPreview = styled.div<{
width: 100%;
height: 100%;
${focusOutline}
- outline-offset: -8px;
+ outline-offset: -${styledDimension(4)};
}
`;
@@ -87,30 +90,34 @@ const ChevronIcon = styled.span<
>`
width: 0px;
height: 0px;
- border-left: 6px solid transparent;
- border-right: 6px solid transparent;
+ border-left: ${styledDimension(3)} solid transparent;
+ border-right: ${styledDimension(3)} solid transparent;
display: inline-block;
- margin-left: 6px;
+ margin-left: ${styledDimension(3)};
${({ $disabled }) =>
$disabled
? css`
- border-top: 6px solid ${({ theme }) => theme.materialTextDisabled};
+ border-top: ${styledDimension(3)} solid
+ ${({ theme }) => theme.materialTextDisabled};
filter: drop-shadow(
- 1px 1px 0px ${({ theme }) => theme.materialTextDisabledShadow}
+ ${styledDimension(0.5)} ${styledDimension(0.5)} 0px
+ ${({ theme }) => theme.materialTextDisabledShadow}
);
`
: css`
- border-top: 6px solid ${({ theme }) => theme.materialText};
+ border-top: ${styledDimension(3)} solid
+ ${({ theme }) => theme.materialText};
`}
&:after {
content: '';
box-sizing: border-box;
position: absolute;
- top: ${({ variant }) => (variant === 'flat' ? '6px' : '8px')};
- right: 8px;
- width: 16px;
- height: 19px;
+ top: ${({ variant }) =>
+ variant === 'flat' ? styledDimension(3) : styledDimension(4)};
+ right: ${styledDimension(4)};
+ width: ${styledDimension(8)};
+ height: ${styledDimension(9.5)};
}
`;
diff --git a/src/DatePicker/DatePicker.tsx b/src/DatePicker/DatePicker.tsx
index a8aaaf10..e81cd701 100644
--- a/src/DatePicker/DatePicker.tsx
+++ b/src/DatePicker/DatePicker.tsx
@@ -1,7 +1,8 @@
import React, { forwardRef, useCallback, useMemo, useState } from 'react';
-import styled from 'styled-components';
+import styled, { useTheme } from 'styled-components';
import { Button } from '../Button/Button';
+import { styledDimension } from '../common';
import { NumberInput } from '../NumberInput/NumberInput';
import { ScrollView } from '../ScrollView/ScrollView';
import { Select } from '../Select/Select';
@@ -14,11 +15,12 @@ type DatePickerProps = {
date?: string;
onAccept?: (chosenDate: string) => void;
onCancel?: React.MouseEventHandler;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
};
const Calendar = styled(ScrollView)`
- width: 234px;
+ width: ${styledDimension(117)};
margin: 1rem 0;
background: ${({ theme }) => theme.canvas};
`;
@@ -50,7 +52,7 @@ const DateItemContent = styled.span<{ active: boolean }>`
active ? theme.canvasTextInvert : theme.canvasText};
&:hover {
- border: 2px dashed
+ border: ${styledDimension(1)} dashed
${({ theme, active }) => (active ? 'none' : theme.materialDark)};
}
`;
@@ -94,10 +96,11 @@ const DatePicker = forwardRef(
date: initialDate = new Date().toISOString(),
onAccept,
onCancel,
- shadow = true
+ shadow
},
ref
) => {
+ const theme = useTheme();
const [date, setDate] = useState(() => convertDateToState(initialDate));
const { year, month, day } = date;
@@ -170,10 +173,14 @@ const DatePicker = forwardRef(
options={months}
value={month}
onChange={handleMonthSelect}
- width={128}
- menuMaxHeight={200}
+ width={styledDimension(64)({ theme })}
+ menuMaxHeight={styledDimension(100)({ theme })}
+ />
+
-
diff --git a/src/Frame/Frame.tsx b/src/Frame/Frame.tsx
index 8094ee14..4f1f6438 100644
--- a/src/Frame/Frame.tsx
+++ b/src/Frame/Frame.tsx
@@ -5,6 +5,7 @@ import { CommonStyledProps } from '../types';
type FrameProps = {
children?: React.ReactNode;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
} & (
| {
diff --git a/src/GroupBox/GroupBox.tsx b/src/GroupBox/GroupBox.tsx
index a2d381c5..3e41414e 100644
--- a/src/GroupBox/GroupBox.tsx
+++ b/src/GroupBox/GroupBox.tsx
@@ -1,6 +1,6 @@
import React, { forwardRef } from 'react';
import styled, { css } from 'styled-components';
-import { createDisabledTextStyles } from '../common';
+import { createDisabledTextStyles, styledDimension } from '../common';
import { CommonStyledProps } from '../types';
type GroupBoxProps = {
@@ -15,18 +15,20 @@ const StyledFieldset = styled.fieldset<
Pick & { $disabled: boolean }
>`
position: relative;
- border: 2px solid
+ border: ${styledDimension(1)} solid
${({ theme, variant }) =>
variant === 'flat' ? theme.flatDark : theme.borderLightest};
- padding: 16px;
- margin-top: 8px;
+ padding: ${styledDimension(8)};
+ margin-top: ${styledDimension(4)};
font-size: 1rem;
color: ${({ theme }) => theme.materialText};
${({ variant }) =>
variant !== 'flat' &&
css`
- box-shadow: -1px -1px 0 1px ${({ theme }) => theme.borderDark},
- inset -1px -1px 0 1px ${({ theme }) => theme.borderDark};
+ box-shadow: -${styledDimension(0.5)} -${styledDimension(0.5)} 0
+ ${styledDimension(0.5)} ${({ theme }) => theme.borderDark},
+ inset -${styledDimension(0.5)} -${styledDimension(0.5)} 0
+ ${styledDimension(0.5)} ${({ theme }) => theme.borderDark};
`}
${props => props.$disabled && createDisabledTextStyles()}
`;
@@ -35,9 +37,9 @@ const StyledLegend = styled.legend>`
display: flex;
position: absolute;
top: 0;
- left: 8px;
- transform: translateY(calc(-50% - 2px));
- padding: 0 8px;
+ left: ${styledDimension(4)};
+ transform: translateY(calc(-50% - ${styledDimension(1)}));
+ padding: 0 ${styledDimension(4)};
font-size: 1rem;
background: ${({ theme, variant }) =>
diff --git a/src/Handle/Handle.tsx b/src/Handle/Handle.tsx
index fc8fd851..313f2f84 100644
--- a/src/Handle/Handle.tsx
+++ b/src/Handle/Handle.tsx
@@ -1,7 +1,8 @@
import React from 'react';
-import styled from 'styled-components';
-import { CommonStyledProps } from '../types';
+import styled, { css } from 'styled-components';
+import { styledDimension } from '../common';
import { getSize } from '../common/utils';
+import { CommonStyledProps } from '../types';
type HandleProps = {
size?: string | number;
@@ -11,17 +12,17 @@ type HandleProps = {
// TODO: add horizontal variant
// TODO: allow user to specify number of bars (like 3 horizontal bars for drag handle)
const Handle = styled.div`
- ${({ theme, size = '100%' }) => `
- display: inline-block;
- box-sizing: border-box;
- height: ${getSize(size)};
- width: 5px;
- border-top: 2px solid ${theme.borderLightest};
- border-left: 2px solid ${theme.borderLightest};
- border-bottom: 2px solid ${theme.borderDark};
- border-right: 2px solid ${theme.borderDark};
- background: ${theme.material};
-`}
+ ${({ theme, size = '100%' }) => css`
+ display: inline-block;
+ box-sizing: border-box;
+ height: ${getSize(size)};
+ width: ${styledDimension(2.5)};
+ border-top: ${styledDimension(1)} solid ${theme.borderLightest};
+ border-left: ${styledDimension(1)} solid ${theme.borderLightest};
+ border-bottom: ${styledDimension(1)} solid ${theme.borderDark};
+ border-right: ${styledDimension(1)} solid ${theme.borderDark};
+ background: ${theme.material};
+ `}
`;
Handle.displayName = 'Handle';
diff --git a/src/MenuList/MenuList.tsx b/src/MenuList/MenuList.tsx
index 57b57848..bea42b16 100644
--- a/src/MenuList/MenuList.tsx
+++ b/src/MenuList/MenuList.tsx
@@ -1,22 +1,28 @@
import React from 'react';
import styled from 'styled-components';
-import { createBorderStyles, createBoxStyles } from '../common';
+import {
+ createBorderStyles,
+ createBoxStyles,
+ styledDimension
+} from '../common';
import { CommonStyledProps } from '../types';
type MenuListProps = React.HTMLAttributes & {
fullWidth?: boolean;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
inline?: boolean;
} & CommonStyledProps;
// TODO keyboard controls
const MenuList = styled.ul.attrs(() => ({
- role: 'menu'
+ role: 'menu',
+ shadow: true
}))`
box-sizing: border-box;
width: ${props => (props.fullWidth ? '100%' : 'auto')};
- padding: 4px;
+ padding: ${styledDimension(2)};
${createBorderStyles({ style: 'window' })}
${createBoxStyles()}
${props =>
diff --git a/src/MenuList/MenuListItem.spec.tsx b/src/MenuList/MenuListItem.spec.tsx
index 734d31d2..a6c2a263 100644
--- a/src/MenuList/MenuListItem.spec.tsx
+++ b/src/MenuList/MenuListItem.spec.tsx
@@ -1,9 +1,16 @@
import React from 'react';
import { renderWithTheme, theme } from '../../test/utils';
+import { SCALE } from '../common/constants';
import { blockSizes } from '../common/system';
import { MenuListItem } from './MenuListItem';
+const expectedBlockSizes = {
+ sm: `${blockSizes.sm * SCALE}px`,
+ md: `${blockSizes.md * SCALE}px`,
+ lg: `${blockSizes.lg * SCALE}px`
+};
+
const defaultSize = 'lg';
describe('', () => {
it('renders MenuListItem', () => {
@@ -76,8 +83,14 @@ describe('', () => {
const { getByRole } = renderWithTheme();
const menuListItem = getByRole('menuitem');
- expect(menuListItem).toHaveStyleRule('width', blockSizes[defaultSize]);
- expect(menuListItem).toHaveStyleRule('height', blockSizes[defaultSize]);
+ expect(menuListItem).toHaveStyleRule(
+ 'width',
+ expectedBlockSizes[defaultSize]
+ );
+ expect(menuListItem).toHaveStyleRule(
+ 'height',
+ expectedBlockSizes[defaultSize]
+ );
});
});
describe('prop: size', () => {
@@ -86,7 +99,7 @@ describe('', () => {
const { getByRole } = renderWithTheme();
const menuListItem = getByRole('menuitem');
- expect(menuListItem).toHaveStyleRule('height', blockSizes[size]);
+ expect(menuListItem).toHaveStyleRule('height', expectedBlockSizes[size]);
});
});
});
diff --git a/src/MenuList/MenuListItem.tsx b/src/MenuList/MenuListItem.tsx
index 45c7e1f2..4e94a420 100644
--- a/src/MenuList/MenuListItem.tsx
+++ b/src/MenuList/MenuListItem.tsx
@@ -1,8 +1,8 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
-import { createDisabledTextStyles } from '../common';
-import { blockSizes } from '../common/system';
+import { createDisabledTextStyles, styledDimension } from '../common';
+import { styledBlockSize } from '../common/system';
import { CommonStyledProps, Sizes } from '../types';
type MenuListItemProps = {
@@ -24,15 +24,15 @@ export const StyledMenuListItem = styled.li<{
display: flex;
align-items: center;
position: relative;
- height: ${props => blockSizes[props.size]};
- width: ${props => (props.square ? blockSizes[props.size] : 'auto')};
- padding: 0 8px;
+ height: ${props => styledBlockSize(props.size)};
+ width: ${props => (props.square ? styledBlockSize(props.size) : 'auto')};
+ padding: 0 ${styledDimension(4)};
font-size: 1rem;
white-space: nowrap;
justify-content: ${props =>
props.square ? 'space-around' : 'space-between'};
text-align: center;
- line-height: ${props => blockSizes[props.size]};
+ line-height: ${props => styledBlockSize(props.size)};
color: ${({ theme }) => theme.materialText};
pointer-events: ${({ $disabled }) => ($disabled ? 'none' : 'auto')};
font-weight: ${({ primary }) => (primary ? 'bold' : 'normal')};
diff --git a/src/Monitor/Monitor.tsx b/src/Monitor/Monitor.tsx
index 8abfa45e..817e89fa 100644
--- a/src/Monitor/Monitor.tsx
+++ b/src/Monitor/Monitor.tsx
@@ -1,5 +1,6 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
+import { styledDimension } from '../common';
import { StyledScrollView } from '../ScrollView/ScrollView';
@@ -11,7 +12,7 @@ type MonitorProps = {
const Wrapper = styled.div`
position: relative;
display: inline-block;
- padding-bottom: 26px;
+ padding-bottom: ${styledDimension(13)};
`;
const Inner = styled.div`
@@ -22,17 +23,18 @@ const MonitorBody = styled.div`
position: relative;
z-index: 1;
box-sizing: border-box;
- width: 195px;
- height: 155px;
- padding: 12px;
+ width: ${styledDimension(97.5)};
+ height: ${styledDimension(77.5)};
+ padding: ${styledDimension(6)};
background: ${({ theme }) => theme.material};
- border-top: 4px solid ${({ theme }) => theme.borderLightest};
- border-left: 4px solid ${({ theme }) => theme.borderLightest};
- border-bottom: 4px solid ${({ theme }) => theme.borderDark};
- border-right: 4px solid ${({ theme }) => theme.borderDark};
+ border-top: ${styledDimension(2)} solid ${({ theme }) => theme.borderLightest};
+ border-left: ${styledDimension(2)} solid
+ ${({ theme }) => theme.borderLightest};
+ border-bottom: ${styledDimension(2)} solid ${({ theme }) => theme.borderDark};
+ border-right: ${styledDimension(2)} solid ${({ theme }) => theme.borderDark};
- outline: 1px dotted ${({ theme }) => theme.material};
- outline-offset: -3px;
+ outline: ${styledDimension(0.5)} dotted ${({ theme }) => theme.material};
+ outline-offset: ${styledDimension(-1.5)};
&:before {
content: '';
position: absolute;
@@ -40,19 +42,20 @@ const MonitorBody = styled.div`
top: 0;
width: 100%;
height: 100%;
- outline: 1px dotted ${({ theme }) => theme.material};
+ outline: ${styledDimension(0.5)} dotted ${({ theme }) => theme.material};
}
- box-shadow: 1px 1px 0 1px ${({ theme }) => theme.borderDarkest};
+ box-shadow: ${styledDimension(0.5)} ${styledDimension(0.5)} 0
+ ${styledDimension(0.5)} ${({ theme }) => theme.borderDarkest};
&:after {
content: '';
display: inline-block;
position: absolute;
- bottom: 4px;
- right: 12px;
- width: 10px;
- border-top: 2px solid #4d9046;
- border-bottom: 2px solid #07ff00;
+ bottom: ${styledDimension(2)};
+ right: ${styledDimension(6)};
+ width: ${styledDimension(5)};
+ border-top: ${styledDimension(1)} solid #4d9046;
+ border-bottom: ${styledDimension(1)} solid #07ff00;
}
`;
@@ -66,43 +69,52 @@ const Background = styled(StyledScrollView).attrs(() => ({
const Stand = styled.div`
box-sizing: border-box;
position: absolute;
- top: calc(100% + 2px);
+ top: calc(100% + ${styledDimension(1)});
left: 50%;
transform: translateX(-50%);
- height: 10px;
+ height: ${styledDimension(5)};
width: 50%;
background: ${({ theme }) => theme.material};
- border-left: 2px solid ${({ theme }) => theme.borderLightest};
- border-bottom: 2px solid ${({ theme }) => theme.borderDarkest};
- border-right: 2px solid ${({ theme }) => theme.borderDarkest};
- box-shadow: inset 0px 0px 0px 2px ${({ theme }) => theme.borderDark};
+ border-left: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderLightest};
+ border-bottom: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderDarkest};
+ border-right: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderDarkest};
+ box-shadow: inset 0px 0px 0px ${styledDimension(1)}
+ ${({ theme }) => theme.borderDark};
&:before {
content: '';
position: absolute;
- top: calc(100% + 2px);
+ top: calc(100% + ${styledDimension(1)});
left: 50%;
transform: translateX(-50%);
width: 80%;
- height: 8px;
+ height: ${styledDimension(4)};
background: ${({ theme }) => theme.material};
- border-left: 2px solid ${({ theme }) => theme.borderLightest};
- border-right: 2px solid ${({ theme }) => theme.borderDarkest};
- box-shadow: inset 0px 0px 0px 2px ${({ theme }) => theme.borderDark};
+ border-left: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderLightest};
+ border-right: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderDarkest};
+ box-shadow: inset 0px 0px 0px ${styledDimension(1)}
+ ${({ theme }) => theme.borderDark};
}
&:after {
content: '';
position: absolute;
- top: calc(100% + 8px);
+ top: calc(100% + ${styledDimension(4)});
left: 50%;
transform: translateX(-50%);
width: 150%;
- height: 4px;
+ height: ${styledDimension(2)};
background: ${({ theme }) => theme.material};
- border: 2px solid ${({ theme }) => theme.borderDark};
+ border: ${styledDimension(1)} solid ${({ theme }) => theme.borderDark};
border-bottom: none;
- box-shadow: inset 1px 1px 0px 1px ${({ theme }) => theme.borderLightest},
- 1px 1px 0 1px ${({ theme }) => theme.borderDarkest};
+ box-shadow: inset ${styledDimension(0.5)} ${styledDimension(0.5)} 0px
+ ${styledDimension(0.5)} ${({ theme }) => theme.borderLightest},
+ ${styledDimension(0.5)} ${styledDimension(0.5)} 0 ${styledDimension(0.5)}
+ ${({ theme }) => theme.borderDarkest};
}
`;
diff --git a/src/ProgressBar/ProgressBar.tsx b/src/ProgressBar/ProgressBar.tsx
index 349f8079..ba9334f1 100644
--- a/src/ProgressBar/ProgressBar.tsx
+++ b/src/ProgressBar/ProgressBar.tsx
@@ -6,6 +6,7 @@ import React, {
useState
} from 'react';
import styled, { css } from 'styled-components';
+import { styledDimension } from '../common';
import { blockSizes } from '../common/system';
import { StyledScrollView } from '../ScrollView/ScrollView';
@@ -13,6 +14,7 @@ import { CommonStyledProps } from '../types';
type ProgressBarProps = {
hideValue?: boolean;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
value?: number;
variant?: 'default' | 'tile';
@@ -39,8 +41,8 @@ const ProgressCutout = styled(StyledScrollView)<
}
`;
const commonBarStyles = css`
- width: calc(100% - 4px);
- height: calc(100% - 4px);
+ width: calc(100% - ${styledDimension(2)});
+ height: calc(100% - ${styledDimension(2)});
display: flex;
align-items: center;
@@ -48,19 +50,19 @@ const commonBarStyles = css`
`;
const WhiteBar = styled.div`
position: relative;
- top: 4px;
+ top: ${styledDimension(2)};
${commonBarStyles}
background: ${({ theme }) => theme.canvas};
color: #000;
- margin-left: 2px;
- margin-top: -2px;
+ margin-left: ${styledDimension(1)};
+ margin-top: ${styledDimension(-1)};
color: ${({ theme }) => theme.materialText};
`;
const BlueBar = styled.div>`
position: absolute;
- top: 2px;
- left: 2px;
+ top: ${styledDimension(1)};
+ left: ${styledDimension(1)};
${commonBarStyles}
color: ${({ theme }) => theme.materialTextInvert};
background: ${({ theme }) => theme.progress};
@@ -74,35 +76,29 @@ const BlueBar = styled.div>`
`;
const TilesWrapper = styled.div`
- width: calc(100% - 6px);
- height: calc(100% - 8px);
+ width: calc(100% - ${styledDimension(3)});
+ height: calc(100% - ${styledDimension(4)});
position: absolute;
- left: 3px;
- top: 4px;
+ left: ${styledDimension(1.5)};
+ top: ${styledDimension(2)};
box-sizing: border-box;
display: inline-flex;
`;
-const tileWidth = 17;
+const tileWidth = 8.5;
const Tile = styled.span`
display: inline-block;
- width: ${tileWidth}px;
+ width: ${styledDimension(tileWidth)};
box-sizing: border-box;
height: 100%;
background: ${({ theme }) => theme.progress};
border-color: ${({ theme }) => theme.material};
- border-width: 0px 1px;
+ border-width: 0px ${styledDimension(0.5)};
border-style: solid;
`;
const ProgressBar = forwardRef(
(
- {
- hideValue = false,
- shadow = true,
- value,
- variant = 'default',
- ...otherProps
- },
+ { hideValue = false, shadow, value, variant = 'default', ...otherProps },
ref
) => {
const displayValue = hideValue ? null : `${value}%`;
@@ -138,7 +134,7 @@ const ProgressBar = forwardRef(
variant={variant}
{...otherProps}
>
-
+
{variant === 'default' ? (
<>
{displayValue}
diff --git a/src/Radio/Radio.tsx b/src/Radio/Radio.tsx
index f49b51ca..a146f87e 100644
--- a/src/Radio/Radio.tsx
+++ b/src/Radio/Radio.tsx
@@ -1,7 +1,7 @@
import React, { forwardRef } from 'react';
import styled, { css, CSSProperties } from 'styled-components';
-import { createFlatBoxStyles } from '../common';
+import { createFlatBoxStyles, styledDimension } from '../common';
import {
LabelText,
size,
@@ -31,8 +31,8 @@ type RadioProps = {
CommonStyledProps;
const sharedCheckboxStyles = css`
- width: ${size}px;
- height: ${size}px;
+ width: ${styledDimension(size)};
+ height: ${styledDimension(size)};
border-radius: 50%;
display: flex;
align-items: center;
@@ -54,8 +54,8 @@ const StyledCheckbox = styled(StyledScrollView)`
position: absolute;
left: 0px;
top: 0px;
- width: calc(100% - 4px);
- height: calc(100% - 4px);
+ width: calc(100% - ${styledDimension(2)});
+ height: calc(100% - ${styledDimension(2)});
border-radius: 50%;
box-shadow: none;
}
@@ -72,9 +72,9 @@ const StyledFlatCheckbox = styled.div`
position: absolute;
top: 0;
left: 0;
- width: calc(100% - 4px);
- height: calc(100% - 4px);
- border: 2px solid ${({ theme }) => theme.flatDark};
+ width: calc(100% - ${styledDimension(2)});
+ height: calc(100% - ${styledDimension(2)});
+ border: ${styledDimension(1)} solid ${({ theme }) => theme.flatDark};
border-radius: 50%;
}
`;
@@ -102,8 +102,8 @@ const Icon = styled.span.attrs(() => ({
display: inline-block;
top: 50%;
left: 50%;
- width: 6px;
- height: 6px;
+ width: ${styledDimension(3)};
+ height: ${styledDimension(3)};
transform: translate(-50%, -50%);
border-radius: 50%;
${({ $disabled, theme, variant }) =>
@@ -113,7 +113,7 @@ const Icon = styled.span.attrs(() => ({
? theme.materialTextDisabled
: theme.materialText};
filter: drop-shadow(
- 1px 1px 0px
+ ${styledDimension(0.5)} ${styledDimension(0.5)} 0px
${$disabled ? theme.materialTextDisabledShadow : 'transparent'}
);
`
diff --git a/src/ScrollView/ScrollView.tsx b/src/ScrollView/ScrollView.tsx
index 632ae1e3..e348a94d 100644
--- a/src/ScrollView/ScrollView.tsx
+++ b/src/ScrollView/ScrollView.tsx
@@ -1,10 +1,16 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
-import { insetShadow, createScrollbars } from '../common';
+import {
+ createScrollbars,
+ createInnerBorderWithShadow,
+ styledDimension
+} from '../common';
+import { defaultTrue } from '../common/utils';
import { CommonStyledProps } from '../types';
type ScrollViewProps = {
children?: React.ReactNode;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
} & React.HTMLAttributes &
CommonStyledProps;
@@ -12,10 +18,10 @@ type ScrollViewProps = {
export const StyledScrollView = styled.div>`
position: relative;
box-sizing: border-box;
- padding: 2px;
+ padding: ${styledDimension(1)};
font-size: 1rem;
border-style: solid;
- border-width: 2px;
+ border-width: ${styledDimension(1)};
border-left-color: ${({ theme }) => theme.borderDark};
border-top-color: ${({ theme }) => theme.borderDark};
border-right-color: ${({ theme }) => theme.borderLightest};
@@ -26,18 +32,23 @@ export const StyledScrollView = styled.div>`
left: 0;
top: 0;
content: '';
- width: calc(100% - 4px);
- height: calc(100% - 4px);
+ width: calc(100% - ${styledDimension(2)});
+ height: calc(100% - ${styledDimension(2)});
border-style: solid;
- border-width: 2px;
+ border-width: ${styledDimension(1)};
border-left-color: ${({ theme }) => theme.borderDarkest};
border-top-color: ${({ theme }) => theme.borderDarkest};
border-right-color: ${({ theme }) => theme.borderLight};
border-bottom-color: ${({ theme }) => theme.borderLight};
pointer-events: none;
- ${props => props.shadow && `box-shadow:${insetShadow};`}
+ ${props =>
+ defaultTrue(props.shadow ?? props.theme.shadow) &&
+ `box-shadow: ${createInnerBorderWithShadow({
+ theme: props.theme,
+ hasInsetShadow: true
+ })};`}
}
`;
@@ -45,13 +56,13 @@ const Content = styled.div`
box-sizing: border-box;
width: 100%;
height: 100%;
- padding: 4px;
+ padding: ${styledDimension(2)};
overflow: auto;
${createScrollbars()}
`;
const ScrollView = forwardRef(
- ({ children, shadow = true, ...otherProps }, ref) => {
+ ({ children, shadow, ...otherProps }, ref) => {
return (
{children}
diff --git a/src/Select/Select.styles.tsx b/src/Select/Select.styles.tsx
index c3e679ea..446cae9e 100644
--- a/src/Select/Select.styles.tsx
+++ b/src/Select/Select.styles.tsx
@@ -5,9 +5,10 @@ import {
createDisabledTextStyles,
createFlatBoxStyles,
createScrollbars,
- shadow as commonShadow
+ shadow as commonShadow,
+ styledDimension
} from '../common';
-import { blockSizes } from '../common/system';
+import { blockSizes, styledBlockSize } from '../common/system';
import { StyledScrollView } from '../ScrollView/ScrollView';
import { CommonThemeProps } from '../types';
@@ -21,7 +22,7 @@ type CommonSelectStyleProps = {
const sharedInputContentStyles = css`
box-sizing: border-box;
- padding-left: 4px;
+ padding-left: ${styledDimension(2)};
overflow: hidden;
white-space: nowrap;
user-select: none;
@@ -45,20 +46,20 @@ export const StyledInner = styled.div`
export const StyledSelectContent = styled.div`
${sharedInputContentStyles}
- padding-right: 8px;
+ padding-right: ${styledDimension(4)};
align-items: center;
display: flex;
- height: calc(100% - 4px);
- width: calc(100% - 4px);
- margin: 0 2px;
- border: 2px solid transparent;
+ height: calc(100% - ${styledDimension(2)});
+ width: calc(100% - ${styledDimension(2)});
+ margin: 0 ${styledDimension(1)};
+ border: ${styledDimension(1)} solid transparent;
${StyledInner}:focus & {
${sharedHoverStyles}
- border: 2px dotted ${({ theme }) => theme.focusSecondary};
+ border: ${styledDimension(1)} dotted ${({ theme }) => theme.focusSecondary};
}
`;
const sharedWrapperStyles = css`
- height: ${blockSizes.md};
+ height: ${styledBlockSize('md')};
display: inline-block;
color: ${({ $disabled = false, theme }) =>
$disabled ? createDisabledTextStyles() : theme.canvasText};
@@ -97,7 +98,7 @@ export const StyledNativeSelect = styled.select`
background: none;
-webkit-tap-highlight-color: transparent;
border-radius: 0;
- padding-right: 30px;
+ padding-right: ${styledDimension(15)};
${sharedInputContentStyles}
cursor: pointer;
&:disabled {
@@ -108,7 +109,7 @@ export const StyledNativeSelect = styled.select`
`;
export const StyledDropdownButton = styled(Button)`
- width: 30px;
+ width: ${styledDimension(15)};
padding: 0;
flex-shrink: 0;
${({ variant = 'default' }) =>
@@ -122,9 +123,11 @@ export const StyledDropdownButton = styled(Button)`
&:before {
border-left-color: ${({ theme }) => theme.borderLight};
border-top-color: ${({ theme }) => theme.borderLight};
- box-shadow: inset 1px 1px 0px 1px
+ box-shadow: inset ${styledDimension(0.5)} ${styledDimension(0.5)}
+ 0px ${styledDimension(0.5)}
${({ theme }) => theme.borderLightest},
- inset -1px -1px 0 1px ${({ theme }) => theme.borderDark};
+ inset -${styledDimension(0.5)} -${styledDimension(0.5)} 0
+ ${styledDimension(0.5)} ${({ theme }) => theme.borderDark};
}
`}
${({ native = false, variant = 'default' }) =>
@@ -135,12 +138,12 @@ export const StyledDropdownButton = styled(Button)`
right: 0;
height: 100%;
`
- : `
- position: absolute;
- top: 2px;
- right: 2px;
- height: calc(100% - 4px);
- `)}
+ : css`
+ position: absolute;
+ top: ${styledDimension(1)};
+ right: ${styledDimension(1)};
+ height: calc(100% - ${styledDimension(2)});
+ `)}
pointer-events: ${({ $disabled = false, native = false }) =>
$disabled || native ? 'none' : 'auto'}
`;
@@ -152,20 +155,23 @@ export const StyledDropdownIcon = styled.span`
transform: translate(-50%, -50%);
width: 0;
height: 0;
- border-left: 6px solid transparent;
- border-right: 6px solid transparent;
+ border-left: ${styledDimension(3)} solid transparent;
+ border-right: ${styledDimension(3)} solid transparent;
display: inline-block;
- border-top: 6px solid
+ border-top: ${styledDimension(3)} solid
${({ $disabled = false, theme }) =>
$disabled ? theme.materialTextDisabled : theme.materialText};
${({ $disabled = false, theme }) =>
$disabled &&
- `
- filter: drop-shadow(1px 1px 0px ${theme.materialTextDisabledShadow});
- border-top-color: ${theme.materialTextDisabled};
+ css`
+ filter: drop-shadow(
+ ${styledDimension(0.5)} ${styledDimension(0.5)} 0px
+ ${theme.materialTextDisabledShadow}
+ );
+ border-top-color: ${theme.materialTextDisabled};
`}
${StyledDropdownButton}:active & {
- margin-top: 2px;
+ margin-top: ${styledDimension(1)};
}
`;
@@ -177,7 +183,7 @@ export const StyledDropdownMenu = styled.ul`
transform: translateY(100%);
left: 0;
background: ${({ theme }) => theme.canvas};
- padding: 2px;
+ padding: ${styledDimension(1)};
border-top: none;
cursor: default;
z-index: 1;
@@ -186,14 +192,15 @@ export const StyledDropdownMenu = styled.ul`
${({ variant = 'default' }) =>
variant === 'flat'
? css`
- bottom: 2px;
+ bottom: ${styledDimension(1)};
width: 100%;
- border: 2px solid ${({ theme }) => theme.flatDark};
+ border: ${styledDimension(1)} solid ${({ theme }) => theme.flatDark};
`
: css`
- bottom: -2px;
- width: calc(100% - 2px);
- border: 2px solid ${({ theme }) => theme.borderDarkest};
+ bottom: -${styledDimension(1)};
+ width: calc(100% - ${styledDimension(1)});
+ border: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderDarkest};
`}
${({ variant = 'default' }) => createScrollbars(variant)}
`;
@@ -202,10 +209,10 @@ export const StyledDropdownMenuItem = styled.li`
box-sizing: border-box;
width: 100%;
- padding-left: 8px;
+ padding-left: ${styledDimension(4)};
- height: calc(${blockSizes.md} - 4px);
- line-height: calc(${blockSizes.md} - 4px);
+ height: calc(${blockSizes.md} - ${styledDimension(2)});
+ line-height: calc(${blockSizes.md} - ${styledDimension(2)});
font-size: 1rem;
white-space: nowrap;
overflow: hidden;
diff --git a/src/Select/Select.tsx b/src/Select/Select.tsx
index e953246e..d3be2785 100644
--- a/src/Select/Select.tsx
+++ b/src/Select/Select.tsx
@@ -79,6 +79,7 @@ type SelectProps = {
readOnly?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
SelectDisplayProps?: Record;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
style?: React.CSSProperties;
value?: T | string;
@@ -170,7 +171,7 @@ function SelectInner(
options: optionsProp = [],
readOnly,
SelectDisplayProps,
- shadow = true,
+ shadow,
style,
value: valueProp,
variant = 'default',
@@ -535,6 +536,7 @@ function SelectInner(
`
${({ orientation, theme, size = '100%' }) =>
orientation === 'vertical'
- ? `
- height: ${getSize(size)};
- border-left: 2px solid ${theme.borderDark};
- border-right: 2px solid ${theme.borderLightest};
- margin: 0;
- `
- : `
- width: ${getSize(size)};
- border-bottom: 2px solid ${theme.borderLightest};
- border-top: 2px solid ${theme.borderDark};
- margin: 0;
- `}
+ ? css`
+ height: ${getSize(size)};
+ border-left: ${styledDimension(1)} solid ${theme.borderDark};
+ border-right: ${styledDimension(1)} solid ${theme.borderLightest};
+ margin: 0;
+ `
+ : css`
+ width: ${getSize(size)};
+ border-bottom: ${styledDimension(1)} solid ${theme.borderLightest};
+ border-top: ${styledDimension(1)} solid ${theme.borderDark};
+ margin: 0;
+ `}
`;
Separator.displayName = 'Separator';
diff --git a/src/Slider/Slider.tsx b/src/Slider/Slider.tsx
index 574229ad..99be5ef7 100644
--- a/src/Slider/Slider.tsx
+++ b/src/Slider/Slider.tsx
@@ -14,7 +14,8 @@ import {
createBoxStyles,
createDisabledTextStyles,
createFlatBoxStyles,
- createHatchedBackground
+ createHatchedBackground,
+ styledDimension
} from '../common';
import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled';
import useForkRef from '../common/hooks/useForkRef';
@@ -132,15 +133,16 @@ const Wrapper = styled.div`
content: '';
display: inline-block;
position: absolute;
- top: -2px;
- left: -15px;
- width: calc(100% + 30px);
- height: ${({ hasMarks }) => (hasMarks ? '41px' : '39px')};
+ top: ${styledDimension(-1)};
+ left: ${styledDimension(-7.5)};
+ width: calc(100% + ${styledDimension(15)});
+ height: ${({ hasMarks }) =>
+ hasMarks ? styledDimension(20.5) : styledDimension(19.5)};
${({ isFocused, theme }) =>
isFocused &&
- `
- outline: 2px dotted ${theme.materialText};
- `}
+ css`
+ outline: ${styledDimension(1)} dotted ${theme.materialText};
+ `}
}
${({ orientation, size }) =>
@@ -149,20 +151,22 @@ const Wrapper = styled.div`
height: ${size};
margin-right: 1.5rem;
&:before {
- left: -6px;
- top: -15px;
- height: calc(100% + 30px);
- width: ${({ hasMarks }) => (hasMarks ? '41px' : '39px')};
+ left: ${styledDimension(-1)};
+ top: ${styledDimension(-7.5)};
+ height: calc(100% + ${styledDimension(15)});
+ width: ${({ hasMarks }) =>
+ hasMarks ? styledDimension(20.5) : styledDimension(19.5)};
}
`
: css`
width: ${size};
margin-bottom: 1.5rem;
&:before {
- top: -2px;
- left: -15px;
- width: calc(100% + 30px);
- height: ${({ hasMarks }) => (hasMarks ? '41px' : '39px')};
+ top: ${styledDimension(-1)};
+ left: ${styledDimension(-7.5)};
+ width: calc(100% + ${styledDimension(15)});
+ height: ${({ hasMarks }) =>
+ hasMarks ? styledDimension(20.5) : styledDimension(19.5)};
}
`}
@@ -177,13 +181,13 @@ const sharedGrooveStyles = () => css`
left: 50%;
transform: translateX(-50%);
height: 100%;
- width: 8px;
+ width: ${styledDimension(4)};
`
: css`
left: 0;
top: 50%;
transform: translateY(-50%);
- height: 8px;
+ height: ${styledDimension(4)};
width: 100%;
`}
`;
@@ -209,22 +213,22 @@ const Thumb = styled.span`
${({ orientation }) =>
orientation === 'vertical'
? css`
- width: 32px;
- height: 18px;
- right: 2px;
+ width: ${styledDimension(16)};
+ height: ${styledDimension(9)};
+ right: ${styledDimension(1)};
transform: translateY(-50%);
`
: css`
- height: 32px;
- width: 18px;
- top: 2px;
+ height: ${styledDimension(16)};
+ width: ${styledDimension(9)};
+ top: ${styledDimension(1)};
transform: translateX(-50%);
`}
${({ variant }) =>
variant === 'flat'
? css`
${createFlatBoxStyles()}
- outline: 2px solid ${({ theme }) => theme.flatDark};
+ outline: ${styledDimension(1)} solid ${({ theme }) => theme.flatDark};
background: ${({ theme }) => theme.flatLight};
`
: css`
@@ -242,7 +246,7 @@ const Thumb = styled.span`
})}
`;
-const tickHeight = 6;
+const tickHeight = 3;
const Tick = styled.span`
display: inline-block;
position: absolute;
@@ -250,18 +254,21 @@ const Tick = styled.span`
${({ orientation }) =>
orientation === 'vertical'
? css`
- right: ${-tickHeight - 2}px;
+ right: ${styledDimension(-tickHeight - 1)};
bottom: 0px;
- transform: translateY(1px);
- width: ${tickHeight}px;
- border-bottom: 2px solid ${({ theme }) => theme.materialText};
+ transform: translateY(${styledDimension(0.5)});
+ width: ${styledDimension(tickHeight)};
+ border-bottom: ${styledDimension(1)} solid
+ ${({ theme }) => theme.materialText};
`
: css`
- bottom: ${-tickHeight}px;
- height: ${tickHeight}px;
- transform: translateX(-1px);
- border-left: 1px solid ${({ theme }) => theme.materialText};
- border-right: 1px solid ${({ theme }) => theme.materialText};
+ bottom: ${styledDimension(-tickHeight)};
+ height: ${styledDimension(tickHeight)};
+ transform: translateX(${styledDimension(-0.5)});
+ border-left: ${styledDimension(0.5)} solid
+ ${({ theme }) => theme.materialText};
+ border-right: ${styledDimension(0.5)} solid
+ ${({ theme }) => theme.materialText};
`}
color: ${({ theme }) => theme.materialText};
@@ -269,7 +276,9 @@ const Tick = styled.span`
$disabled &&
css`
${createDisabledTextStyles()}
- box-shadow: 1px 1px 0px ${theme.materialTextDisabledShadow};
+ box-shadow: ${styledDimension(0.5)} ${styledDimension(
+ 0.5
+ )} 0px ${theme.materialTextDisabledShadow};
border-color: ${theme.materialTextDisabled};
`}
`;
@@ -283,10 +292,13 @@ const Mark = styled.div`
${({ orientation }) =>
orientation === 'vertical'
? css`
- transform: translate(${tickHeight + 2}px, ${tickHeight + 1}px);
+ transform: translate(
+ ${styledDimension(tickHeight + 1)},
+ ${styledDimension(tickHeight + 0.5)}
+ );
`
: css`
- transform: translate(-0.5ch, calc(100% + 2px));
+ transform: translate(-0.5ch, calc(100% + ${styledDimension(1)}));
`}
`;
diff --git a/src/Table/TableBody.tsx b/src/Table/TableBody.tsx
index 542de3a0..8213e999 100644
--- a/src/Table/TableBody.tsx
+++ b/src/Table/TableBody.tsx
@@ -1,24 +1,30 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
-import { insetShadow } from '../common';
+import { createInnerBorderWithShadow } from '../common';
+import { defaultTrue } from '../common/utils';
import { CommonStyledProps } from '../types';
type TableBodyProps = {
children?: React.ReactNode;
+ shadow?: boolean;
} & React.HTMLAttributes &
CommonStyledProps;
-const StyledTableBody = styled.tbody`
+const StyledTableBody = styled.tbody>`
background: ${({ theme }) => theme.canvas};
display: table-row-group;
- box-shadow: ${insetShadow};
+ box-shadow: ${({ theme, shadow }) =>
+ createInnerBorderWithShadow({
+ theme,
+ hasInsetShadow: defaultTrue(shadow ?? theme.shadow)
+ })};
overflow-y: auto;
`;
const TableBody = forwardRef(
- function TableBody({ children, ...otherProps }, ref) {
+ function TableBody({ children, shadow = true, ...otherProps }, ref) {
return (
-
+
{children}
);
diff --git a/src/Table/TableDataCell.tsx b/src/Table/TableDataCell.tsx
index f97f8b76..c1d3e473 100644
--- a/src/Table/TableDataCell.tsx
+++ b/src/Table/TableDataCell.tsx
@@ -1,5 +1,6 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
+import { styledDimension } from '../common';
import { CommonStyledProps } from '../types';
type TableDataCellProps = {
@@ -8,7 +9,7 @@ type TableDataCellProps = {
CommonStyledProps;
const StyledTd = styled.td`
- padding: 0 8px;
+ padding: 0 ${styledDimension(4)};
`;
const TableDataCell = forwardRef(
diff --git a/src/Table/TableHeadCell.tsx b/src/Table/TableHeadCell.tsx
index e653d6b6..89a70f7b 100644
--- a/src/Table/TableHeadCell.tsx
+++ b/src/Table/TableHeadCell.tsx
@@ -1,6 +1,10 @@
import React, { forwardRef } from 'react';
import styled, { css } from 'styled-components';
-import { createBorderStyles, createDisabledTextStyles } from '../common';
+import {
+ createBorderStyles,
+ createDisabledTextStyles,
+ styledDimension
+} from '../common';
import { noOp } from '../common/utils';
import { CommonStyledProps } from '../types';
@@ -13,7 +17,7 @@ type TableHeadCellProps = {
const StyledHeadCell = styled.th<{ $disabled: boolean }>`
position: relative;
- padding: 0 8px;
+ padding: 0 ${styledDimension(4)};
display: table-cell;
vertical-align: inherit;
background: ${({ theme }) => theme.material};
@@ -40,12 +44,12 @@ const StyledHeadCell = styled.th<{ $disabled: boolean }>`
${createBorderStyles({ invert: true, style: 'window' })}
border-left: none;
border-top: none;
- padding-top: 2px;
+ padding-top: ${styledDimension(1)};
}
& > div {
position: relative;
- top: 2px;
+ top: ${styledDimension(1)};
}
}
`}
diff --git a/src/Table/TableRow.tsx b/src/Table/TableRow.tsx
index b601c093..9f5ac94b 100644
--- a/src/Table/TableRow.tsx
+++ b/src/Table/TableRow.tsx
@@ -1,5 +1,6 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
+import { styledDimension } from '../common';
import { blockSizes } from '../common/system';
type TableRowProps = {
@@ -9,8 +10,8 @@ type TableRowProps = {
const StyledTr = styled.tr`
color: inherit;
display: table-row;
- height: calc(${blockSizes.md} - 2px);
- line-height: calc(${blockSizes.md} - 2px);
+ height: calc(${blockSizes.md} - ${styledDimension(1)});
+ line-height: calc(${blockSizes.md} - ${styledDimension(1)});
vertical-align: middle;
outline: none;
diff --git a/src/Tabs/Tab.tsx b/src/Tabs/Tab.tsx
index 17f0666f..4f7c2e8b 100644
--- a/src/Tabs/Tab.tsx
+++ b/src/Tabs/Tab.tsx
@@ -1,8 +1,13 @@
import React, { forwardRef } from 'react';
-import styled from 'styled-components';
+import styled, { css } from 'styled-components';
-import { createBorderStyles, createBoxStyles, focusOutline } from '../common';
-import { blockSizes } from '../common/system';
+import {
+ createBorderStyles,
+ createBoxStyles,
+ focusOutline,
+ styledDimension
+} from '../common';
+import { styledBlockSize } from '../common/system';
import { CommonStyledProps } from '../types';
type TabProps = {
@@ -23,13 +28,13 @@ const StyledTab = styled.button`
align-items: center;
justify-content: center;
font-size: 1rem;
- height: ${blockSizes.md};
- line-height: ${blockSizes.md};
- padding: 0 8px;
+ height: ${styledBlockSize('md')};
+ line-height: ${styledBlockSize('md')};
+ padding: 0 ${styledDimension(4)};
border-bottom: none;
- border-top-left-radius: 5px;
- border-top-right-radius: 5px;
- margin: 0 0 -2px 0;
+ border-top-left-radius: ${styledDimension(2.5)};
+ border-top-right-radius: ${styledDimension(2.5)};
+ margin: 0 0 ${styledDimension(-1)} 0;
cursor: default;
color: ${({ theme }) => theme.materialText};
user-select: none;
@@ -43,29 +48,29 @@ const StyledTab = styled.button`
width: 100%;
height: 100%;
${focusOutline}
- outline-offset: -6px;
+ outline-offset: ${styledDimension(-3)};
}
${props =>
props.selected &&
- `
- z-index: 1;
- height: calc(${blockSizes.md} + 4px);
- top: -4px;
- margin-bottom: -6px;
- padding: 0 16px;
- margin-left: -8px;
- &:not(:last-child) {
- margin-right: -8px;
- }
- `}
+ css`
+ z-index: 1;
+ height: calc(${styledBlockSize('md')} + ${styledDimension(2)});
+ top: ${styledDimension(-2)};
+ margin-bottom: ${styledDimension(-3)};
+ padding: 0 ${styledDimension(8)};
+ margin-left: ${styledDimension(-4)};
+ &:not(:last-child) {
+ margin-right: ${styledDimension(-4)};
+ }
+ `}
&:before {
content: '';
position: absolute;
- width: calc(100% - 4px);
- height: 6px;
+ width: calc(100% - ${styledDimension(2)});
+ height: ${styledDimension(3)};
background: ${({ theme }) => theme.material};
- bottom: -4px;
- left: 2px;
+ bottom: ${styledDimension(-2)};
+ left: ${styledDimension(1)};
}
`;
diff --git a/src/Tabs/TabBody.tsx b/src/Tabs/TabBody.tsx
index 1afb4f54..83f781c7 100644
--- a/src/Tabs/TabBody.tsx
+++ b/src/Tabs/TabBody.tsx
@@ -1,7 +1,11 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
-import { createBorderStyles, createBoxStyles } from '../common';
+import {
+ createBorderStyles,
+ createBoxStyles,
+ styledDimension
+} from '../common';
import { CommonStyledProps } from '../types';
type TabBodyProps = {
@@ -15,7 +19,7 @@ const StyledTabBody = styled.div`
position: relative;
display: block;
height: 100%;
- padding: 16px;
+ padding: ${styledDimension(8)};
font-size: 1rem;
`;
const TabBody = forwardRef(
diff --git a/src/Tabs/Tabs.tsx b/src/Tabs/Tabs.tsx
index b0c95582..67665cb1 100644
--- a/src/Tabs/Tabs.tsx
+++ b/src/Tabs/Tabs.tsx
@@ -1,6 +1,7 @@
import React, { forwardRef, useMemo } from 'react';
import styled from 'styled-components';
+import { styledDimension } from '../common';
import { noOp } from '../common/utils';
import { CommonStyledProps } from '../types';
import { TabProps } from './Tab';
@@ -22,7 +23,7 @@ const StyledTabs = styled.div<{ isMultiRow: boolean }>`
flex-grow: 1;
}
button:last-child:before {
- border-right: 2px solid ${theme.borderDark};
+ border-right: ${styledDimension(1)} solid ${theme.borderDark};
}
`}
`;
@@ -34,8 +35,8 @@ const Row = styled.div.attrs(() => ({
display: flex;
flex-wrap: no-wrap;
text-align: left;
- left: 8px;
- width: calc(100% - 8px);
+ left: ${styledDimension(4)};
+ width: calc(100% - ${styledDimension(4)});
&:not(:first-child):before {
content: '';
@@ -43,8 +44,10 @@ const Row = styled.div.attrs(() => ({
right: 0;
left: 0;
height: 100%;
- border-right: 2px solid ${({ theme }) => theme.borderDarkest};
- border-left: 2px solid ${({ theme }) => theme.borderLightest};
+ border-right: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderDarkest};
+ border-left: ${styledDimension(1)} solid
+ ${({ theme }) => theme.borderLightest};
}
`;
diff --git a/src/TextInput/TextInput.tsx b/src/TextInput/TextInput.tsx
index 11f92999..49f3f6b0 100644
--- a/src/TextInput/TextInput.tsx
+++ b/src/TextInput/TextInput.tsx
@@ -33,6 +33,7 @@ type TextInputProps = {
disabled?: boolean;
fullWidth?: boolean;
multiline?: boolean;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
style?: React.CSSProperties;
variant?: 'default' | 'flat';
@@ -105,7 +106,7 @@ const TextInput = forwardRef<
disabled = false,
fullWidth,
onChange = noOp,
- shadow = true,
+ shadow,
style,
variant = 'default',
...otherProps
@@ -141,9 +142,10 @@ const TextInput = forwardRef<
return (
diff --git a/src/Tooltip/Tooltip.tsx b/src/Tooltip/Tooltip.tsx
index 60cf5558..0e44b803 100644
--- a/src/Tooltip/Tooltip.tsx
+++ b/src/Tooltip/Tooltip.tsx
@@ -1,7 +1,12 @@
import React, { forwardRef, useState } from 'react';
-import styled from 'styled-components';
-
-import { shadow } from '../common';
+import styled, {
+ css,
+ DefaultTheme,
+ FlattenInterpolation,
+ ThemeProps
+} from 'styled-components';
+
+import { shadow, styledDimension } from '../common';
import { isReactFocusEvent, isReactMouseEvent } from '../common/utils/events';
import { CommonStyledProps } from '../types';
@@ -33,19 +38,30 @@ type TooltipProps = {
> &
CommonStyledProps;
-const positioningStyles: Record = {
- top: `top: -4px;
- left: 50%;
- transform: translate(-50%, -100%);`,
- bottom: `bottom: -4px;
- left: 50%;
- transform: translate(-50%, 100%);`,
- left: `left: -4px;
- top: 50%;
- transform: translate(-100%, -50%);`,
- right: `right: -4px;
- top: 50%;
- transform: translate(100%, -50%);`
+const positioningStyles: Record<
+ TooltipPosition,
+ FlattenInterpolation>
+> = {
+ top: css`
+ top: -${styledDimension(2)};
+ left: 50%;
+ transform: translate(-50%, -100%);
+ `,
+ bottom: css`
+ bottom: -${styledDimension(2)};
+ left: 50%;
+ transform: translate(-50%, 100%);
+ `,
+ left: css`
+ left: -${styledDimension(2)};
+ top: 50%;
+ transform: translate(-100%, -50%);
+ `,
+ right: css`
+ right: -${styledDimension(2)};
+ top: 50%;
+ transform: translate(100%, -50%);
+ `
};
const Tip = styled.span<{ position: TooltipPosition; show: boolean }>`
@@ -53,8 +69,8 @@ const Tip = styled.span<{ position: TooltipPosition; show: boolean }>`
z-index: 1;
display: ${props => (props.show ? 'block' : 'none')};
- padding: 4px;
- border: 2px solid ${({ theme }) => theme.borderDarkest};
+ padding: ${styledDimension(2)};
+ border: ${styledDimension(1)} solid ${({ theme }) => theme.borderDarkest};
background: ${({ theme }) => theme.tooltip};
box-shadow: ${shadow};
text-align: center;
diff --git a/src/TreeView/TreeView.tsx b/src/TreeView/TreeView.tsx
index f8a85492..c808cb33 100644
--- a/src/TreeView/TreeView.tsx
+++ b/src/TreeView/TreeView.tsx
@@ -1,5 +1,6 @@
import React, { forwardRef, useCallback } from 'react';
import styled, { css } from 'styled-components';
+import { styledDimension } from '../common';
import useControlledOrUncontrolled from '../common/hooks/useControlledOrUncontrolled';
import { LabelText, StyledLabel } from '../common/SwitchBase';
@@ -59,7 +60,8 @@ const focusedElementStyles = css<{ $disabled: boolean }>`
${Text} {
background: ${({ theme }) => theme.hoverBackground};
color: ${({ theme }) => theme.materialTextInvert};
- outline: 2px dotted ${({ theme }) => theme.focusSecondary};
+ outline: ${styledDimension(1)} dotted
+ ${({ theme }) => theme.focusSecondary};
}
}
`
@@ -76,16 +78,17 @@ const TreeWrapper = styled.ul<{ isRootLevel: boolean }>`
&:before {
content: '';
position: absolute;
- top: 20px;
+ top: ${styledDimension(10)};
bottom: 0;
- left: 5.5px;
- width: 1px;
- border-left: 2px dashed ${({ theme }) => theme.borderDark};
+ left: ${styledDimension(2.75)};
+ width: ${styledDimension(0.5)};
+ border-left: ${styledDimension(1)} dashed
+ ${({ theme }) => theme.borderDark};
}
`}
ul {
- padding-left: 19.5px;
+ padding-left: ${styledDimension(9.75)};
}
li {
@@ -94,18 +97,19 @@ const TreeWrapper = styled.ul<{ isRootLevel: boolean }>`
&:before {
content: '';
position: absolute;
- top: 17.5px;
- left: 5.5px;
- width: 22px;
- border-top: 2px dashed ${({ theme }) => theme.borderDark};
- font-size: 12px;
+ top: ${styledDimension(8.75)};
+ left: ${styledDimension(2.75)};
+ width: ${styledDimension(11)};
+ border-top: ${styledDimension(1)} dashed
+ ${({ theme }) => theme.borderDark};
+ font-size: ${styledDimension(6)};
}
}
`;
const TreeItem = styled.li<{ hasItems: boolean; isRootLevel: boolean }>`
position: relative;
- padding-left: ${({ hasItems }) => (!hasItems ? '13px' : '0')};
+ padding-left: ${({ hasItems }) => (!hasItems ? styledDimension(6.5) : '0')};
${({ isRootLevel }) =>
!isRootLevel
@@ -115,10 +119,10 @@ const TreeItem = styled.li<{ hasItems: boolean; isRootLevel: boolean }>`
content: '';
position: absolute;
z-index: 1;
- top: 19.5px;
+ top: ${styledDimension(9.75)};
bottom: 0;
- left: 1.5px;
- width: 10px;
+ left: ${styledDimension(0.75)};
+ width: ${styledDimension(5)};
background: ${({ theme }) => theme.material};
}
}
@@ -128,10 +132,10 @@ const TreeItem = styled.li<{ hasItems: boolean; isRootLevel: boolean }>`
&:after {
content: '';
position: absolute;
- top: 19.5px;
- left: 1px;
+ top: ${styledDimension(9.75)};
+ left: ${styledDimension(0.5)};
bottom: 0;
- width: 10px;
+ width: ${styledDimension(5)};
background: ${({ theme }) => theme.material};
}
}
@@ -141,10 +145,11 @@ const TreeItem = styled.li<{ hasItems: boolean; isRootLevel: boolean }>`
&:after {
content: '';
position: absolute;
- top: -18px;
+ top: ${styledDimension(-9)};
bottom: 0;
- left: 25px;
- border-left: 2px dashed ${({ theme }) => theme.borderDark};
+ left: ${styledDimension(12.5)};
+ border-left: ${styledDimension(1)} dashed
+ ${({ theme }) => theme.borderDark};
}
}
`;
@@ -165,7 +170,7 @@ const Summary = styled.summary`
align-items: center;
color: ${({ theme }) => theme.materialText};
user-select: none;
- padding-left: 18px;
+ padding-left: ${styledDimension(9)};
${focusedElementStyles};
&::-webkit-details-marker {
@@ -177,12 +182,12 @@ const Summary = styled.summary`
position: absolute;
left: 0;
display: block;
- width: 8px;
- height: 9px;
- border: 2px solid #808080;
- padding-left: 1px;
+ width: ${styledDimension(4)};
+ height: ${styledDimension(4.5)};
+ border: ${styledDimension(1)} solid #808080;
+ padding-left: ${styledDimension(0.5)};
background-color: #fff;
- line-height: 8px;
+ line-height: ${styledDimension(4)};
text-align: center;
}
`;
@@ -193,8 +198,8 @@ const TitleWithIcon = styled(StyledLabel)`
background: none;
border: 0;
font-family: inherit;
- padding-top: 8px;
- padding-bottom: 8px;
+ padding-top: ${styledDimension(4)};
+ padding-bottom: ${styledDimension(4)};
margin: 0;
${focusedElementStyles};
`;
@@ -203,9 +208,9 @@ const Icon = styled.span`
display: flex;
align-items: center;
justify-content: center;
- width: 16px;
- height: 16px;
- margin-right: 6px;
+ width: ${styledDimension(8)};
+ height: ${styledDimension(8)};
+ margin-right: ${styledDimension(3)};
`;
function toggleItem(state: T[], id: T) {
diff --git a/src/Window/Window.tsx b/src/Window/Window.tsx
index 79c003dd..9cd03304 100644
--- a/src/Window/Window.tsx
+++ b/src/Window/Window.tsx
@@ -1,19 +1,24 @@
import React, { forwardRef } from 'react';
import styled, { css } from 'styled-components';
-import { createBorderStyles, createBoxStyles } from '../common';
+import {
+ createBorderStyles,
+ createBoxStyles,
+ styledDimension
+} from '../common';
import { CommonStyledProps } from '../types';
type WindowProps = {
children?: React.ReactNode;
resizable?: boolean;
resizeRef?: React.Ref;
+ /** @deprecated Change `shadow` property on theme */
shadow?: boolean;
} & React.HTMLAttributes &
CommonStyledProps;
const StyledWindow = styled.div`
position: relative;
- padding: 4px;
+ padding: ${styledDimension(2)};
font-size: 1rem;
${createBorderStyles({ style: 'window' })}
${createBoxStyles()}
@@ -23,10 +28,10 @@ const ResizeHandle = styled.span`
${({ theme }) => css`
display: inline-block;
position: absolute;
- bottom: 10px;
- right: 10px;
- width: 25px;
- height: 25px;
+ bottom: ${styledDimension(5)};
+ right: ${styledDimension(5)};
+ width: ${styledDimension(12.5)};
+ height: ${styledDimension(12.5)};
background-image: linear-gradient(
135deg,
${theme.borderLightest} 16.67%,
@@ -41,19 +46,16 @@ const ResizeHandle = styled.span`
${theme.borderDark} 83.33%,
${theme.borderDark} 100%
);
- background-size: 8.49px 8.49px;
+ background-size: ${styledDimension(4.245)} ${styledDimension(4.245)};
clip-path: polygon(100% 0px, 0px 100%, 100% 100%);
cursor: nwse-resize;
`}
`;
const Window = forwardRef(
- (
- { children, resizable = false, resizeRef, shadow = true, ...otherProps },
- ref
- ) => {
+ ({ children, resizable = false, resizeRef, shadow, ...otherProps }, ref) => {
return (
-
+
{children}
{resizable && (
diff --git a/src/Window/WindowContent.tsx b/src/Window/WindowContent.tsx
index 7206ef7a..8ee39bcd 100644
--- a/src/Window/WindowContent.tsx
+++ b/src/Window/WindowContent.tsx
@@ -1,5 +1,6 @@
import React, { forwardRef } from 'react';
import styled from 'styled-components';
+import { styledDimension } from '../common';
import { CommonStyledProps } from '../types';
type WindowContentProps = {
@@ -8,7 +9,7 @@ type WindowContentProps = {
CommonStyledProps;
const StyledWindowContent = styled.div`
- padding: 16px;
+ padding: ${styledDimension(8)};
`;
const WindowContent = forwardRef(
diff --git a/src/Window/WindowHeader.tsx b/src/Window/WindowHeader.tsx
index 8c1bdd71..6c93b3ca 100644
--- a/src/Window/WindowHeader.tsx
+++ b/src/Window/WindowHeader.tsx
@@ -1,6 +1,7 @@
import React, { forwardRef } from 'react';
import styled, { css } from 'styled-components';
import { StyledButton } from '../Button/Button';
+import { styledDimension } from '../common';
import { CommonStyledProps } from '../types';
type WindowHeaderProps = {
@@ -10,12 +11,12 @@ type WindowHeaderProps = {
CommonStyledProps;
const StyledWindowHeader = styled.div>`
- height: 33px;
- line-height: 33px;
+ height: ${styledDimension(16.5)};
+ line-height: ${styledDimension(16.5)};
padding-left: 0.25rem;
- padding-right: 3px;
+ padding-right: ${styledDimension(1.5)};
font-weight: bold;
- border: 2px solid ${({ theme }) => theme.material};
+ border: ${styledDimension(1)} solid ${({ theme }) => theme.material};
${({ active }) =>
active === false
? css`
@@ -30,8 +31,8 @@ const StyledWindowHeader = styled.div>`
${StyledButton} {
padding-left: 0;
padding-right: 0;
- height: 27px;
- width: 31px;
+ height: ${styledDimension(13.5)};
+ width: ${styledDimension(15.5)};
}
`;
diff --git a/src/common/SwitchBase.ts b/src/common/SwitchBase.ts
index 717e268f..f807996a 100644
--- a/src/common/SwitchBase.ts
+++ b/src/common/SwitchBase.ts
@@ -1,16 +1,16 @@
import styled, { css } from 'styled-components';
-import { createDisabledTextStyles, focusOutline } from '.';
+import { createDisabledTextStyles, focusOutline, styledDimension } from '.';
import { StyledMenuListItem } from '../MenuList/MenuList';
-export const size = 20;
+export const size = 10;
export const StyledInput = styled.input`
position: absolute;
left: 0;
margin: 0;
- width: ${size}px;
- height: ${size}px;
+ width: ${styledDimension(size)};
+ height: ${styledDimension(size)};
opacity: 0;
z-index: -1;
`;
@@ -19,7 +19,7 @@ export const StyledLabel = styled.label<{ $disabled: boolean }>`
display: inline-flex;
align-items: center;
position: relative;
- margin: 8px 0;
+ margin: ${styledDimension(4)} 0;
cursor: ${({ $disabled }) => (!$disabled ? 'pointer' : 'auto')};
user-select: none;
font-size: 1rem;
@@ -43,8 +43,8 @@ export const StyledLabel = styled.label<{ $disabled: boolean }>`
export const LabelText = styled.span`
display: inline-block;
line-height: 1;
- padding: 2px;
- ${StyledInput}:focus ~ & {
+ padding: ${styledDimension(1)};
+ ${StyledInput}:focus ~& {
${focusOutline}
}
${StyledInput}:not(:disabled) ~ &:active {
diff --git a/src/common/constants.ts b/src/common/constants.ts
new file mode 100644
index 00000000..7c9756a6
--- /dev/null
+++ b/src/common/constants.ts
@@ -0,0 +1 @@
+export const SCALE = 2;
diff --git a/src/common/index.spec.ts b/src/common/index.spec.ts
new file mode 100644
index 00000000..f60e20a6
--- /dev/null
+++ b/src/common/index.spec.ts
@@ -0,0 +1,34 @@
+import { SCALE } from './constants';
+import { styledDimension } from './index';
+import original from './themes/original';
+
+describe(styledDimension, () => {
+ it('returns the default scale with no theme', () => {
+ expect(styledDimension()({ theme: undefined })).toEqual(`${SCALE}px`);
+ });
+
+ it('returns the default scale with a theme that has no scale', () => {
+ const themeWithoutScale = {
+ ...original,
+ scale: undefined
+ };
+ expect(styledDimension()({ theme: themeWithoutScale })).toEqual(
+ `${SCALE}px`
+ );
+ });
+
+ it('returns a proportional scale', () => {
+ const themeScale1 = {
+ ...original,
+ scale: 1
+ };
+ const themeScale3 = {
+ ...original,
+ scale: 3
+ };
+ expect(styledDimension()({ theme: themeScale1 })).toEqual('1px');
+ expect(styledDimension()({ theme: themeScale3 })).toEqual('3px');
+ expect(styledDimension(5)({ theme: themeScale1 })).toEqual('5px');
+ expect(styledDimension(5)({ theme: themeScale3 })).toEqual('15px');
+ });
+});
diff --git a/src/common/index.ts b/src/common/index.ts
index 6789ed15..dee7b432 100644
--- a/src/common/index.ts
+++ b/src/common/index.ts
@@ -1,13 +1,18 @@
import { css } from 'styled-components';
-import { Color, CommonThemeProps, Theme } from '../types';
+import { CommonThemeProps, Theme } from '../types';
+import { SCALE } from './constants';
+import { Color, ThemeColors } from './themes/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)';
+export const styledDimension =
+ (ratio = 1, { delta = 0, unit = 'px' } = {}) =>
+ ({ theme }: { theme: Theme | undefined }) =>
+ `${(theme?.scale ?? SCALE) * ratio + delta}${unit}`;
export const createDisabledTextStyles = () => css`
-webkit-text-fill-color: ${({ theme }) => theme.materialTextDisabled};
color: ${({ theme }) => theme.materialTextDisabled};
- text-shadow: 1px 1px ${({ theme }) => theme.materialTextDisabledShadow};
+ text-shadow: ${styledDimension(0.5)} ${styledDimension(0.5)}
+ ${({ theme }) => theme.materialTextDisabledShadow};
/* filter: grayscale(100%); */
`;
@@ -15,8 +20,8 @@ export const createBoxStyles = ({
background = 'material',
color = 'materialText'
}: {
- background?: keyof Theme;
- color?: keyof Theme;
+ background?: keyof ThemeColors;
+ color?: keyof ThemeColors;
} = {}) => css`
box-sizing: border-box;
display: inline-block;
@@ -28,28 +33,34 @@ export const createBoxStyles = ({
export const createHatchedBackground = ({
mainColor = 'black',
secondaryColor = 'transparent',
- pixelSize = 2
-}) => css`
- background-image: ${[
- `linear-gradient(
- 45deg,
- ${mainColor} 25%,
- transparent 25%,
- transparent 75%,
- ${mainColor} 75%
- )`,
- `linear-gradient(
- 45deg,
- ${mainColor} 25%,
- transparent 25%,
- transparent 75%,
- ${mainColor} 75%
- )`
- ].join(',')};
- background-color: ${secondaryColor};
- background-size: ${`${pixelSize * 2}px ${pixelSize * 2}px`};
- background-position: 0 0, ${`${pixelSize}px ${pixelSize}px`};
-`;
+ pixelSize
+}: {
+ mainColor?: Color;
+ secondaryColor?: Color;
+ pixelSize?: number;
+}) => {
+ const size = styledDimension(pixelSize !== undefined ? pixelSize / 2 : 1);
+ const doubleSize = styledDimension(pixelSize !== undefined ? pixelSize : 2);
+ return css`
+ background-image: linear-gradient(
+ 45deg,
+ ${mainColor} 25%,
+ transparent 25%,
+ transparent 75%,
+ ${mainColor} 75%
+ ),
+ linear-gradient(
+ 45deg,
+ ${mainColor} 25%,
+ transparent 25%,
+ transparent 75%,
+ ${mainColor} 75%
+ );
+ background-color: ${secondaryColor};
+ background-size: ${doubleSize} ${doubleSize};
+ background-position: 0 0, ${size} ${size};
+ `;
+};
export const createFlatBoxStyles = () => css`
position: relative;
@@ -58,9 +69,9 @@ export const createFlatBoxStyles = () => css`
color: ${({ theme }) => theme.materialText};
background: ${({ $disabled, theme }) =>
$disabled ? theme.flatLight : theme.canvas};
- border: 2px solid ${({ theme }) => theme.canvas};
- outline: 2px solid ${({ theme }) => theme.flatDark};
- outline-offset: -4px;
+ border: ${styledDimension(1)} solid ${({ theme }) => theme.canvas};
+ outline: ${styledDimension(1)} solid ${({ theme }) => theme.flatDark};
+ outline-offset: -${styledDimension(2)};
`;
export type BorderStyles =
@@ -74,10 +85,10 @@ export type BorderStyles =
| 'window';
type BorderStyle = {
- topLeftOuter: keyof Theme;
- topLeftInner: keyof Theme | null;
- bottomRightInner: keyof Theme | null;
- bottomRightOuter: keyof Theme;
+ topLeftOuter: keyof ThemeColors;
+ topLeftInner: keyof ThemeColors | undefined;
+ bottomRightInner: keyof ThemeColors | undefined;
+ bottomRightOuter: keyof ThemeColors;
};
const borderStyles: Record = {
@@ -95,14 +106,14 @@ const borderStyles: Record = {
},
buttonThin: {
topLeftOuter: 'borderLightest',
- topLeftInner: null,
- bottomRightInner: null,
+ topLeftInner: undefined,
+ bottomRightInner: undefined,
bottomRightOuter: 'borderDark'
},
buttonThinPressed: {
topLeftOuter: 'borderDark',
- topLeftInner: null,
- bottomRightInner: null,
+ topLeftInner: undefined,
+ bottomRightInner: undefined,
bottomRightOuter: 'borderLightest'
},
field: {
@@ -119,8 +130,8 @@ const borderStyles: Record = {
},
status: {
topLeftOuter: 'borderDark',
- topLeftInner: null,
- bottomRightInner: null,
+ topLeftInner: undefined,
+ bottomRightInner: undefined,
bottomRightOuter: 'borderLightest'
},
window: {
@@ -139,23 +150,35 @@ export const createInnerBorderWithShadow = ({
hasInsetShadow = false
}: {
theme: Theme;
- topLeftInner: keyof Theme | null;
- bottomRightInner: keyof Theme | null;
+ topLeftInner?: keyof ThemeColors;
+ bottomRightInner?: keyof ThemeColors;
hasShadow?: boolean;
hasInsetShadow?: boolean;
-}) =>
- [
- hasShadow ? shadow : false,
- hasInsetShadow ? insetShadow : false,
- topLeftInner !== null
- ? `inset 1px 1px 0px 1px ${theme[topLeftInner]}`
+}) => {
+ const scale = Number(styledDimension(1, { unit: '' })({ theme }));
+ return [
+ hasShadow
+ ? `${scale * 2}px ${scale * 2}px ${scale * 5}px 0 rgba(0, 0, 0, 0.35)`
: false,
- bottomRightInner !== null
- ? `inset -1px -1px 0 1px ${theme[bottomRightInner]}`
+ hasInsetShadow
+ ? `inset ${scale * 1}px ${scale * 1}px ${
+ scale * 1.5
+ }px rgba(0, 0, 0, 0.2)`
+ : false,
+ topLeftInner !== undefined
+ ? `inset ${scale / 2}px ${scale / 2}px 0px ${scale / 2}px ${
+ theme[topLeftInner]
+ }`
+ : false,
+ bottomRightInner !== undefined
+ ? `inset -${scale / 2}px -${scale / 2}px 0 ${scale / 2}px ${
+ theme[bottomRightInner]
+ }`
: false
]
.filter(Boolean)
.join(', ');
+};
export const createBorderStyles = ({
invert = false,
@@ -169,7 +192,7 @@ export const createBorderStyles = ({
} as const;
return css`
border-style: solid;
- border-width: 2px;
+ border-width: ${styledDimension(1)};
border-left-color: ${({ theme }) =>
theme[borderStyles[style][borders.topLeftOuter]]};
border-top-color: ${({ theme }) =>
@@ -178,12 +201,12 @@ export const createBorderStyles = ({
theme[borderStyles[style][borders.bottomRightOuter]]};
border-bottom-color: ${({ theme }) =>
theme[borderStyles[style][borders.bottomRightOuter]]};
- box-shadow: ${({ theme, shadow: hasShadow }) =>
+ box-shadow: ${({ defaultShadow, theme, shadow: hasShadow }) =>
createInnerBorderWithShadow({
theme,
topLeftInner: borderStyles[style][borders.topLeftInner],
bottomRightInner: borderStyles[style][borders.bottomRightInner],
- hasShadow
+ hasShadow: (defaultShadow && theme.shadow) || hasShadow
})};
`;
};
@@ -196,16 +219,23 @@ export const createWellBorderStyles = (invert = false) =>
});
export const focusOutline = () => css`
- outline: 2px dotted ${({ theme }) => theme.materialText};
+ outline: ${styledDimension(1)} dotted ${({ theme }) => theme.materialText};
`;
const nodeBtoa = (string: string) => Buffer.from(string).toString('base64');
const base64encode = typeof btoa !== 'undefined' ? btoa : nodeBtoa;
-const createTriangleSVG = (color: Color, angle = 0) => {
- const svg = `