Skip to content

Commit

Permalink
Addon-knobs: migrate components
Browse files Browse the repository at this point in the history
  • Loading branch information
emilio-martinez committed Jun 25, 2019
1 parent 45d9c55 commit 8535624
Show file tree
Hide file tree
Showing 13 changed files with 555 additions and 258 deletions.
73 changes: 42 additions & 31 deletions addons/knobs/src/components/types/Array.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,61 @@
import PropTypes from 'prop-types';
import React from 'react';
import React, { Component, WeakValidationMap } from 'react';

import { Form } from '@storybook/components';

function formatArray(value, separator) {
type ArrayTypeKnobValue = string[];

interface ArrayTypeProps {
knob: {
name: string;
value: ArrayTypeKnobValue;
separator: string;
};
onChange: (value: ArrayTypeKnobValue) => ArrayTypeKnobValue;
}

function formatArray(value: string, separator: string) {
if (value === '') {
return [];
}
return value.split(separator);
}

class ArrayType extends React.Component {
shouldComponentUpdate(nextProps) {
export default class ArrayType extends Component<ArrayTypeProps> {
static defaultProps: Partial<ArrayTypeProps> = {
knob: {} as any,
onChange: (value: ArrayTypeKnobValue) => value,
};

static propTypes: WeakValidationMap<ArrayTypeProps> = {
// TODO: remove `any` once DefinitelyTyped/DefinitelyTyped#31280 has been resolved
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.array,
separator: PropTypes.string,
}) as any,
onChange: PropTypes.func,
};

static serialize = (value: ArrayTypeKnobValue) => value;

static deserialize = (value: ArrayTypeKnobValue) => {
if (Array.isArray(value)) return value;

return Object.keys(value)
.sort()
.reduce((array, key) => [...array, value[key]], []);
};

shouldComponentUpdate(nextProps: Readonly<ArrayTypeProps>) {
const { knob } = this.props;

return nextProps.knob.value !== knob.value;
}

handleChange = e => {
handleChange = (e: Event) => {
const { knob, onChange } = this.props;
const { value } = e.target;
const { value } = e.target as HTMLTextAreaElement;
const newVal = formatArray(value, knob.separator);

onChange(newVal);
Expand All @@ -40,28 +76,3 @@ class ArrayType extends React.Component {
);
}
}

ArrayType.defaultProps = {
knob: {},
onChange: value => value,
};

ArrayType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.array,
separator: PropTypes.string,
}),
onChange: PropTypes.func,
};

ArrayType.serialize = value => value;
ArrayType.deserialize = value => {
if (Array.isArray(value)) return value;

return Object.keys(value)
.sort()
.reduce((array, key) => [...array, value[key]], []);
};

export default ArrayType;
30 changes: 24 additions & 6 deletions addons/knobs/src/components/types/Boolean.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import PropTypes from 'prop-types';
import React from 'react';
import React, { FunctionComponent } from 'react';

import { styled } from '@storybook/theming';

type BooleanTypeKnobValue = boolean;

interface BooleanTypeProps {
knob: {
name: string;
value: BooleanTypeKnobValue;
separator: string;
};
onChange: (value: BooleanTypeKnobValue) => BooleanTypeKnobValue;
}

const Input = styled.input({
display: 'table-cell',
boxSizing: 'border-box',
Expand All @@ -14,7 +25,13 @@ const Input = styled.input({
color: '#555',
});

const BooleanType = ({ knob, onChange }) => (
const serialize = (value: BooleanTypeKnobValue): string | null => (value ? String(value) : null);
const deserialize = (value: string | null) => value === 'true';

const BooleanType: FunctionComponent<BooleanTypeProps> & {
serialize: typeof serialize;
deserialize: typeof deserialize;
} = ({ knob, onChange }) => (
<Input
id={knob.name}
name={knob.name}
Expand All @@ -25,19 +42,20 @@ const BooleanType = ({ knob, onChange }) => (
);

BooleanType.defaultProps = {
knob: {},
knob: {} as any,
onChange: value => value,
};

BooleanType.propTypes = {
// TODO: remove `any` once DefinitelyTyped/DefinitelyTyped#31280 has been resolved
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.bool,
}),
}) as any,
onChange: PropTypes.func,
};

BooleanType.serialize = value => (value ? String(value) : null);
BooleanType.deserialize = value => value === 'true';
BooleanType.serialize = serialize;
BooleanType.deserialize = deserialize;

export default BooleanType;
30 changes: 25 additions & 5 deletions addons/knobs/src/components/types/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
import PropTypes from 'prop-types';
import React from 'react';
import React, { FunctionComponent, Validator } from 'react';

import { Form } from '@storybook/components';

const ButtonType = ({ knob, onClick }) => (
interface ButtonTypeKnobProp {
name: string;
}

interface ButtonTypeProps {
knob: ButtonTypeKnobProp;
onClick: (knob: ButtonTypeKnobProp) => any;
}

const serialize = (): undefined => undefined;
const deserialize = (): undefined => undefined;

const ButtonType: FunctionComponent<ButtonTypeProps> & {
serialize: typeof serialize;
deserialize: typeof deserialize;
} = ({ knob, onClick }) => (
<Form.Button type="button" name={knob.name} onClick={() => onClick(knob)}>
{knob.name}
</Form.Button>
);

ButtonType.defaultProps = {
knob: {} as any,
};

ButtonType.propTypes = {
// TODO: remove `any` once DefinitelyTyped/DefinitelyTyped#31280 has been resolved
knob: PropTypes.shape({
name: PropTypes.string,
}).isRequired,
}).isRequired as Validator<any>,
onClick: PropTypes.func.isRequired,
};

ButtonType.serialize = () => undefined;
ButtonType.deserialize = () => undefined;
ButtonType.serialize = serialize;
ButtonType.deserialize = deserialize;

export default ButtonType;
83 changes: 54 additions & 29 deletions addons/knobs/src/components/types/Checkboxes.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
import React, { Component } from 'react';
import React, { Component, ChangeEvent, WeakValidationMap } from 'react';
import PropTypes from 'prop-types';
import { styled } from '@storybook/theming';

const CheckboxesWrapper = styled.div(({ isInline }) =>
type CheckboxesTypeKnobValue = string[];

interface CheckboxesWrapperProps {
isInline: boolean;
}

interface CheckboxesTypeKnobProp {
name: string;
value: CheckboxesTypeKnobValue;
defaultValue: CheckboxesTypeKnobValue;
options: {
[key: string]: string;
};
}

interface CheckboxesTypeProps {
knob: CheckboxesTypeKnobProp;
isInline: boolean;
onChange: (value: CheckboxesTypeKnobValue) => CheckboxesTypeKnobValue;
}

interface CheckboxesTypeState {
values: CheckboxesTypeKnobValue;
}

const CheckboxesWrapper = styled.div(({ isInline }: CheckboxesWrapperProps) =>
isInline
? {
display: 'flex',
Expand All @@ -27,8 +52,29 @@ const CheckboxLabel = styled.label({
display: 'inline-block',
});

class CheckboxesType extends Component {
constructor(props) {
export default class CheckboxesType extends Component<CheckboxesTypeProps, CheckboxesTypeState> {
static defaultProps: CheckboxesTypeProps = {
knob: {} as any,
onChange: value => value,
isInline: false,
};

static propTypes: WeakValidationMap<CheckboxesTypeProps> = {
// TODO: remove `any` once DefinitelyTyped/DefinitelyTyped#31280 has been resolved
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.array,
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
}) as any,
onChange: PropTypes.func,
isInline: PropTypes.bool,
};

static serialize = (value: CheckboxesTypeKnobValue) => value;

static deserialize = (value: CheckboxesTypeKnobValue) => value;

constructor(props: CheckboxesTypeProps) {
super(props);
const { knob } = props;

Expand All @@ -37,9 +83,9 @@ class CheckboxesType extends Component {
};
}

handleChange = e => {
handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const { onChange } = this.props;
const currentValue = e.target.value;
const currentValue = (e.target as HTMLInputElement).value;
const { values } = this.state;

if (values.includes(currentValue)) {
Expand All @@ -53,10 +99,10 @@ class CheckboxesType extends Component {
onChange(values);
};

renderCheckboxList = ({ options }) =>
renderCheckboxList = ({ options }: CheckboxesTypeKnobProp) =>
Object.keys(options).map(key => this.renderCheckbox(key, options[key]));

renderCheckbox = (label, value) => {
renderCheckbox = (label: string, value: string) => {
const { knob } = this.props;
const { name } = knob;
const id = `${name}-${value}`;
Expand Down Expand Up @@ -87,24 +133,3 @@ class CheckboxesType extends Component {
);
}
}

CheckboxesType.defaultProps = {
knob: {},
onChange: value => value,
isInline: false,
};

CheckboxesType.propTypes = {
knob: PropTypes.shape({
name: PropTypes.string,
value: PropTypes.array,
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
}),
onChange: PropTypes.func,
isInline: PropTypes.bool,
};

CheckboxesType.serialize = value => value;
CheckboxesType.deserialize = value => value;

export default CheckboxesType;
Loading

0 comments on commit 8535624

Please sign in to comment.