Skip to content

Commit

Permalink
Merge pull request #16 from stoplightio/SL-640/state
Browse files Browse the repository at this point in the history
Sl 640/stateful-components
  • Loading branch information
casserni authored Nov 20, 2018
2 parents 1c3fe79 + 34d1876 commit 038266b
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 123 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,14 @@
"@fortawesome/react-fontawesome": "0.1.3",
"@types/enzyme": "^3.1.15",
"@types/lodash": "4.x.x",
"@types/react": "16.x.x",
"@types/react-dom": "16.x.x",
"@types/react-input-autosize": "2.0.x",
"@types/react-textarea-autosize": "4.3.x",
"@types/styled-components": "4.0.x",
"@types/styled-system": "3.0.x",
"lodash": "4.x.x",
"react-dom": "^16.7.0-alpha.2",
"react-contextmenu": "2.10.x",
"react-input-autosize": "2.2.x",
"react-textarea-autosize": "7.1.0-1",
Expand All @@ -65,14 +68,11 @@
"@fortawesome/free-solid-svg-icons": "5.5.x",
"@sambego/storybook-state": "1.x.x",
"@stoplight/scripts": "1.2.3",
"@types/react": "16.x.x",
"@types/react-dom": "16.x.x",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.7.0",
"enzyme-to-json": "^3.3.4",
"jest-enzyme": "^7.0.1",
"react": "16.x.x",
"react-dom": "16.x.x",
"react": "^16.7.0-alpha.2",
"storybook-chromatic": "1.2.x",
"typescript": "3.1.6"
},
Expand Down
86 changes: 46 additions & 40 deletions src/Checkbox.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,63 @@
import noop = require('lodash/noop');
import * as React from 'react';

import { Box } from './Box';
import { Flex } from './Flex';
import { Icon } from './Icon';
import { Input } from './Input';
import { styled } from './utils';

export interface ICheckboxProps {
checked?: boolean;
disabled?: boolean;
id?: string;
className?: string;
checked?: boolean;
disabled?: boolean;
width?: string;
height?: string;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
onChange?: (checked: boolean) => void;
}

export const Checkbox = styled<ICheckboxProps>((props: ICheckboxProps) => {
const { id, className, checked, width, height, disabled, onChange } = props;
export const BasicCheckbox = (props: ICheckboxProps) => {
const { id, className, width, height, disabled, onChange = noop } = props;

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

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.checked);
onChange(event.target.checked);
};

return (
<span className={className}>
<Box display="inline-block">
<Input
type="checkbox"
id={id}
checked={checked}
disabled={disabled}
onChange={onChange}
position="absolute"
css={{ clip: 'rect(1px, 1px, 1px, 1px)' }}
/>
<Flex
as="span"
display="block"
m="none"
p="none"
radius="md"
items="center"
justify="center"
bg={checked ? 'toggle.checked.bg' : 'toggle.bg'}
cursor={disabled ? 'not-allowed' : 'pointer'}
width={width || '20px'}
height={height || '20px'}
opacity={disabled ? 0.6 : 1}
css={{
fontSize: '14px',
transition: 'background-color .15s ease-in-out',
}}
>
{checked && <Icon icon="check" fg="toggle.checked.fg" />}
</Flex>
</Box>
</span>
<Box as="label" display="inline-block" id={id} className={className}>
<input
type="checkbox"
checked={isChecked || false}
disabled={disabled}
onChange={handleChange}
style={{ position: 'absolute', clip: 'rect(1px, 1px, 1px, 1px)' }}
/>
<Flex
as="span"
display="block"
m="none"
p="none"
radius="md"
items="center"
justify="center"
bg={isChecked ? 'toggle.checked.bg' : 'toggle.bg'}
cursor={disabled ? 'not-allowed' : 'pointer'}
width={width || '20px'}
height={height || '20px'}
opacity={disabled ? 0.6 : 1}
css={{
fontSize: '14px',
transition: 'background-color .15s ease-in-out',
}}
>
{isChecked && <Icon icon="check" fg="toggle.checked.fg" />}
</Flex>
</Box>
);
})``;
};

export const Checkbox = styled<ICheckboxProps>(BasicCheckbox as any)``;
41 changes: 34 additions & 7 deletions src/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import noop = require('lodash/noop');
import * as React from 'react';
import AutosizeInput from 'react-input-autosize';

Expand All @@ -7,16 +8,41 @@ import { styled } from './utils';
export interface IInputProps extends ITextProps {
type?: string;
autosize?: boolean;
as?: any;
value?: string | number;
onChange?: (value?: string | number) => void;
}

const StyledAutosizeInput = ({ autosize, className, ...rest }: IInputProps) => (
<AutosizeInput inputClassName={className} {...rest} />
);
export interface IInputState {
value?: string | number;
}

export const BasicInput = (props: IInputProps) => {
const { autosize, className, onChange = noop, ...rest } = props;

const [value, setValue] = React.useState(props.value || '');
const internalValue = props.hasOwnProperty('value') ? props.value : value;

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
onChange(event.target.value);
};

if (autosize) {
return (
<AutosizeInput
inputClassName={className}
placeholderIsMinWidth={true}
{...rest}
value={internalValue}
onChange={handleChange}
/>
);
}

return React.createElement('input', { className, ...rest, value: internalValue, onChange: handleChange });
};

export const Input = styled<IInputProps>(Text as any).attrs({
as: ({ autosize }: IInputProps) => (autosize ? StyledAutosizeInput : 'input'),
})(
export const Input = styled<IInputProps, 'input'>(Text as any)(
{
// @ts-ignore
':focus': {
Expand All @@ -34,6 +60,7 @@ export const Input = styled<IInputProps>(Text as any).attrs({
);

Input.defaultProps = {
as: BasicInput,
px: 'md',
py: 'sm',
border: 'xs',
Expand Down
31 changes: 27 additions & 4 deletions src/Textarea.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import noop = require('lodash/noop');
import * as React from 'react';
import AutosizeTextarea from 'react-textarea-autosize';

import { ITextProps, Text } from './Text';
Expand All @@ -7,12 +9,32 @@ export interface ITextareaProps extends ITextProps {
autosize?: boolean;
minRows?: number;
maxRows?: number;
as?: any;

value?: string;
onChange?: (value: string) => void;
}

export const Textarea = styled<ITextareaProps>(Text as any).attrs({
as: ({ autosize }: ITextareaProps) => (autosize ? AutosizeTextarea : 'textarea'),
})(
export const BasicTextArea = (props: ITextareaProps) => {
const { autosize, minRows, maxRows, onChange = noop, ...rest } = props;

const [value, setValue] = React.useState(props.value || '');
const internalValue = props.hasOwnProperty('value') ? props.value : value;

const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setValue(event.target.value);
onChange(event.target.value);
};

if (autosize) {
return (
<AutosizeTextarea {...rest} minRows={minRows} maxRows={maxRows} value={internalValue} onChange={handleChange} />
);
}

return React.createElement('textarea', { ...rest, value: internalValue, onChange: handleChange });
};

export const Textarea = styled<ITextareaProps>(Text as any)(
{
// @ts-ignore
':focus': {
Expand All @@ -34,6 +56,7 @@ export const Textarea = styled<ITextareaProps>(Text as any).attrs({
);

Textarea.defaultProps = {
as: BasicTextArea,
px: 'md',
py: 'sm',
border: 'xs',
Expand Down
95 changes: 51 additions & 44 deletions src/Toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,70 @@
import noop = require('lodash/noop');
import * as React from 'react';

import { Box } from './Box';
import { Flex } from './Flex';
import { Icon } from './Icon';
import { Input } from './Input';
import { styled } from './utils';

export interface IToggleProps {
checked: boolean;
disabled?: boolean;
id?: string;
className?: string;
checked?: boolean;
disabled?: boolean;
width?: string;
height?: string;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
onChange?: (checked: boolean) => void;
}

export const Toggle = styled<IToggleProps>((props: IToggleProps) => {
const { id, className, checked, width, height, disabled, onChange } = props;
export const BasicToggle = (props: IToggleProps) => {
const { id, className, width, height, disabled, onChange = noop } = props;

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

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.checked);
onChange(event.target.checked);
};

return (
<span className={className}>
<Box display="inline-block">
<Input
type="checkbox"
id={id}
checked={checked}
disabled={disabled}
onChange={onChange}
position="absolute"
css={{ clip: 'rect(1px, 1px, 1px, 1px)' }}
/>
<Flex
as="span"
display="block"
m="none"
p="none"
radius="100px"
bg={checked ? 'toggle.checked.bg' : 'toggle.bg'}
cursor={disabled ? 'not-allowed' : 'pointer'}
width={width || '40px'}
height={height || '20px'}
opacity={disabled ? 0.6 : 1}
items="center"
<Box as="label" display="inline-block" id={id} className={className}>
<input
type="checkbox"
id={id}
checked={isChecked || false}
disabled={disabled}
onChange={handleChange}
style={{ position: 'absolute', clip: 'rect(1px, 1px, 1px, 1px)' }}
/>
<Flex
as="span"
display="block"
m="none"
p="none"
radius="100px"
bg={isChecked ? 'toggle.checked.bg' : 'toggle.bg'}
cursor={disabled ? 'not-allowed' : 'pointer'}
width={width || '40px'}
height={height || '20px'}
opacity={disabled ? 0.6 : 1}
items="center"
css={{
fontSize: '14px',
transition: 'background-color .15s ease-in-out',
}}
>
<Icon
icon="circle"
fg={isChecked ? 'toggle.checked.fg' : 'toggle.fg'}
css={{
fontSize: '14px',
transition: 'background-color .15s ease-in-out',
paddingLeft: isChecked ? '22px' : '4px',
transition: 'padding .15s ease-in-out, color .25s ease-in-out',
}}
>
<Icon
icon="circle"
fg={checked ? 'toggle.checked.fg' : 'toggle.fg'}
css={{
paddingLeft: checked ? '22px' : '4px',
transition: 'padding .15s ease-in-out, color .25s ease-in-out',
}}
/>
</Flex>
</Box>
</span>
/>
</Flex>
</Box>
);
})``;
};

export const Toggle = styled<IToggleProps>(BasicToggle as any)``;
Loading

0 comments on commit 038266b

Please sign in to comment.