diff options
Diffstat (limited to 'src/settings/components/ui')
| -rw-r--r-- | src/settings/components/ui/AddButton.scss | 13 | ||||
| -rw-r--r-- | src/settings/components/ui/AddButton.tsx | 31 | ||||
| -rw-r--r-- | src/settings/components/ui/DeleteButton.scss | 13 | ||||
| -rw-r--r-- | src/settings/components/ui/DeleteButton.tsx | 30 | ||||
| -rw-r--r-- | src/settings/components/ui/Input.scss | 29 | ||||
| -rw-r--r-- | src/settings/components/ui/Input.tsx | 89 | ||||
| -rw-r--r-- | src/settings/components/ui/Radio.tsx | 33 | ||||
| -rw-r--r-- | src/settings/components/ui/Text.tsx | 54 | ||||
| -rw-r--r-- | src/settings/components/ui/TextArea.tsx | 56 | 
9 files changed, 178 insertions, 170 deletions
| diff --git a/src/settings/components/ui/AddButton.scss b/src/settings/components/ui/AddButton.scss deleted file mode 100644 index beb5688..0000000 --- a/src/settings/components/ui/AddButton.scss +++ /dev/null @@ -1,13 +0,0 @@ -.ui-add-button { -  border: none; -  padding: 4; -  display: inline; -  background: none; -  font-weight: bold; -  color: green; -  cursor: pointer; - -  &:hover { -    color: darkgreen; -  } -} diff --git a/src/settings/components/ui/AddButton.tsx b/src/settings/components/ui/AddButton.tsx index c15a732..8cf4300 100644 --- a/src/settings/components/ui/AddButton.tsx +++ b/src/settings/components/ui/AddButton.tsx @@ -1,19 +1,24 @@ -import "./AddButton.scss";  import React from "react"; +import styled from "styled-components"; -type Props = React.AllHTMLAttributes<HTMLInputElement>; +const Button = styled.input` +  border: none; +  padding: 4; +  display: inline; +  background: none; +  font-weight: bold; +  color: green; +  cursor: pointer; -class AddButton extends React.Component<Props> { -  render() { -    return ( -      <input -        className="ui-add-button" -        type="button" -        value="✚" -        {...this.props} -      /> -    ); +  &:hover { +    color: darkgreen;    } -} +`; + +type Props = React.InputHTMLAttributes<HTMLInputElement>; + +const AddButton: React.FC<Props> = (props) => ( +  <Button type="button" value="✚" {...props} /> +);  export default AddButton; diff --git a/src/settings/components/ui/DeleteButton.scss b/src/settings/components/ui/DeleteButton.scss deleted file mode 100644 index 5932a72..0000000 --- a/src/settings/components/ui/DeleteButton.scss +++ /dev/null @@ -1,13 +0,0 @@ - -.ui-delete-button { -  border: none; -  padding: 4; -  display: inline; -  background: none; -  color: red; -  cursor: pointer; - -  &:hover { -    color: darkred; -  } -} diff --git a/src/settings/components/ui/DeleteButton.tsx b/src/settings/components/ui/DeleteButton.tsx index df8976e..ce0183b 100644 --- a/src/settings/components/ui/DeleteButton.tsx +++ b/src/settings/components/ui/DeleteButton.tsx @@ -1,19 +1,23 @@ -import "./DeleteButton.scss";  import React from "react"; +import styled from "styled-components"; -type Props = React.AllHTMLAttributes<HTMLInputElement>; +const Button = styled.input` +  border: none; +  padding: 4; +  display: inline; +  background: none; +  color: red; +  cursor: pointer; -class DeleteButton extends React.Component<Props> { -  render() { -    return ( -      <input -        className="ui-delete-button" -        type="button" -        value="✖" -        {...this.props} -      /> -    ); +  &:hover { +    color: darkred;    } -} +`; + +type Props = React.InputHTMLAttributes<HTMLInputElement>; + +const DeleteButton: React.FC<Props> = (props) => ( +  <Button type="button" value="✖" {...props} /> +);  export default DeleteButton; diff --git a/src/settings/components/ui/Input.scss b/src/settings/components/ui/Input.scss deleted file mode 100644 index ad4daf8..0000000 --- a/src/settings/components/ui/Input.scss +++ /dev/null @@ -1,29 +0,0 @@ -.settings-ui-input { -  page-break-inside: avoid; - -  * { -    page-break-inside: avoid; -  } - -  label { -    font-weight: bold; -    min-width: 14rem; -    display: inline-block; -  } - -  input[type='text'] { -    padding: 4px; -    width: 8rem; -  } - -  input.input-crror, -  textarea.input-error { -    box-shadow: 0 0 2px red; -  } - -  &-error { -    font-weight: bold; -    color: red; -    min-height: 1.5em; -  } -} diff --git a/src/settings/components/ui/Input.tsx b/src/settings/components/ui/Input.tsx deleted file mode 100644 index 0e24277..0000000 --- a/src/settings/components/ui/Input.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from "react"; -import "./Input.scss"; - -interface Props extends React.AllHTMLAttributes<HTMLElement> { -  name: string; -  type: string; -  error?: string; -  label: string; -  value: string; -  onValueChange?: (name: string, value: string) => void; -  onBlur?: (e: React.FocusEvent<Element>) => void; -} - -class Input extends React.Component<Props> { -  renderText(props: Props) { -    const inputClassName = props.error ? "input-error" : ""; -    const pp = { ...props }; -    delete pp.onValueChange; -    return ( -      <div className="settings-ui-input"> -        <label htmlFor={props.id}>{props.label}</label> -        <input -          className={inputClassName} -          onChange={this.bindOnChange.bind(this)} -          {...pp} -        /> -      </div> -    ); -  } - -  renderRadio(props: Props) { -    const inputClassName = props.error ? "input-error" : ""; -    const pp = { ...props }; -    delete pp.onValueChange; -    return ( -      <div className="settings-ui-input"> -        <label> -          <input -            className={inputClassName} -            onChange={this.bindOnChange.bind(this)} -            {...pp} -          /> -          {props.label} -        </label> -      </div> -    ); -  } - -  renderTextArea(props: Props) { -    const inputClassName = props.error ? "input-error" : ""; -    const pp = { ...props }; -    delete pp.onValueChange; -    return ( -      <div className="settings-ui-input"> -        <label htmlFor={props.id}>{props.label}</label> -        <textarea -          className={inputClassName} -          onChange={this.bindOnChange.bind(this)} -          {...pp} -        /> -        <p className="settings-ui-input-error">{this.props.error}</p> -      </div> -    ); -  } - -  render() { -    const { type } = this.props; - -    switch (this.props.type) { -      case "text": -        return this.renderText(this.props); -      case "radio": -        return this.renderRadio(this.props); -      case "textarea": -        return this.renderTextArea(this.props); -      default: -        console.warn(`Unsupported input type ${type}`); -    } -    return null; -  } - -  bindOnChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) { -    if (this.props.onValueChange) { -      this.props.onValueChange(e.target.name, e.target.value); -    } -  } -} - -export default Input; diff --git a/src/settings/components/ui/Radio.tsx b/src/settings/components/ui/Radio.tsx new file mode 100644 index 0000000..c0d4dd9 --- /dev/null +++ b/src/settings/components/ui/Radio.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import styled from "styled-components"; + +const Container = styled.div` +  font-family: system-ui; +`; + +interface Props extends React.InputHTMLAttributes<HTMLInputElement> { +  label: string; +  onValueChange?: (name: string, value: string) => void; +} + +const Radio: React.FC<Props> = (props) => { +  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { +    if (props.onValueChange) { +      props.onValueChange(e.target.name, e.target.value); +    } +  }; + +  const pp = { ...props }; +  delete pp.onValueChange; + +  return ( +    <Container> +      <label htmlFor={props.id}> +        <input type="radio" onChange={onChange} {...pp} /> +        {props.label} +      </label> +    </Container> +  ); +}; + +export default Radio; diff --git a/src/settings/components/ui/Text.tsx b/src/settings/components/ui/Text.tsx new file mode 100644 index 0000000..700b08a --- /dev/null +++ b/src/settings/components/ui/Text.tsx @@ -0,0 +1,54 @@ +import React from "react"; +import styled from "styled-components"; + +const Container = styled.div` +  page-break-inside: avoid; +`; + +const Input = styled.input<{ hasError: boolean }>` +  padding: 4px; +  width: 8rem; +  box-shadow: ${({ hasError }) => (hasError ? "0 0 2px red" : "none")}; +`; + +const Label = styled.label` +  font-weight: bold; +  min-width: 14rem; +  display: inline-block; +`; + +interface Props extends React.HTMLAttributes<HTMLElement> { +  name: string; +  error?: string; +  label: string; +  value: string; +  onValueChange?: (name: string, value: string) => void; +} + +const Text: React.FC<Props> = (props) => { +  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => { +    if (props.onValueChange) { +      props.onValueChange(e.target.name, e.target.value); +    } +  }; + +  const pp = { ...props }; +  delete pp.onValueChange; + +  return ( +    <Container> +      <Label> +        {props.label} +        <br /> +        <Input +          type="text" +          hasError={props.error !== undefined} +          onChange={onChange} +          {...pp} +        /> +      </Label> +    </Container> +  ); +}; + +export default Text; diff --git a/src/settings/components/ui/TextArea.tsx b/src/settings/components/ui/TextArea.tsx new file mode 100644 index 0000000..9dcd5be --- /dev/null +++ b/src/settings/components/ui/TextArea.tsx @@ -0,0 +1,56 @@ +import React from "react"; +import styled from "styled-components"; + +const Container = styled.div` +  page-break-inside: avoid; +`; + +const Label = styled.label` +  font-weight: bold; +  min-width: 14rem; +  display: inline-block; +`; + +const ErrorableTextArea = styled.textarea<{ hasError: boolean }>` +  box-shadow: ${({ hasError }) => (hasError ? "0 0 2px red" : "none")}; +  font-family: monospace; +  font-family: monospace; +  width: 100%; +  min-height: 64ex; +  resize: vertical; +`; + +const ErrorMessage = styled.p` +  font-weight: bold; +  color: red; +  min-height: 1.5em; +`; + +interface Props extends React.TextareaHTMLAttributes<HTMLTextAreaElement> { +  error?: string; +  label: string; +  onValueChange?: (name: string, value: string) => void; +} + +const TextArea: React.FC<Props> = (props) => { +  const onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { +    if (props.onValueChange) { +      props.onValueChange(e.target.name, e.target.value); +    } +  }; + +  const hasError = typeof props.error !== "undefined" && props.error !== ""; +  const pp = { ...props }; +  delete pp.onValueChange; +  return ( +    <Container> +      <Label htmlFor={props.id}>{props.label}</Label> +      <ErrorableTextArea hasError={hasError} onChange={onChange} {...pp} /> +      {hasError ? ( +        <ErrorMessage role="alert">{props.error}</ErrorMessage> +      ) : null} +    </Container> +  ); +}; + +export default TextArea; | 
