mirror of
https://github.com/Steffo99/bluelib.git
synced 2024-12-22 19:44:21 +00:00
🚧 Continue working on inputs
This commit is contained in:
parent
632048601b
commit
04e014ad8e
10 changed files with 296 additions and 17 deletions
26
src/components/inputs/Area.stories.jsx
Normal file
26
src/components/inputs/Area.stories.jsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Decorators from "../../utils/Decorators"
|
||||||
|
import { Area } from "./Area"
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
component: Area,
|
||||||
|
title: "Inputs/Area",
|
||||||
|
decorators: [Decorators.Bluelib],
|
||||||
|
argTypes: {
|
||||||
|
customColor: {
|
||||||
|
control: {type: "color"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const Default = props => (
|
||||||
|
<Area {...props}/>
|
||||||
|
)
|
||||||
|
Default.args = {
|
||||||
|
placeholder: "Enter multiline text here\n\nThis component can be resized",
|
||||||
|
disabled: false,
|
||||||
|
required: false,
|
||||||
|
}
|
41
src/components/inputs/Area.tsx
Normal file
41
src/components/inputs/Area.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Types from "../../types"
|
||||||
|
import {BaseElement} from "../BaseElement"
|
||||||
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
|
interface AreaProps {
|
||||||
|
placeholder: string,
|
||||||
|
required?: boolean,
|
||||||
|
disabled?: boolean,
|
||||||
|
|
||||||
|
onChange: (contents: string) => boolean,
|
||||||
|
value?: string,
|
||||||
|
|
||||||
|
[props: string]: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function Area({onChange, ...props}: AreaProps): JSX.Element {
|
||||||
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-area")
|
||||||
|
|
||||||
|
const onChangeWrapper = React.useCallback(
|
||||||
|
|
||||||
|
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
||||||
|
const contents = event.target.value
|
||||||
|
|
||||||
|
if(onChange) {
|
||||||
|
return onChange(contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
[onChange]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseElement kind={"textarea"} onChange={onChangeWrapper} {...props}/>
|
||||||
|
)
|
||||||
|
}
|
|
@ -12,9 +12,6 @@ export default {
|
||||||
customColor: {
|
customColor: {
|
||||||
control: {type: "color"},
|
control: {type: "color"},
|
||||||
},
|
},
|
||||||
disabled: {
|
|
||||||
control: {type: "boolean"},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,28 +10,32 @@ interface FieldProps {
|
||||||
required?: boolean,
|
required?: boolean,
|
||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
|
|
||||||
onChange?: (event: React.FormEvent<HTMLInputElement>) => boolean,
|
onChange: (contents: string) => boolean,
|
||||||
onInput?: (event: React.FormEvent<HTMLInputElement>) => boolean,
|
value?: string,
|
||||||
onInvalid?: (event: React.FormEvent<HTMLInputElement>) => boolean,
|
|
||||||
onReset?: (event: React.FormEvent<HTMLInputElement>) => boolean,
|
|
||||||
onSubmit?: (event: React.FormEvent<HTMLInputElement>) => boolean,
|
|
||||||
|
|
||||||
[props: string]: any,
|
[props: string]: any,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function Field({onChange, onInput, onInvalid, ...props}: FieldProps): JSX.Element {
|
export function Field({onChange, value, ...props}: FieldProps): JSX.Element {
|
||||||
|
|
||||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-field")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-field")
|
||||||
|
|
||||||
// Propagate change events only if the element is enabled
|
const onChangeWrapper = React.useCallback(
|
||||||
if(!props.disabled) {
|
|
||||||
props.onChange = onChange
|
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
||||||
props.onInput = onInput
|
const contents = event.target.value
|
||||||
props.onInvalid = onInvalid
|
|
||||||
}
|
if(onChange) {
|
||||||
|
return onChange(contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
[onChange]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseElement kind={"input"} {...props}/>
|
<BaseElement kind={"input"} onChange={onChangeWrapper} {...props}/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
49
src/components/inputs/Multiselect.stories.jsx
Normal file
49
src/components/inputs/Multiselect.stories.jsx
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Decorators from "../../utils/Decorators"
|
||||||
|
import { Option } from "./Option"
|
||||||
|
import { OptionGroup } from "./OptionGroup"
|
||||||
|
import { Multiselect } from "./Multiselect"
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
component: Multiselect,
|
||||||
|
title: "Inputs/Multiselect",
|
||||||
|
decorators: [Decorators.Bluelib],
|
||||||
|
argTypes: {
|
||||||
|
customColor: {
|
||||||
|
control: {type: "color"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const Default = props => (
|
||||||
|
<Multiselect {...props}>
|
||||||
|
<Option label={"Yes"}/>
|
||||||
|
<Option label={"Maybe"}/>
|
||||||
|
<Option label={"No"}/>
|
||||||
|
</Multiselect>
|
||||||
|
)
|
||||||
|
Default.args = {
|
||||||
|
disabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const WithGroups = props => (
|
||||||
|
<Multiselect {...props}>
|
||||||
|
<OptionGroup label={"A"}>
|
||||||
|
<Option label={"Anchor"}/>
|
||||||
|
<Option label={"Angel"}/>
|
||||||
|
<Option label={"Anti-air"}/>
|
||||||
|
</OptionGroup>
|
||||||
|
<OptionGroup label={"B"}>
|
||||||
|
<Option label={"Banana"}/>
|
||||||
|
<Option label={"Boat"}/>
|
||||||
|
<Option label={"Bus"}/>
|
||||||
|
</OptionGroup>
|
||||||
|
</Multiselect>
|
||||||
|
)
|
||||||
|
WithGroups.args = {
|
||||||
|
disabled: false,
|
||||||
|
}
|
24
src/components/inputs/Multiselect.tsx
Normal file
24
src/components/inputs/Multiselect.tsx
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Types from "../../types"
|
||||||
|
import {BaseElement} from "../BaseElement"
|
||||||
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
|
interface MultiselectProps {
|
||||||
|
disabled?: boolean,
|
||||||
|
|
||||||
|
onChange?: (event: React.FormEvent<HTMLInputElement>) => boolean,
|
||||||
|
|
||||||
|
[props: string]: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function Multiselect({...props}: MultiselectProps): JSX.Element {
|
||||||
|
|
||||||
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-multiselect")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseElement kind={"select"} multiple={true} {...props}/>
|
||||||
|
)
|
||||||
|
}
|
23
src/components/inputs/Option.tsx
Normal file
23
src/components/inputs/Option.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Types from "../../types"
|
||||||
|
import {BaseElement} from "../BaseElement"
|
||||||
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
|
interface OptionProps {
|
||||||
|
label: string,
|
||||||
|
|
||||||
|
[props: string]: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function Option({label, ...props}: OptionProps): JSX.Element {
|
||||||
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input-option")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseElement kind={"option"} {...props}>
|
||||||
|
{label}
|
||||||
|
</BaseElement>
|
||||||
|
)
|
||||||
|
}
|
22
src/components/inputs/OptionGroup.tsx
Normal file
22
src/components/inputs/OptionGroup.tsx
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Types from "../../types"
|
||||||
|
import {BaseElement} from "../BaseElement"
|
||||||
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
|
interface OptionGroupProps {
|
||||||
|
label: string,
|
||||||
|
|
||||||
|
[props: string]: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function OptionGroup({...props}: OptionGroupProps): JSX.Element {
|
||||||
|
|
||||||
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input-optgroup")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseElement kind={"optgroup"} {...props}/>
|
||||||
|
)
|
||||||
|
}
|
50
src/components/inputs/Select.stories.jsx
Normal file
50
src/components/inputs/Select.stories.jsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Decorators from "../../utils/Decorators"
|
||||||
|
import { Select } from "./Select"
|
||||||
|
import { Option } from "./Option"
|
||||||
|
import { OptionGroup } from "./OptionGroup"
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
component: Select,
|
||||||
|
title: "Inputs/Select",
|
||||||
|
decorators: [Decorators.Bluelib],
|
||||||
|
argTypes: {
|
||||||
|
customColor: {
|
||||||
|
control: {type: "color"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const Default = props => (
|
||||||
|
<Select {...props}>
|
||||||
|
<Option label={"Yes"}/>
|
||||||
|
<Option label={"Maybe"}/>
|
||||||
|
<Option label={"No"}/>
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
Default.args = {
|
||||||
|
disabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const WithGroups = props => (
|
||||||
|
<Select {...props}>
|
||||||
|
<Option label={"Ungrouped"}/>
|
||||||
|
<OptionGroup label={"A"}>
|
||||||
|
<Option label={"Anchor"}/>
|
||||||
|
<Option label={"Angel"}/>
|
||||||
|
<Option label={"Anti-air"}/>
|
||||||
|
</OptionGroup>
|
||||||
|
<OptionGroup label={"B"}>
|
||||||
|
<Option label={"Banana"}/>
|
||||||
|
<Option label={"Boat"}/>
|
||||||
|
<Option label={"Bus"}/>
|
||||||
|
</OptionGroup>
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
|
WithGroups.args = {
|
||||||
|
disabled: false,
|
||||||
|
}
|
43
src/components/inputs/Select.tsx
Normal file
43
src/components/inputs/Select.tsx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import * as React from "react"
|
||||||
|
import * as ReactDOM from "react-dom"
|
||||||
|
import * as Types from "../../types"
|
||||||
|
import {BaseElement} from "../BaseElement"
|
||||||
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
|
interface SelectProps {
|
||||||
|
disabled?: boolean,
|
||||||
|
|
||||||
|
onChange?: (contents: string) => boolean,
|
||||||
|
value?: string,
|
||||||
|
|
||||||
|
children: React.ReactNode,
|
||||||
|
|
||||||
|
[props: string]: any,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function Select({onChange, children, ...props}: SelectProps): JSX.Element {
|
||||||
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-select")
|
||||||
|
|
||||||
|
const onChangeWrapper = React.useCallback(
|
||||||
|
|
||||||
|
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
||||||
|
const contents = event.target.value
|
||||||
|
|
||||||
|
if(onChange) {
|
||||||
|
return onChange(contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
[onChange]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseElement kind={"select"} multiple={false} {...props}>
|
||||||
|
// TODO
|
||||||
|
</BaseElement>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in a new issue