Skip to content

Commit

Permalink
Merge pull request #47 from stoplightio/bug/no-keys
Browse files Browse the repository at this point in the history
[SL-1151] No keys bug
  • Loading branch information
P0lip authored Jan 7, 2019
2 parents 74286fa + 22522fc commit 8eb2441
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 211 deletions.
28 changes: 21 additions & 7 deletions src/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @jsx jsx */

import { jsx } from '@emotion/core';
import { Interpolation, jsx } from '@emotion/core';
import { ComponentClass, CSSProperties, forwardRef, FunctionComponent, HTMLAttributes, ReactHTML } from 'react';
import * as ss from 'styled-system';

Expand All @@ -18,7 +18,9 @@ export const Box = forwardRef<HTMLOrSVGElement, IBox<HTMLOrSVGElement>>((props,
borderLeft,
borderRight,
borderRadius,
borderColor,
boxShadow,
cursor,
display,
fontSize,
fontWeight,
Expand Down Expand Up @@ -56,18 +58,22 @@ export const Box = forwardRef<HTMLOrSVGElement, IBox<HTMLOrSVGElement>>((props,
maxWidth,
opacity,
overflow,
overflowX,
overflowY,
textDecoration,
textDecorationColor,
textTransform,
color,
backgroundColor,
transform,
visibility,
...rest
} = props;

/** Add all the supported styles, passing in the relevant props. */
const css = [
const css: IBoxCSS = [
ss.borders({ border, borderTop, borderBottom, borderLeft, borderRight }),
ss.borderColor({ borderColor }),
ss.borderRadius({ borderRadius }),
ss.boxShadow({ boxShadow }),
ss.space({ m, mt, mb, ml, mr, mx, my, p, pt, pb, pl, pr, px, py }),
Expand All @@ -89,7 +95,6 @@ export const Box = forwardRef<HTMLOrSVGElement, IBox<HTMLOrSVGElement>>((props,
ss.minWidth({ minWidth }),
ss.maxWidth({ maxWidth }),

ss.overflow({ overflow }),
ss.position({ position }),
ss.top({ top }),
ss.bottom({ bottom }),
Expand All @@ -103,12 +108,15 @@ export const Box = forwardRef<HTMLOrSVGElement, IBox<HTMLOrSVGElement>>((props,
sl.color({ color, backgroundColor }),
sl.textTransform({ textTransform }),
sl.textDecoration({ textDecoration, textDecorationColor }),
sl.cursor({ cursor }),
sl.visibility({ visibility }),
sl.overflow({ overflow, overflowX, overflowY }),
];

/** User provided style get pushed on last. */
if (style) css.push(style);
if (style) css.push(style as IBoxCSS);

return jsx<Partial<IBox<HTMLElement>>>(
return jsx<Partial<IBox<HTMLOrSVGElement>>>(
as,
{
...rest,
Expand All @@ -121,8 +129,12 @@ export const Box = forwardRef<HTMLOrSVGElement, IBox<HTMLOrSVGElement>>((props,

export interface IBox<T extends HTMLOrSVGElement = HTMLDivElement>
extends HTMLAttributes<T>,
sl.IColorProps,
sl.ITextDecorationProps,
sl.IListStyleProps,
sl.ITextTransformProps,
sl.IVisibilityProps,
sl.IOverflowProps,
sl.ICursorProps,
ss.BorderProps,
ss.BorderTopProps,
ss.BorderBottomProps,
Expand Down Expand Up @@ -156,6 +168,8 @@ export interface IBox<T extends HTMLOrSVGElement = HTMLDivElement>
as?: keyof ReactHTML | FunctionComponent | ComponentClass;
children?: any;
style?: CSSProperties;
css?: any;
css?: IBoxCSS;
[key: string]: any;
}

export type IBoxCSS = Interpolation | Interpolation[];
143 changes: 51 additions & 92 deletions src/Checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,115 +2,74 @@

import { jsx } from '@emotion/core';
import { Omit } from '@stoplight/types';
import noop = require('lodash/noop');
import { FunctionComponent, ReactEventHandler, useState } from 'react';
import { ChangeEventHandler, FunctionComponent, useCallback, useState } from 'react';

import { Box, Flex, IBox, Icon, useTheme } from './';
import { Box, Flex, IBox, useTheme } from './';

interface ICheckboxInputProps {
id: IBox['id'];
onChange: ReactEventHandler<HTMLInputElement>;
}
export const Checkbox: FunctionComponent<ICheckbox> = props => {
const { id, disabled: isDisabled, onChange, ...rest } = props;

interface ICheckboxInput extends ICheckboxInputProps {}
const [checked, setValue] = useState<boolean>(props.checked || false);
const isChecked = props.hasOwnProperty('checked') ? props.checked : checked;

const CheckboxInput: FunctionComponent<ICheckboxInput> = props => {
return jsx(Box, {
...props,
as: 'input',
type: 'checkbox',
position: 'absolute',
style: {
clip: 'rect(1px, 1px, 1px, 1px)',
},
});
const css = checkboxStyles({ isDisabled, isChecked });

const handleChange = useCallback<ChangeEventHandler<HTMLInputElement>>(({ target }) => {
setValue(target.checked);
if (onChange !== undefined) {
onChange(target.checked);
}
}, []);

return (
<Flex {...rest} as="label" css={css} htmlFor={id}>
<Box
as="input"
type="checkbox"
id={id}
checked={checked}
onChange={handleChange}
position="absolute"
css={{ clip: 'rect(1px, 1px, 1px, 1px)' }}
/>
<svg aria-hidden="true" viewBox="0 0 512 512" width="14px" height="14px">
<path
fill="currentColor"
d="M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z"
/>
</svg>
</Flex>
);
};

interface ICheckboxInnerProps {
isChecked: boolean;
isDisabled: boolean;
width?: IBox['width'];
height?: IBox['height'];
export interface ICheckboxProps {
id: IBox['id'];
onChange?: (checked: boolean) => void;
}

export interface ICheckboxInner extends ICheckboxInnerProps {}

const CheckboxInner: FunctionComponent<ICheckboxInner> = props => {
const css = checkboxInnerStyles(props);

return jsx(
Flex,
{
as: 'span',
css,
},
props.isChecked && [jsx(Icon, { icon: 'check', backgroundColor: 'inherit' })]
);
};
export interface ICheckbox extends ICheckboxProps, Omit<IBox<HTMLLabelElement>, 'as|onChange'> {}

const checkboxInnerStyles = ({ isDisabled, isChecked, height = '20px', width = '20px' }: ICheckboxInner) => {
export const checkboxStyles = ({ isChecked, isDisabled }: ICheckboxStyles) => {
const theme = useTheme();

return {
margin: 0,
padding: 0,
borderRadius: '5px',
alignItems: 'center',
backgroundColor: isChecked ? theme.checkbox.checkedBg : theme.checkbox.bg,
color: theme.checkbox.fg,
borderRadius: '5px',
color: isChecked ? theme.checkbox.fg : theme.checkbox.bg,
cursor: isDisabled ? 'not-allowed' : 'pointer',
width,
height,
opacity: isDisabled ? 0.6 : 1,
fontSize: '14px',
alignItems: 'center',
height: '20px',
justifyContent: 'center',
transition: 'background-color .15s ease-in-out',
opacity: isDisabled ? 0.6 : 1,
overflow: 'hidden',
margin: 0,
padding: 0,
width: '20px',
transition: 'background-color .15s ease-in-out',
};
};

export const Checkbox: FunctionComponent<ICheckbox> = props => {
const { id, disabled: isDisabled, width, height, onChange = noop, ...rest } = props;
const css = checkboxStyles();

const [checked, setValue] = useState<boolean>(props.checked || false);
const isChecked = props.hasOwnProperty('checked') ? props.checked : checked;

const handleChange: ReactEventHandler<HTMLInputElement> = event => {
setValue(event.currentTarget.checked);
onChange(event.currentTarget.checked);
};

return jsx(
Box,
{
...rest,
as: 'label',
htmlFor: id,
css,
},
[
jsx(CheckboxInput, {
id,
onChange: handleChange,
}),
jsx(CheckboxInner, {
isChecked,
isDisabled,
height,
width,
}),
]
);
};

export interface ICheckboxProps {
id: IBox['id'];
onChange?: (checked: boolean) => void;
interface ICheckboxStyles {
isChecked: boolean;
isDisabled: boolean;
}

export interface ICheckbox extends ICheckboxProps, Omit<IBox<HTMLLabelElement>, 'as|onChange'> {}

export const checkboxStyles = () => ({
display: 'inline-block',
});
10 changes: 3 additions & 7 deletions src/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import * as sl from './styles';
export const List: FunctionComponent<IList> = props => {
const { as = 'ul', listStyle, listStylePosition, ...rest } = props;

const css = [sl.listStyle({ listStyle, listStylePosition })];
const css = sl.listStyle({ listStyle, listStylePosition });

return jsx(Box, {
...rest,
css,
as,
});
return <Box {...rest} as={as} css={css} />;
};

export interface IList extends IListProps, sl.IColorProps, Omit<IBox<HTMLUListElement | HTMLOListElement>, 'as'> {}
export interface IList extends IListProps, sl.IListStyleProps, Omit<IBox<HTMLUListElement | HTMLOListElement>, 'as'> {}

export interface IListProps {
as?: 'ul' | 'ol';
Expand Down
8 changes: 4 additions & 4 deletions src/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { jsx } from '@emotion/core';

import { FunctionComponent, ReactNode } from 'react';

import { Box } from './Box';
import { Box, IBoxCSS } from './Box';
import { Flex, IFlex } from './Flex';
import { useHover } from './hooks/useHover';
import { Icon, IIcon } from './Icon';
Expand Down Expand Up @@ -167,15 +167,15 @@ export interface IMenuItemProps {

export interface IMenuItem extends IMenuItemProps, Pick<IFlex, Exclude<keyof IFlex, 'title'>> {}

const menuItemStyles = ({ disabled, onClick }: Partial<IMenuItemProps>) => {
const menuItemStyles = ({ disabled, onClick }: Partial<IMenuItemProps>): IBoxCSS => {
const theme = useTheme();

return [
{
alignItems: 'center',
padding: '6px 10px', // @md @lg'
padding: '6px 10px',
cursor: disabled ? 'not-allowed' : onClick ? 'pointer' : 'default',
opacity: disabled && 0.6,
opacity: disabled ? 0.6 : 1,

':hover': {
backgroundColor: theme.menu.hoverBg,
Expand Down
Loading

0 comments on commit 8eb2441

Please sign in to comment.