mirror of
https://github.com/Steffo99/bluelib.git
synced 2024-12-22 19:44:21 +00:00
✨ Implement (properly) inputs and forms (#1)
* 🔧 Use `<label>` in the `ThreeRadios` and `ThreeCheckboxes` stories * 🔧 Make `onChange` return void, as React does not support implicit preventDefault https://reactjs.org/docs/handling-events.html * 🚧 Some work on forms * 💥 A huge non-atomic commit * 💥 Another huge non-atomic commit * 💥 The final non-atomic commit * 💥 Just kidding, have another * 🚧 A bit more * 🚧 A bot more * ✨ Add `onSimpleChange` events * 🚧 More work on inputs * ✨ Finish `FormRadioGroup` * ✨ Finish `FormCheckboxGroup` * ✨ Finish `Form` * 💥 idk anymore * ✨ Add `Button` input * ✨ Add `FormRow` to forms * 🔨 Fix storybook preview.js * 🔧 Prevent button from submitting a form * 📔 Fix a bit the Form story * 💥 Tweak forms a bit more
This commit is contained in:
parent
6355ddee36
commit
8b7c57aae6
92 changed files with 1644 additions and 753 deletions
|
@ -2,7 +2,43 @@ import { Bluelib } from "../src/components/Bluelib"
|
|||
|
||||
|
||||
export const parameters = {
|
||||
actions: {
|
||||
argTypesRegex: "^on[A-Z][a-z]*$"
|
||||
argTypes: {
|
||||
bluelibClassNames: {
|
||||
control: {type: "string"},
|
||||
description: "Additional Bluelib classNames to be appended to the element's classNames",
|
||||
table: {category: "Global props"}
|
||||
},
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
description: "Apply a Bluelib custom color to the element",
|
||||
table: {category: "Global props"}
|
||||
},
|
||||
disabled: {
|
||||
control: {type: "boolean"},
|
||||
description: "Apply the disabled status to an element",
|
||||
table: {category: "Global props"}
|
||||
}
|
||||
},
|
||||
options: {
|
||||
storySort: {
|
||||
order: [
|
||||
"Core",
|
||||
"Layouts",
|
||||
"Panels",
|
||||
"Chapters",
|
||||
"Separators",
|
||||
"Images",
|
||||
"Tables",
|
||||
"Lists",
|
||||
"Status",
|
||||
"Inputs",
|
||||
"Forms",
|
||||
"Common",
|
||||
"Annotations",
|
||||
"Semantics",
|
||||
"Colors",
|
||||
"Internals",
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
|
@ -13,12 +13,14 @@
|
|||
"@types/node": "^12.0.0",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/uuid": "^8.3.1",
|
||||
"classnames": "^2.3.1",
|
||||
"color": "https://github.com/Steffo99/color",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-scripts": "4.0.3",
|
||||
"typescript": "^4.1.2",
|
||||
"uuid": "^8.3.2",
|
||||
"web-vitals": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0fe4c9e477a681031c4d62fd9a7c39e94befa849
|
||||
Subproject commit 48722dcbfa0d6e9e1e5fe3bcb84b0be102d5db38
|
|
@ -1,42 +1,23 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../utils/Decorators"
|
||||
import { BaseElement } from "./BaseElement"
|
||||
import { BaseElement as BaseElementComponent } from "./BaseElement"
|
||||
import { Bluelib } from "./Bluelib"
|
||||
|
||||
|
||||
export default {
|
||||
component: BaseElement,
|
||||
title: "Bluelib/BaseElement",
|
||||
component: BaseElementComponent,
|
||||
title: "Internals/Base Element",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<BaseElement kind={"div"} {...props}>
|
||||
export const BaseElement = props => (
|
||||
<BaseElementComponent kind={"div"} {...props}>
|
||||
This is a text node child.
|
||||
</BaseElement>
|
||||
</BaseElementComponent>
|
||||
)
|
||||
Default.args = {
|
||||
BaseElement.args = {
|
||||
kind: "div",
|
||||
disabled: false,
|
||||
}
|
||||
|
||||
|
||||
export const CustomColor = Default.bind({})
|
||||
CustomColor.args = {
|
||||
...Default.args,
|
||||
customColor: "#ff7f00",
|
||||
}
|
||||
|
||||
|
||||
export const Disabled = Default.bind({})
|
||||
Disabled.args = {
|
||||
...Default.args,
|
||||
disabled: true,
|
||||
}
|
|
@ -7,29 +7,28 @@ import Color from "color"
|
|||
import mergeClassNames, {Argument as ClassNamesArgument} from "classnames"
|
||||
|
||||
|
||||
export interface BaseElementProps {
|
||||
kind: Types.ComponentKind,
|
||||
export interface BaseElementProps extends React.HTMLProps<any> {
|
||||
kind: string,
|
||||
bluelibClassNames?: Types.ClassNames,
|
||||
customColor?: typeof Color,
|
||||
disabled?: boolean,
|
||||
|
||||
[props: string]: any,
|
||||
customColor?: typeof Color,
|
||||
}
|
||||
|
||||
|
||||
export function BaseElement({kind, bluelibClassNames, customColor, ...props}: BaseElementProps): JSX.Element {
|
||||
export function BaseElement({kind = "div", bluelibClassNames, disabled = false, customColor, ...props}: BaseElementProps): JSX.Element {
|
||||
// Set the Bluelib color
|
||||
if(customColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("color", customColor)}
|
||||
if(customColor) {
|
||||
props.style = {...props.style, ...Colors.colorToBluelibStyle("color", customColor)}
|
||||
}
|
||||
|
||||
// Possibly disable the element
|
||||
if(props.disabled) bluelibClassNames = mergeClassNames(bluelibClassNames, "status-disabled")
|
||||
bluelibClassNames = mergeClassNames(bluelibClassNames, disabled ? "status-disabled" : "")
|
||||
// @ts-ignore
|
||||
props.disabled = disabled
|
||||
|
||||
// Map regular class names to module class names
|
||||
bluelibClassNames = BluelibMapper.rootToModule(bluelibClassNames)
|
||||
props.className = mergeClassNames(props.className, bluelibClassNames)
|
||||
|
||||
// Dynamically determine the element kind
|
||||
const Kind = kind
|
||||
|
||||
return <Kind {...props}/>
|
||||
return React.createElement(kind, props)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import Color from "color"
|
|||
|
||||
export default {
|
||||
component: Bluelib,
|
||||
title: "Bluelib/Bluelib",
|
||||
title: "Core/Bluelib",
|
||||
decorators: [Decorators.Fill],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
|
|
|
@ -19,7 +19,7 @@ const BuiltinThemes = {
|
|||
}
|
||||
|
||||
|
||||
export interface BluelibProps {
|
||||
export interface BluelibProps extends Types.BluelibHTMLProps<HTMLDivElement> {
|
||||
theme: "paper" | "royalblue" | "hacker" | "sophon",
|
||||
|
||||
backgroundColor?: typeof Color,
|
||||
|
@ -38,8 +38,6 @@ export interface BluelibProps {
|
|||
magentaColor?: typeof Color,
|
||||
grayColor?: typeof Color,
|
||||
polarity?: number,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,7 +79,10 @@ export function Bluelib({
|
|||
if(blueColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("blue", blueColor)}
|
||||
if(magentaColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("magenta", magentaColor)}
|
||||
if(grayColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("gray", grayColor)}
|
||||
if(polarity) props.style["--bluelib-polarity"] = polarity
|
||||
if(polarity) {
|
||||
// @ts-ignore
|
||||
props.style["--bluelib-polarity"] = polarity
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseElement
|
||||
|
|
|
@ -20,16 +20,14 @@ export default {
|
|||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
export const Basic = props => (
|
||||
<Chapter {...props}>
|
||||
<Box>First</Box>
|
||||
<Box>Second</Box>
|
||||
<Box>Third</Box>
|
||||
</Chapter>
|
||||
)
|
||||
Default.args = {
|
||||
disabled: false,
|
||||
}
|
||||
Basic.args = {}
|
||||
|
||||
|
||||
export const AutoWrap = props => (
|
||||
|
@ -46,14 +44,18 @@ export const AutoWrap = props => (
|
|||
<Box>Tenth</Box>
|
||||
<Box>Eleventh</Box>
|
||||
<Box>Twelfth</Box>
|
||||
<Box>Thirtheenth</Box>
|
||||
<Box>Fourtheenth</Box>
|
||||
<Box>Fiftheenth</Box>
|
||||
<Box>Thirteenth</Box>
|
||||
<Box>Fourteenth</Box>
|
||||
<Box>Fifteenth</Box>
|
||||
<Box>Sixteenth</Box>
|
||||
<Box>Seventeenth</Box>
|
||||
<Box>Eighteenth</Box>
|
||||
<Box>Ninteenth</Box>
|
||||
<Box>Ninteenth</Box>
|
||||
<Box>Twentieth</Box>
|
||||
</Chapter>
|
||||
)
|
||||
AutoWrap.args = {
|
||||
disabled: false,
|
||||
}
|
||||
AutoWrap.args = {}
|
||||
|
||||
|
||||
export const ForceWrap = props => (
|
||||
|
@ -65,6 +67,4 @@ export const ForceWrap = props => (
|
|||
<Box>Fourth</Box>
|
||||
</Chapter>
|
||||
)
|
||||
ForceWrap.args = {
|
||||
disabled: false,
|
||||
}
|
||||
ForceWrap.args = {}
|
||||
|
|
|
@ -3,11 +3,10 @@ import * as ReactDOM from "react-dom"
|
|||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {ChapterForceWrap} from "./ChapterForceWrap";
|
||||
|
||||
|
||||
interface ChapterProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
export interface ChapterProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function Chapter({...props}: ChapterProps): JSX.Element {
|
||||
|
@ -19,15 +18,4 @@ export function Chapter({...props}: ChapterProps): JSX.Element {
|
|||
}
|
||||
|
||||
|
||||
interface ChapterForceWrapProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
Chapter.ForceWrap = function({...props}: ChapterForceWrapProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "chapter-forcewrap")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
||||
Chapter.ForceWrap = ChapterForceWrap
|
17
src/components/chapters/ChapterForceWrap.tsx
Normal file
17
src/components/chapters/ChapterForceWrap.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface ChapterForceWrapProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function ChapterForceWrap({...props}: ChapterForceWrapProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "chapter-forcewrap")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
74
src/components/forms/Form.stories.jsx
Normal file
74
src/components/forms/Form.stories.jsx
Normal file
|
@ -0,0 +1,74 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Form as FormComponent } from "./Form"
|
||||
import { FormField } from "./FormField"
|
||||
import { FormArea } from "./FormArea"
|
||||
import { FormSelect } from "./FormSelect"
|
||||
import { Option } from "../inputs/Option"
|
||||
import { FormMultiselect } from "./FormMultiselect"
|
||||
import { FormRadioGroup } from "./FormRadioGroup"
|
||||
import { FormCheckboxGroup } from "./FormCheckboxGroup"
|
||||
import { FormRow } from "./FormRow"
|
||||
import { Button } from "../inputs/Button"
|
||||
import { Parenthesis } from "../panels/Parenthesis"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormComponent,
|
||||
subcomponents: {FormField, FormRow, FormArea, FormSelect, FormRadioGroup, FormCheckboxGroup, Parenthesis, Option, Button},
|
||||
title: "Forms/Form",
|
||||
decorators: [Decorators.Box, Decorators.Bluelib],
|
||||
}
|
||||
|
||||
|
||||
export const Form = props => (
|
||||
<FormComponent {...props}>
|
||||
<FormComponent.Field label={"Username"}/>
|
||||
<FormComponent.Field label={"Password"} type={"password"}/>
|
||||
<FormComponent.Row>
|
||||
<Parenthesis>Enter the details of your characters below.</Parenthesis>
|
||||
</FormComponent.Row>
|
||||
<FormComponent.Field label={"Name"}/>
|
||||
<FormComponent.Area label={"Backstory"}/>
|
||||
<FormComponent.Select label={"Gender"}>
|
||||
<FormComponent.Select.Option value={"Male"}/>
|
||||
<FormComponent.Select.Option value={"Female"}/>
|
||||
<FormComponent.Select.Option value={"Non-binary"}/>
|
||||
</FormComponent.Select>
|
||||
<FormComponent.Field label={"Level"} type={"number"} min={1} max={20}/>
|
||||
<FormComponent.Radios label={"Alignment"} row={true} options={[
|
||||
"Lawful good",
|
||||
"Lawful neutral",
|
||||
"Lawful evil",
|
||||
"Neutral good",
|
||||
"Neutral",
|
||||
"Neutral evil",
|
||||
"Chaotic good",
|
||||
"Chaotic neutral",
|
||||
"Chaotic evil",
|
||||
"Other",
|
||||
]}/>
|
||||
<FormComponent.Checkboxes label={"Classes"} row={false} options={[
|
||||
"Artificer",
|
||||
"Barbarian",
|
||||
"Bard",
|
||||
"Cleric",
|
||||
"Druid",
|
||||
"Fighter",
|
||||
"Monk",
|
||||
"Paladin",
|
||||
"Ranger",
|
||||
"Rogue",
|
||||
"Sorcerer",
|
||||
"Warlock",
|
||||
"Wizard",
|
||||
]}/>
|
||||
<FormComponent.Row>
|
||||
<FormComponent.Button>Throw fireball</FormComponent.Button>
|
||||
<FormComponent.Button>Shoot a magic missile</FormComponent.Button>
|
||||
<FormComponent.Button>Save character</FormComponent.Button>
|
||||
</FormComponent.Row>
|
||||
</FormComponent>
|
||||
)
|
||||
Form.args = {}
|
44
src/components/forms/Form.tsx
Normal file
44
src/components/forms/Form.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormArea} from "./FormArea";
|
||||
import {FormCheckboxGroup} from "./FormCheckboxGroup";
|
||||
import {FormField} from "./FormField";
|
||||
import {FormMultiselect} from "./FormMultiselect";
|
||||
import {FormRadioGroup} from "./FormRadioGroup";
|
||||
import {FormRow} from "./FormRow";
|
||||
import {FormSelect} from "./FormSelect";
|
||||
import {FormLabel} from "./FormLabel";
|
||||
import {FormPair} from "./FormPair";
|
||||
import {FormGroup} from "./FormGroup";
|
||||
import {Button} from "../inputs/Button";
|
||||
|
||||
|
||||
export interface FormProps extends Types.BluelibHTMLProps<HTMLFormElement> {}
|
||||
|
||||
|
||||
export function Form({...props}: FormProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"form"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Form.Area = FormArea
|
||||
Form.Checkboxes = FormCheckboxGroup
|
||||
Form.Field = FormField
|
||||
Form.Multiselect = FormMultiselect
|
||||
Form.Radios = FormRadioGroup
|
||||
Form.Row = FormRow
|
||||
Form.Select = FormSelect
|
||||
Form.Button = Button
|
||||
|
||||
Form.Internals = {
|
||||
Label: FormLabel,
|
||||
Pair: FormPair,
|
||||
Group: FormGroup,
|
||||
}
|
23
src/components/forms/FormArea.stories.jsx
Normal file
23
src/components/forms/FormArea.stories.jsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { FormArea as FormAreaComponent } from "./FormArea"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormAreaComponent,
|
||||
title: "Forms/Form Area",
|
||||
decorators: [Decorators.Form, Decorators.Box, Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const FormArea = props => (
|
||||
<FormAreaComponent {...props}/>
|
||||
)
|
||||
FormArea.args = {
|
||||
label: "Bio",
|
||||
}
|
30
src/components/forms/FormArea.tsx
Normal file
30
src/components/forms/FormArea.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormPair, FormPairProps} from "./FormPair";
|
||||
import {FormLabel, FormLabelProps} from "./FormLabel";
|
||||
import {Area, AreaProps} from "../inputs/Area";
|
||||
|
||||
|
||||
export interface FormAreaProps extends AreaProps {
|
||||
label: string,
|
||||
|
||||
validity?: Types.Validity,
|
||||
|
||||
pairProps?: FormPairProps,
|
||||
labelProps?: FormLabelProps,
|
||||
}
|
||||
|
||||
|
||||
export function FormArea({label, validity, pairProps, labelProps, ...props}: FormAreaProps): JSX.Element {
|
||||
return (
|
||||
<FormPair
|
||||
label={<FormLabel {...labelProps}>{label}</FormLabel>}
|
||||
input={<Area {...props}/>}
|
||||
validity={validity}
|
||||
{...pairProps}
|
||||
/>
|
||||
)
|
||||
}
|
34
src/components/forms/FormCheckboxGroup.stories.jsx
Normal file
34
src/components/forms/FormCheckboxGroup.stories.jsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { FormCheckboxGroup as FormCheckboxGroupComponent } from "./FormCheckboxGroup"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormCheckboxGroupComponent,
|
||||
title: "Forms/Form Checkbox Group",
|
||||
decorators: [Decorators.Form, Decorators.Box, Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Unmanaged = props => (
|
||||
<FormCheckboxGroupComponent {...props}/>
|
||||
)
|
||||
Unmanaged.args = {
|
||||
label: "Sizes",
|
||||
options: ["XS", "S", "M", "L", "XL"],
|
||||
value: undefined,
|
||||
row: false,
|
||||
disabled: false,
|
||||
}
|
||||
|
||||
|
||||
export const Managed = Unmanaged.bind({})
|
||||
Managed.args = {
|
||||
...Unmanaged.args,
|
||||
value: ["M"],
|
||||
}
|
83
src/components/forms/FormCheckboxGroup.tsx
Normal file
83
src/components/forms/FormCheckboxGroup.tsx
Normal file
|
@ -0,0 +1,83 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import * as UUID from "uuid"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormPair, FormPairProps} from "./FormPair";
|
||||
import {FormLabel, FormLabelProps} from "./FormLabel";
|
||||
import {FormGroup, FormGroupProps} from "./FormGroup";
|
||||
import {LabelledCheckbox, LabelledCheckboxProps} from "../inputs/LabelledCheckbox";
|
||||
|
||||
|
||||
export interface FormCheckboxGroupProps extends Types.BluelibProps {
|
||||
name?: string,
|
||||
label: string,
|
||||
options: string[],
|
||||
|
||||
row?: boolean,
|
||||
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
onSimpleChange?: (value: string[]) => void,
|
||||
value?: string[],
|
||||
|
||||
validity?: Types.Validity,
|
||||
|
||||
pairProps?: FormPairProps,
|
||||
labelProps?: FormLabelProps,
|
||||
groupProps?: FormGroupProps,
|
||||
checkboxProps?: LabelledCheckboxProps,
|
||||
}
|
||||
|
||||
|
||||
export function FormCheckboxGroup({name, label, options, row, onChange, onSimpleChange, value, validity, pairProps, labelProps, groupProps, checkboxProps, disabled, bluelibClassNames, customColor}: FormCheckboxGroupProps): JSX.Element {
|
||||
if(!name) {
|
||||
name = UUID.v4()
|
||||
}
|
||||
|
||||
const checkboxes = options.map<JSX.Element>(option => (
|
||||
<LabelledCheckbox
|
||||
label={option}
|
||||
value={option}
|
||||
row={row}
|
||||
checked={value ? value.includes(option) : undefined}
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
{...checkboxProps}
|
||||
/>
|
||||
))
|
||||
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(value && onSimpleChange) {
|
||||
if(event.target.checked) {
|
||||
onSimpleChange(value.concat(event.target.value))
|
||||
}
|
||||
else {
|
||||
const valueCopy = Array.from(value)
|
||||
const indexOf = valueCopy.indexOf(event.target.value)
|
||||
if(indexOf !== -1) valueCopy.splice(indexOf, 1)
|
||||
onSimpleChange(valueCopy)
|
||||
}
|
||||
}
|
||||
},
|
||||
[onChange, value, onSimpleChange]
|
||||
)
|
||||
|
||||
const group = (
|
||||
<FormGroup onChange={onChangeWrapped} value={value} {...groupProps}>
|
||||
{checkboxes}
|
||||
</FormGroup>
|
||||
)
|
||||
|
||||
return (
|
||||
<FormPair
|
||||
label={<FormLabel {...labelProps}>{label}</FormLabel>}
|
||||
input={group}
|
||||
validity={validity}
|
||||
bluelibClassNames={bluelibClassNames}
|
||||
customColor={customColor}
|
||||
{...pairProps}
|
||||
/>
|
||||
)
|
||||
}
|
23
src/components/forms/FormField.stories.jsx
Normal file
23
src/components/forms/FormField.stories.jsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { FormField as FormFieldComponent } from "./FormField"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormFieldComponent,
|
||||
title: "Forms/Form Field",
|
||||
decorators: [Decorators.Form, Decorators.Box, Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const FormField = props => (
|
||||
<FormFieldComponent {...props}/>
|
||||
)
|
||||
FormField.args = {
|
||||
label: "Username",
|
||||
}
|
30
src/components/forms/FormField.tsx
Normal file
30
src/components/forms/FormField.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormPair, FormPairProps} from "./FormPair";
|
||||
import {FormLabel, FormLabelProps} from "./FormLabel";
|
||||
import {Field, FieldProps} from "../inputs/Field";
|
||||
|
||||
|
||||
export interface FormFieldProps extends FieldProps {
|
||||
label: string,
|
||||
|
||||
validity?: Types.Validity,
|
||||
|
||||
pairProps?: FormPairProps,
|
||||
labelProps?: FormLabelProps,
|
||||
}
|
||||
|
||||
|
||||
export function FormField({label, validity, pairProps, labelProps, ...props}: FormFieldProps): JSX.Element {
|
||||
return (
|
||||
<FormPair
|
||||
label={<FormLabel {...labelProps}>{label}</FormLabel>}
|
||||
input={<Field {...props}/>}
|
||||
validity={validity}
|
||||
{...pairProps}
|
||||
/>
|
||||
)
|
||||
}
|
17
src/components/forms/FormGroup.tsx
Normal file
17
src/components/forms/FormGroup.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface FormGroupProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function FormGroup({...props}: FormGroupProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form-group")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
17
src/components/forms/FormLabel.tsx
Normal file
17
src/components/forms/FormLabel.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface FormLabelProps extends Types.BluelibHTMLProps<HTMLLabelElement> {}
|
||||
|
||||
|
||||
export function FormLabel({...props}: FormLabelProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form-label")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"label"} {...props}/>
|
||||
)
|
||||
}
|
35
src/components/forms/FormMultiselect.stories.jsx
Normal file
35
src/components/forms/FormMultiselect.stories.jsx
Normal file
|
@ -0,0 +1,35 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { FormMultiselect as FormMultiselectComponent } from "./FormMultiselect"
|
||||
import { Option } from "../inputs/Option"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormMultiselectComponent,
|
||||
title: "Forms/Form Multiselect",
|
||||
decorators: [Decorators.Form, Decorators.Box, Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const FormMultiselect = props => (
|
||||
<FormMultiselectComponent {...props}>
|
||||
<Option value={"Red"}/>
|
||||
<Option value={"Orange"}/>
|
||||
<Option value={"Yellow"}/>
|
||||
<Option value={"Green"}/>
|
||||
<Option value={"Cyan"}/>
|
||||
<Option value={"Blue"}/>
|
||||
<Option value={"Purple"}/>
|
||||
<Option value={"White"}/>
|
||||
<Option value={"Black"}/>
|
||||
<Option value={"Grey"}/>
|
||||
</FormMultiselectComponent>
|
||||
)
|
||||
FormMultiselect.args = {
|
||||
label: "Favourite colors",
|
||||
}
|
33
src/components/forms/FormMultiselect.tsx
Normal file
33
src/components/forms/FormMultiselect.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormPair, FormPairProps} from "./FormPair";
|
||||
import {FormLabel, FormLabelProps} from "./FormLabel";
|
||||
import {Multiselect, MultiselectProps} from "../inputs/Multiselect";
|
||||
|
||||
|
||||
export interface FormMultiselectProps extends MultiselectProps {
|
||||
label: string,
|
||||
|
||||
validity?: Types.Validity,
|
||||
|
||||
pairProps?: FormPairProps,
|
||||
labelProps?: FormLabelProps,
|
||||
}
|
||||
|
||||
|
||||
export function FormMultiselect({label, validity, pairProps, labelProps, ...props}: FormMultiselectProps): JSX.Element {
|
||||
return (
|
||||
<FormPair
|
||||
label={<FormLabel {...labelProps}>{label}</FormLabel>}
|
||||
input={<Multiselect {...props}/>}
|
||||
validity={validity}
|
||||
{...pairProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
FormMultiselect.Option = Multiselect.Option
|
60
src/components/forms/FormPair.tsx
Normal file
60
src/components/forms/FormPair.tsx
Normal file
|
@ -0,0 +1,60 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as UUID from "uuid"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormLabel} from "./FormLabel";
|
||||
import {FormGroup} from "./FormGroup";
|
||||
|
||||
|
||||
export interface FormPairProps extends Types.BluelibProps {
|
||||
label: JSX.Element,
|
||||
input: JSX.Element,
|
||||
// Validity is in the form pair so it can be propagated to both the label and the group
|
||||
validity?: Types.Validity,
|
||||
id?: string,
|
||||
}
|
||||
|
||||
|
||||
export function FormPair({id, label, input, validity, bluelibClassNames, customColor, disabled}: FormPairProps): JSX.Element {
|
||||
if(!id) {
|
||||
id = UUID.v4()
|
||||
}
|
||||
|
||||
let validityClass
|
||||
// If the input is valid
|
||||
if(validity === true) {
|
||||
validityClass = "color-lime"
|
||||
}
|
||||
// If the input is invalid
|
||||
else if(validity === false) {
|
||||
validityClass = "color-red"
|
||||
}
|
||||
// If the input has no validity
|
||||
else if(validity === null) {
|
||||
validityClass = ""
|
||||
}
|
||||
// If no validity has been passed
|
||||
else {
|
||||
validityClass = ""
|
||||
}
|
||||
|
||||
label = React.cloneElement(label, {
|
||||
htmlFor: id,
|
||||
bluelibClassNames: mergeClassNames(bluelibClassNames, validityClass),
|
||||
customColor: customColor,
|
||||
})
|
||||
|
||||
input = React.cloneElement(input, {
|
||||
id: id,
|
||||
bluelibClassNames: mergeClassNames(bluelibClassNames, validityClass),
|
||||
customColor: customColor,
|
||||
disabled: disabled,
|
||||
})
|
||||
|
||||
return <>
|
||||
{label}
|
||||
{input}
|
||||
</>
|
||||
}
|
26
src/components/forms/FormRadioGroup.stories.jsx
Normal file
26
src/components/forms/FormRadioGroup.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 { FormRadioGroup as FormRadioGroupComponent } from "./FormRadioGroup"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormRadioGroupComponent,
|
||||
title: "Forms/Form Radio Group",
|
||||
decorators: [Decorators.Form, Decorators.Box, Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const FormRadioGroup = props => (
|
||||
<FormRadioGroupComponent {...props}/>
|
||||
)
|
||||
FormRadioGroup.args = {
|
||||
label: "Size",
|
||||
options: ["XS", "S", "M", "L", "XL"],
|
||||
row: false,
|
||||
disabled: false,
|
||||
}
|
75
src/components/forms/FormRadioGroup.tsx
Normal file
75
src/components/forms/FormRadioGroup.tsx
Normal file
|
@ -0,0 +1,75 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import * as UUID from "uuid"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormPair, FormPairProps} from "./FormPair";
|
||||
import {FormLabel, FormLabelProps} from "./FormLabel";
|
||||
import {FormGroup, FormGroupProps} from "./FormGroup";
|
||||
import {Radio} from "../inputs/Radio";
|
||||
import {LabelledRadio, LabelledRadioProps} from "../inputs/LabelledRadio";
|
||||
|
||||
|
||||
|
||||
export interface FormRadioGroupProps extends Types.BluelibProps {
|
||||
name?: string,
|
||||
label: string,
|
||||
options: string[],
|
||||
|
||||
row?: boolean,
|
||||
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
onSimpleChange?: (value: string) => void,
|
||||
value?: string,
|
||||
|
||||
validity?: Types.Validity,
|
||||
|
||||
pairProps?: FormPairProps,
|
||||
labelProps?: FormLabelProps,
|
||||
groupProps?: FormGroupProps,
|
||||
radioProps?: LabelledRadioProps,
|
||||
}
|
||||
|
||||
|
||||
export function FormRadioGroup({name, label, options, row, onChange, onSimpleChange, value, validity, pairProps, labelProps, groupProps, radioProps, disabled, bluelibClassNames, customColor}: FormRadioGroupProps): JSX.Element {
|
||||
if(!name) {
|
||||
name = UUID.v4()
|
||||
}
|
||||
|
||||
const radios = options.map<JSX.Element>(option => (
|
||||
<LabelledRadio
|
||||
label={option}
|
||||
value={option}
|
||||
row={row}
|
||||
checked={value ? value === option : undefined}
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
{...radioProps}
|
||||
/>
|
||||
))
|
||||
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||
},
|
||||
[onChange, onSimpleChange]
|
||||
)
|
||||
|
||||
const group = (
|
||||
<FormGroup onChange={onChangeWrapped} value={value} {...groupProps}>
|
||||
{radios}
|
||||
</FormGroup>
|
||||
)
|
||||
|
||||
return (
|
||||
<FormPair
|
||||
label={<FormLabel {...labelProps}>{label}</FormLabel>}
|
||||
input={group}
|
||||
validity={validity}
|
||||
bluelibClassNames={bluelibClassNames}
|
||||
customColor={customColor}
|
||||
{...pairProps}
|
||||
/>
|
||||
)
|
||||
}
|
32
src/components/forms/FormRow.stories.jsx
Normal file
32
src/components/forms/FormRow.stories.jsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { FormRow as FormRowComponent } from "./FormRow"
|
||||
import { Parenthesis } from "../panels/Parenthesis"
|
||||
import { Button } from "../inputs/Button"
|
||||
import { Separator } from "../separators/Separator"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormRowComponent,
|
||||
title: "Forms/Form Row",
|
||||
decorators: [Decorators.Form, Decorators.Box, Decorators.Bluelib],
|
||||
}
|
||||
|
||||
|
||||
export const WithText = props => (
|
||||
<FormRowComponent {...props}>
|
||||
<Parenthesis>By logging in, you accept our Terms of Service.</Parenthesis>
|
||||
</FormRowComponent>
|
||||
)
|
||||
WithText.args = {}
|
||||
|
||||
|
||||
export const WithButtons = props => (
|
||||
<FormRowComponent {...props}>
|
||||
<Button>Cancel</Button>
|
||||
<Button>Retry</Button>
|
||||
<Button>Ignore</Button>
|
||||
</FormRowComponent>
|
||||
)
|
||||
WithButtons.args = {}
|
17
src/components/forms/FormRow.tsx
Normal file
17
src/components/forms/FormRow.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface FormRowProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function FormRow({...props}: FormRowProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form-row")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
28
src/components/forms/FormSelect.stories.jsx
Normal file
28
src/components/forms/FormSelect.stories.jsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { FormSelect as FormSelectComponent } from "./FormSelect"
|
||||
import { Option } from "../inputs/Option"
|
||||
|
||||
|
||||
export default {
|
||||
component: FormSelectComponent,
|
||||
title: "Forms/Form Select",
|
||||
decorators: [Decorators.Form, Decorators.Box, Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const FormSelect = props => (
|
||||
<FormSelectComponent {...props}>
|
||||
<Option value={"I'm ready!"}/>
|
||||
<Option value={"Please wait..."}/>
|
||||
<Option value={"I won't be there."}/>
|
||||
</FormSelectComponent>
|
||||
)
|
||||
FormSelect.args = {
|
||||
label: "Ready check",
|
||||
}
|
32
src/components/forms/FormSelect.tsx
Normal file
32
src/components/forms/FormSelect.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {FormPair, FormPairProps} from "./FormPair";
|
||||
import {FormLabel, FormLabelProps} from "./FormLabel";
|
||||
import {Select, SelectProps} from "../inputs/Select";
|
||||
|
||||
|
||||
export interface FormSelectProps extends SelectProps {
|
||||
label: string,
|
||||
|
||||
validity?: Types.Validity,
|
||||
|
||||
pairProps?: FormPairProps,
|
||||
labelProps?: FormLabelProps,
|
||||
}
|
||||
|
||||
|
||||
export function FormSelect({label, validity, pairProps, labelProps, ...props}: FormSelectProps): JSX.Element {
|
||||
return (
|
||||
<FormPair
|
||||
label={<FormLabel {...labelProps}>{label}</FormLabel>}
|
||||
input={<Select {...props}/>}
|
||||
validity={validity}
|
||||
{...pairProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
FormSelect.Option = Select.Option
|
|
@ -17,25 +17,28 @@ export default {
|
|||
}
|
||||
|
||||
|
||||
export const NoLimit = props => (
|
||||
export const FullLimit = props => (
|
||||
<Image {...props}/>
|
||||
)
|
||||
NoLimit.args = {
|
||||
FullLimit.args = {
|
||||
src: PineappleWithSunglasses,
|
||||
|
||||
limit: "no",
|
||||
disabled: false,
|
||||
}
|
||||
|
||||
|
||||
export const HalfLimit = NoLimit.bind({})
|
||||
export const HalfLimit = FullLimit.bind({})
|
||||
HalfLimit.args = {
|
||||
...NoLimit.args,
|
||||
...FullLimit.args,
|
||||
|
||||
limit: "half",
|
||||
}
|
||||
|
||||
|
||||
export const QuarterLimit = NoLimit.bind({})
|
||||
export const QuarterLimit = FullLimit.bind({})
|
||||
QuarterLimit.args = {
|
||||
...NoLimit.args,
|
||||
...FullLimit.args,
|
||||
|
||||
limit: "quarter",
|
||||
}
|
|
@ -5,29 +5,25 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface ImageProps {
|
||||
src: string,
|
||||
limit?: "no" | "half" | "quarter",
|
||||
|
||||
[props: string]: any,
|
||||
export interface ImageProps extends Types.BluelibHTMLProps<HTMLImageElement> {
|
||||
limit?: "full" | "half" | "quarter",
|
||||
}
|
||||
|
||||
|
||||
const LIMIT_CLASSES = {
|
||||
no: "",
|
||||
full: "",
|
||||
half: "image-limit-half",
|
||||
quarter: "image-limit-quarter",
|
||||
}
|
||||
|
||||
|
||||
export function Image({limit = "no", ...props}: ImageProps): JSX.Element {
|
||||
export function Image({limit = "full", ...props}: ImageProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "image")
|
||||
|
||||
if(limit) {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, LIMIT_CLASSES[limit])
|
||||
}
|
||||
|
||||
// TODO: Capture the src and make the image clickable
|
||||
|
||||
return (
|
||||
<BaseElement kind={"img"} {...props}/>
|
||||
)
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Area } from "./Area"
|
||||
import { Area as AreaComponent } from "./Area"
|
||||
|
||||
|
||||
export default {
|
||||
component: Area,
|
||||
component: AreaComponent,
|
||||
title: "Inputs/Area",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<Area {...props}/>
|
||||
export const Area = props => (
|
||||
<AreaComponent {...props}/>
|
||||
)
|
||||
Default.args = {
|
||||
Area.args = {
|
||||
placeholder: "Enter multiline text here\n\nThis component can be resized",
|
||||
disabled: false,
|
||||
required: false,
|
||||
|
|
|
@ -5,37 +5,25 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface AreaProps {
|
||||
placeholder: string,
|
||||
required?: boolean,
|
||||
disabled?: boolean,
|
||||
|
||||
onChange: (contents: string) => boolean,
|
||||
export interface AreaProps extends Types.BluelibHTMLProps<HTMLTextAreaElement> {
|
||||
onChange?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void,
|
||||
onSimpleChange?: (value: string) => void,
|
||||
value?: string,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function Area({onChange, ...props}: AreaProps): JSX.Element {
|
||||
export function Area({onChange, onSimpleChange, ...props}: AreaProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-area")
|
||||
|
||||
const onChangeWrapper = React.useCallback(
|
||||
|
||||
(event: React.ChangeEvent<HTMLTextAreaElement>): boolean => {
|
||||
const contents = event.target.value
|
||||
|
||||
if(onChange) {
|
||||
return onChange(contents)
|
||||
}
|
||||
|
||||
return false
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||
},
|
||||
|
||||
[onChange]
|
||||
[onChange, onSimpleChange]
|
||||
)
|
||||
|
||||
return (
|
||||
<BaseElement kind={"textarea"} onChange={onChangeWrapper} {...props}/>
|
||||
<BaseElement kind={"textarea"} onChange={onChangeWrapped} {...props}/>
|
||||
)
|
||||
}
|
||||
|
|
24
src/components/inputs/Button.stories.jsx
Normal file
24
src/components/inputs/Button.stories.jsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Button as ButtonComponent } from "./Button"
|
||||
|
||||
|
||||
export default {
|
||||
component: ButtonComponent,
|
||||
title: "Inputs/Button",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onClick: {action: "Click"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Button = ({ children, ...props }) => {
|
||||
// Weird thing to get IntelliJ to understand that this component is fine
|
||||
return <ButtonComponent {...props}>{children}</ButtonComponent>
|
||||
}
|
||||
Button.args = {
|
||||
children: "Click me!",
|
||||
disabled: false,
|
||||
}
|
23
src/components/inputs/Button.tsx
Normal file
23
src/components/inputs/Button.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"
|
||||
|
||||
|
||||
export interface ButtonProps extends Types.BluelibHTMLProps<HTMLButtonElement> {
|
||||
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void,
|
||||
|
||||
children: React.ReactNode,
|
||||
}
|
||||
|
||||
|
||||
export function Button({onClick, disabled, children, ...props}: ButtonProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-button")
|
||||
|
||||
const onClickWrapped = disabled ? () => {} : onClick
|
||||
|
||||
return (
|
||||
<BaseElement kind={"button"} type={"button"} onClick={onClickWrapped} disabled={disabled} {...props}>{children}</BaseElement>
|
||||
)
|
||||
}
|
|
@ -1,50 +1,26 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Checkbox } from "./Checkbox"
|
||||
import { Checkbox as CheckboxComponent } from "./Checkbox"
|
||||
import { Box } from "../panels/Box"
|
||||
import { BaseElement } from "../BaseElement"
|
||||
|
||||
|
||||
export default {
|
||||
component: Checkbox,
|
||||
component: CheckboxComponent,
|
||||
title: "Inputs/Checkbox",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<Checkbox value={"zero"} {...props}/>
|
||||
export const Checkbox = props => (
|
||||
<CheckboxComponent {...props}/>
|
||||
)
|
||||
|
||||
|
||||
|
||||
export const ThreeCheckboxes = props => (
|
||||
<BaseElement kind={"div"}>
|
||||
<BaseElement kind={"div"} bluelibClassNames={"color-blue"}>
|
||||
<Checkbox value={"suicune"} {...props}/> Suicune
|
||||
</BaseElement>
|
||||
<BaseElement kind={"div"} bluelibClassNames={"color-yellow"}>
|
||||
<Checkbox value={"raikou"} {...props}/> Raikou
|
||||
</BaseElement>
|
||||
<BaseElement kind={"div"} bluelibClassNames={"color-red"}>
|
||||
<Checkbox value={"entei"} {...props}/> Entei
|
||||
</BaseElement>
|
||||
</BaseElement>
|
||||
)
|
||||
ThreeCheckboxes.args = {
|
||||
name: "example"
|
||||
Checkbox.args = {
|
||||
name: "what",
|
||||
value: "this-checkbox-right-here",
|
||||
}
|
||||
ThreeCheckboxes.argTypes = {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
value: {
|
||||
control: {type: "null"},
|
||||
},
|
||||
}
|
|
@ -5,38 +5,26 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface CheckboxProps {
|
||||
disabled?: boolean,
|
||||
|
||||
onChange?: (value: string, checked: boolean) => boolean,
|
||||
|
||||
name: string,
|
||||
export interface CheckboxProps extends Types.BluelibHTMLProps<HTMLInputElement> {
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
onSimpleChange?: (value: string, checked: boolean) => void,
|
||||
checked?: boolean,
|
||||
value: string,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function Checkbox({onChange, ...props}: CheckboxProps): JSX.Element {
|
||||
export function Checkbox({onChange, onSimpleChange, ...props}: CheckboxProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-checkbox")
|
||||
|
||||
const onChangeWrapper = React.useCallback(
|
||||
|
||||
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
||||
const checked = event.target.checked
|
||||
const value = event.target.value
|
||||
|
||||
if(onChange) {
|
||||
return onChange(value, checked)
|
||||
}
|
||||
|
||||
return false
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(onSimpleChange) onSimpleChange(event.target.value, event.target.checked)
|
||||
},
|
||||
|
||||
[onChange]
|
||||
[onChange, onSimpleChange]
|
||||
)
|
||||
|
||||
return (
|
||||
<BaseElement kind={"input"} type={"checkbox"} onChange={onChangeWrapper} {...props}/>
|
||||
<BaseElement kind={"input"} type={"checkbox"} onChange={onChangeWrapped} {...props}/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Field } from "./Field"
|
||||
import { Field as FieldComponent } from "./Field"
|
||||
|
||||
|
||||
export default {
|
||||
component: Field,
|
||||
component: FieldComponent,
|
||||
title: "Inputs/Field",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<Field {...props}/>
|
||||
export const Field = props => (
|
||||
<FieldComponent {...props}/>
|
||||
)
|
||||
Default.args = {
|
||||
Field.args = {
|
||||
placeholder: "Enter text here",
|
||||
disabled: false,
|
||||
required: false,
|
||||
|
|
|
@ -5,37 +5,25 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface FieldProps {
|
||||
placeholder: string,
|
||||
required?: boolean,
|
||||
disabled?: boolean,
|
||||
|
||||
onChange: (contents: string) => boolean,
|
||||
export interface FieldProps extends Types.BluelibHTMLProps<HTMLInputElement> {
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
onSimpleChange?: (value: string) => void,
|
||||
value?: string,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function Field({onChange, value, ...props}: FieldProps): JSX.Element {
|
||||
export function Field({onChange, onSimpleChange, ...props}: FieldProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-field")
|
||||
|
||||
const onChangeWrapper = React.useCallback(
|
||||
|
||||
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
||||
const contents = event.target.value
|
||||
|
||||
if(onChange) {
|
||||
return onChange(contents)
|
||||
}
|
||||
|
||||
return false
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||
},
|
||||
|
||||
[onChange]
|
||||
[onChange, onSimpleChange]
|
||||
)
|
||||
|
||||
return (
|
||||
<BaseElement kind={"input"} onChange={onChangeWrapper} {...props}/>
|
||||
<BaseElement kind={"input"} onChange={onChangeWrapped} {...props}/>
|
||||
)
|
||||
}
|
||||
|
|
15
src/components/inputs/InputLabel.tsx
Normal file
15
src/components/inputs/InputLabel.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface InputLabelProps extends Types.BluelibHTMLProps<HTMLLabelElement> {}
|
||||
|
||||
|
||||
export function InputLabel({...props}: InputLabelProps): JSX.Element {
|
||||
return (
|
||||
<BaseElement kind={"label"} {...props}/>
|
||||
)
|
||||
}
|
25
src/components/inputs/LabelledCheckbox.stories.jsx
Normal file
25
src/components/inputs/LabelledCheckbox.stories.jsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { LabelledCheckbox as LabelledCheckboxComponent } from "./LabelledCheckbox"
|
||||
|
||||
|
||||
export default {
|
||||
component: LabelledCheckboxComponent,
|
||||
title: "Inputs/Labelled Checkbox",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const LabelledCheckbox = props => (
|
||||
<LabelledCheckboxComponent {...props}/>
|
||||
)
|
||||
LabelledCheckbox.args = {
|
||||
label: "This",
|
||||
name: "what",
|
||||
value: "this",
|
||||
}
|
26
src/components/inputs/LabelledCheckbox.tsx
Normal file
26
src/components/inputs/LabelledCheckbox.tsx
Normal file
|
@ -0,0 +1,26 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {InputLabel, InputLabelProps} from "./InputLabel";
|
||||
import {Checkbox, CheckboxProps} from "./Checkbox";
|
||||
|
||||
|
||||
export interface LabelledCheckboxProps extends CheckboxProps {
|
||||
label: string,
|
||||
labelProps?: InputLabelProps,
|
||||
row?: boolean,
|
||||
}
|
||||
|
||||
|
||||
export function LabelledCheckbox({label, labelProps = {}, row, ...props}: LabelledCheckboxProps): JSX.Element {
|
||||
labelProps.bluelibClassNames = mergeClassNames(props.bluelibClassNames, row ? "form-group-row": "")
|
||||
|
||||
return (
|
||||
<InputLabel {...labelProps}>
|
||||
<Checkbox {...props}/>
|
||||
{label}
|
||||
</InputLabel>
|
||||
)
|
||||
}
|
25
src/components/inputs/LabelledRadio.stories.jsx
Normal file
25
src/components/inputs/LabelledRadio.stories.jsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { LabelledRadio as LabelledRadioComponent } from "./LabelledRadio"
|
||||
|
||||
|
||||
export default {
|
||||
component: LabelledRadioComponent,
|
||||
title: "Inputs/Labelled Radio",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const LabelledRadio = props => (
|
||||
<LabelledRadioComponent {...props}/>
|
||||
)
|
||||
LabelledRadio.args = {
|
||||
label: "This",
|
||||
name: "what",
|
||||
value: "this",
|
||||
}
|
26
src/components/inputs/LabelledRadio.tsx
Normal file
26
src/components/inputs/LabelledRadio.tsx
Normal file
|
@ -0,0 +1,26 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {Radio, RadioProps} from "./Radio";
|
||||
import {InputLabel, InputLabelProps} from "./InputLabel";
|
||||
|
||||
|
||||
export interface LabelledRadioProps extends RadioProps {
|
||||
label: string,
|
||||
labelProps?: InputLabelProps,
|
||||
row?: boolean,
|
||||
}
|
||||
|
||||
|
||||
export function LabelledRadio({label, labelProps = {}, row, ...props}: LabelledRadioProps): JSX.Element {
|
||||
labelProps.bluelibClassNames = mergeClassNames(props.bluelibClassNames, row ? "form-group-row": "")
|
||||
|
||||
return (
|
||||
<InputLabel {...labelProps}>
|
||||
<Radio {...props}/>
|
||||
{label}
|
||||
</InputLabel>
|
||||
)
|
||||
}
|
|
@ -8,40 +8,40 @@ import { Multiselect } from "./Multiselect"
|
|||
|
||||
export default {
|
||||
component: Multiselect,
|
||||
subcomponents: {Option, OptionGroup},
|
||||
title: "Inputs/Multiselect",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
export const Basic = props => (
|
||||
<Multiselect {...props}>
|
||||
<Option label={"Yes"}/>
|
||||
<Option label={"Maybe"}/>
|
||||
<Option label={"No"}/>
|
||||
<Multiselect.Option value={"Yes"}/>
|
||||
<Multiselect.Option value={"Maybe"}/>
|
||||
<Multiselect.Option value={"No"}/>
|
||||
</Multiselect>
|
||||
)
|
||||
Default.args = {
|
||||
Basic.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.Group label={"A"}>
|
||||
<Multiselect.Option value={"Anchor"}/>
|
||||
<Multiselect.Option value={"Angel"}/>
|
||||
<Multiselect.Option value={"Anti-air"}/>
|
||||
</Multiselect.Group>
|
||||
<Multiselect.Group label={"B"}>
|
||||
<Multiselect.Option value={"Banana"}/>
|
||||
<Multiselect.Option value={"Boat"}/>
|
||||
<Multiselect.Option value={"Bus"}/>
|
||||
</Multiselect.Group>
|
||||
</Multiselect>
|
||||
)
|
||||
WithGroups.args = {
|
||||
|
|
|
@ -3,39 +3,33 @@ import * as ReactDOM from "react-dom"
|
|||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {Option} from "./Option";
|
||||
import {OptionGroup} from "./OptionGroup";
|
||||
|
||||
|
||||
interface MultiselectProps {
|
||||
disabled?: boolean,
|
||||
|
||||
onChange?: (contents: string[]) => boolean,
|
||||
|
||||
children: React.ReactNode,
|
||||
|
||||
[props: string]: any,
|
||||
export interface MultiselectProps extends Types.BluelibHTMLProps<HTMLSelectElement> {
|
||||
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void,
|
||||
onSimpleChange?: (value: string[]) => void,
|
||||
value?: string[],
|
||||
}
|
||||
|
||||
|
||||
export function Multiselect({onChange, ...props}: MultiselectProps): JSX.Element {
|
||||
export function Multiselect({onChange, onSimpleChange, ...props}: MultiselectProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-multiselect")
|
||||
|
||||
const onChangeWrapper = React.useCallback(
|
||||
|
||||
(event: React.ChangeEvent<HTMLSelectElement>): boolean => {
|
||||
const options = Array.from(event.target.selectedOptions)
|
||||
const contents = options.map((option: HTMLOptionElement) => option.value)
|
||||
|
||||
if(onChange) {
|
||||
return onChange(contents)
|
||||
}
|
||||
|
||||
return false
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(onSimpleChange) onSimpleChange(Array.from<HTMLOptionElement>(event.target.selectedOptions).map(option => option.value))
|
||||
},
|
||||
|
||||
[onChange]
|
||||
[onChange, onSimpleChange]
|
||||
)
|
||||
|
||||
return (
|
||||
<BaseElement kind={"select"} multiple={true} onChange={onChangeWrapper} {...props}/>
|
||||
<BaseElement kind={"select"} multiple={true} onChange={onChangeWrapped} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Multiselect.Option = Option
|
||||
Multiselect.Group = OptionGroup
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import * as React from "react"
|
||||
import * as Types from "../../types"
|
||||
|
||||
|
||||
export const MultiselectContext: Types.UseStateContext<string[]> = React.createContext(null) as Types.UseStateContext<string[]>
|
|
@ -5,19 +5,19 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface OptionProps {
|
||||
label: string,
|
||||
export interface OptionProps {
|
||||
value: string,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function Option({label, ...props}: OptionProps): JSX.Element {
|
||||
export function Option({value, ...props}: OptionProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input-option")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"option"} {...props}>
|
||||
{label}
|
||||
{value}
|
||||
</BaseElement>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface OptionGroupProps {
|
||||
export interface OptionGroupProps {
|
||||
label: string,
|
||||
|
||||
[props: string]: any,
|
||||
|
|
|
@ -1,50 +1,26 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Radio } from "./Radio"
|
||||
import { Radio as RadioComponent } from "./Radio"
|
||||
import { Box } from "../panels/Box"
|
||||
import { BaseElement } from "../BaseElement"
|
||||
|
||||
|
||||
export default {
|
||||
component: Radio,
|
||||
component: RadioComponent,
|
||||
title: "Inputs/Radio",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<Radio value={"zero"} {...props}/>
|
||||
export const Radio = props => (
|
||||
<RadioComponent {...props}/>
|
||||
)
|
||||
|
||||
|
||||
|
||||
export const ThreeRadios = props => (
|
||||
<BaseElement kind={"div"}>
|
||||
<BaseElement kind={"div"} bluelibClassNames={"color-blue"}>
|
||||
<Radio value={"articuno"} {...props}/> Articuno
|
||||
</BaseElement>
|
||||
<BaseElement kind={"div"} bluelibClassNames={"color-yellow"}>
|
||||
<Radio value={"zapdos"} {...props}/> Zapdos
|
||||
</BaseElement>
|
||||
<BaseElement kind={"div"} bluelibClassNames={"color-red"}>
|
||||
<Radio value={"moltres"} {...props}/> Moltres
|
||||
</BaseElement>
|
||||
</BaseElement>
|
||||
)
|
||||
ThreeRadios.args = {
|
||||
name: "example"
|
||||
Radio.args = {
|
||||
name: "what",
|
||||
value: "this-radio-right-here",
|
||||
}
|
||||
ThreeRadios.argTypes = {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
value: {
|
||||
control: {type: "null"},
|
||||
},
|
||||
}
|
|
@ -5,37 +5,26 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface RadioProps {
|
||||
disabled?: boolean,
|
||||
|
||||
onChange?: (value: string) => boolean,
|
||||
|
||||
name: string,
|
||||
export interface RadioProps extends Types.BluelibHTMLProps<HTMLInputElement> {
|
||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||
onSimpleChange?: (value: string) => void,
|
||||
checked?: boolean,
|
||||
value: string,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function Radio({onChange, ...props}: RadioProps): JSX.Element {
|
||||
export function Radio({onChange, onSimpleChange, ...props}: RadioProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-radio")
|
||||
|
||||
const onChangeWrapper = React.useCallback(
|
||||
|
||||
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
||||
const value = event.target.value
|
||||
|
||||
if(onChange) {
|
||||
return onChange(value)
|
||||
}
|
||||
|
||||
return false
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||
},
|
||||
|
||||
[onChange]
|
||||
[onChange, onSimpleChange]
|
||||
)
|
||||
|
||||
return (
|
||||
<BaseElement kind={"input"} type={"radio"} onChange={onChangeWrapper} {...props}/>
|
||||
<BaseElement kind={"input"} type={"radio"} onChange={onChangeWrapped} {...props}/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,49 +1,48 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Select } from "./Select"
|
||||
import { Select, Select as SelectComponent } from "./Select"
|
||||
import { Option } from "./Option"
|
||||
import { OptionGroup } from "./OptionGroup"
|
||||
|
||||
|
||||
export default {
|
||||
component: Select,
|
||||
component: SelectComponent,
|
||||
title: "Inputs/Select",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
onChange: {action: "Change"},
|
||||
onSimpleChange: {action: "SimpleChange"},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<Select {...props}>
|
||||
<Option label={"Yes"}/>
|
||||
<Option label={"Maybe"}/>
|
||||
<Option label={"No"}/>
|
||||
</Select>
|
||||
export const Basic = props => (
|
||||
<SelectComponent {...props}>
|
||||
<SelectComponent.Option value={"Yes"}/>
|
||||
<SelectComponent.Option value={"Maybe"}/>
|
||||
<SelectComponent.Option value={"No"}/>
|
||||
</SelectComponent>
|
||||
)
|
||||
Default.args = {
|
||||
Basic.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>
|
||||
<SelectComponent {...props}>
|
||||
<SelectComponent.Option value={"Ungrouped"}/>
|
||||
<SelectComponent.Group label={"A"}>
|
||||
<SelectComponent.Option value={"Anchor"}/>
|
||||
<SelectComponent.Option value={"Angel"}/>
|
||||
<SelectComponent.Option value={"Anti-air"}/>
|
||||
</SelectComponent.Group>
|
||||
<SelectComponent.Group label={"B"}>
|
||||
<SelectComponent.Option value={"Banana"}/>
|
||||
<SelectComponent.Option value={"Boat"}/>
|
||||
<SelectComponent.Option value={"Bus"}/>
|
||||
</SelectComponent.Group>
|
||||
</SelectComponent>
|
||||
)
|
||||
WithGroups.args = {
|
||||
disabled: false,
|
||||
|
|
|
@ -3,40 +3,33 @@ import * as ReactDOM from "react-dom"
|
|||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {SelectContext} from "./SelectContext";
|
||||
import {Option} from "./Option"
|
||||
import {OptionGroup} from "./OptionGroup"
|
||||
|
||||
|
||||
interface SelectProps {
|
||||
disabled?: boolean,
|
||||
|
||||
onChange?: (contents: string) => boolean,
|
||||
|
||||
children: React.ReactNode,
|
||||
|
||||
[props: string]: any,
|
||||
export interface SelectProps extends Types.BluelibHTMLProps<HTMLSelectElement> {
|
||||
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void,
|
||||
onSimpleChange?: (value: string) => void,
|
||||
value?: string,
|
||||
}
|
||||
|
||||
|
||||
export function Select({onChange, ...props}: SelectProps): JSX.Element {
|
||||
|
||||
export function Select({onChange, onSimpleChange, ...props}: SelectProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-select")
|
||||
|
||||
const onChangeWrapper = React.useCallback(
|
||||
|
||||
(event: React.ChangeEvent<HTMLSelectElement>): boolean => {
|
||||
const contents = event.target.value
|
||||
|
||||
if(onChange) {
|
||||
return onChange(contents)
|
||||
}
|
||||
|
||||
return false
|
||||
const onChangeWrapped = React.useCallback(
|
||||
event => {
|
||||
if(onChange) onChange(event)
|
||||
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||
},
|
||||
|
||||
[onChange]
|
||||
[onChange, onSimpleChange]
|
||||
)
|
||||
|
||||
return (
|
||||
<BaseElement kind={"select"} multiple={false} onChange={onChangeWrapper} {...props}/>
|
||||
<BaseElement kind={"select"} multiple={false} required={true} onChange={onChangeWrapped} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Select.Option = Option
|
||||
Select.Group = OptionGroup
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import * as React from "react"
|
||||
import * as Types from "../../types"
|
||||
|
||||
|
||||
export const SelectContext: Types.UseStateContext<string> = React.createContext(null) as Types.UseStateContext<string>
|
|
@ -5,14 +5,10 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface LayoutProps {
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
export interface BaseLayoutProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function BaseLayout({...props}: LayoutProps): JSX.Element {
|
||||
|
||||
export function BaseLayout({...props}: BaseLayoutProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout")
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { LayoutFill } from "./LayoutFill"
|
||||
import { Bluelib } from "../Bluelib"
|
||||
import { LayoutFill as LayoutFillComponent } from "./LayoutFill"
|
||||
import { LayoutFillSingle } from "./LayoutFillSingle"
|
||||
import { Box } from "../panels/Box"
|
||||
|
||||
|
||||
export default {
|
||||
component: LayoutFill,
|
||||
title: "Layouts/LayoutFill",
|
||||
component: LayoutFillComponent,
|
||||
subcomponents: {LayoutFillSingle},
|
||||
title: "Layouts/Layout Fill",
|
||||
decorators: [Decorators.Bluelib, Decorators.Fill],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
|
@ -16,13 +17,13 @@ export default {
|
|||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<LayoutFill {...props}>
|
||||
<LayoutFill.Single>
|
||||
export const LayoutFill = props => (
|
||||
<LayoutFillComponent {...props}>
|
||||
<LayoutFillComponent.Single>
|
||||
<Box>
|
||||
Single
|
||||
</Box>
|
||||
</LayoutFill.Single>
|
||||
</LayoutFill>
|
||||
</LayoutFillComponent.Single>
|
||||
</LayoutFillComponent>
|
||||
)
|
||||
Default.args = {}
|
||||
LayoutFill.args = {}
|
||||
|
|
|
@ -3,12 +3,11 @@ import * as ReactDOM from "react-dom"
|
|||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {BaseLayout} from "./BaseLayout";
|
||||
import {BaseLayout, BaseLayoutProps} from "./BaseLayout";
|
||||
import {LayoutFillSingle} from "./LayoutFillSingle";
|
||||
|
||||
|
||||
interface LayoutFillProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
export interface LayoutFillProps extends BaseLayoutProps {}
|
||||
|
||||
|
||||
export function LayoutFill({...props}: LayoutFillProps): JSX.Element {
|
||||
|
@ -18,12 +17,4 @@ export function LayoutFill({...props}: LayoutFillProps): JSX.Element {
|
|||
}
|
||||
|
||||
|
||||
interface LayoutFillSingleProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
LayoutFill.Single = function({...props}: LayoutFillSingleProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-fill-single")
|
||||
|
||||
return <BaseElement kind={"div"} {...props}/>
|
||||
}
|
||||
LayoutFill.Single = LayoutFillSingle
|
17
src/components/layouts/LayoutFillSingle.tsx
Normal file
17
src/components/layouts/LayoutFillSingle.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface LayoutFillSingleProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function LayoutFillSingle({...props}: LayoutFillSingleProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-fill-single")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
|
@ -1,13 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { LayoutThreeCol } from "./LayoutThreeCol"
|
||||
import { LayoutThreeCol as LayoutThreeColComponent } from "./LayoutThreeCol"
|
||||
import { LayoutThreeColLeft } from "./LayoutThreeColLeft"
|
||||
import { LayoutThreeColCenter } from "./LayoutThreeColCenter"
|
||||
import { LayoutThreeColRight } from "./LayoutThreeColRight"
|
||||
import { Box } from "../panels/Box"
|
||||
|
||||
|
||||
export default {
|
||||
component: LayoutThreeCol,
|
||||
title: "Layouts/LayoutThreeCol",
|
||||
component: LayoutThreeColComponent,
|
||||
subcomponents: {LayoutThreeColLeft, LayoutThreeColCenter, LayoutThreeColRight},
|
||||
title: "Layouts/Layout Three Col",
|
||||
decorators: [Decorators.Bluelib, Decorators.Fill],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
|
@ -15,23 +19,23 @@ export default {
|
|||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<LayoutThreeCol {...props}>
|
||||
<LayoutThreeCol.Left>
|
||||
export const LayoutThreeCol = props => (
|
||||
<LayoutThreeColComponent {...props}>
|
||||
<LayoutThreeColComponent.Left>
|
||||
<Box>
|
||||
Left
|
||||
</Box>
|
||||
</LayoutThreeCol.Left>
|
||||
<LayoutThreeCol.Center>
|
||||
</LayoutThreeColComponent.Left>
|
||||
<LayoutThreeColComponent.Center>
|
||||
<Box>
|
||||
Center
|
||||
</Box>
|
||||
</LayoutThreeCol.Center>
|
||||
<LayoutThreeCol.Right>
|
||||
</LayoutThreeColComponent.Center>
|
||||
<LayoutThreeColComponent.Right>
|
||||
<Box>
|
||||
Right
|
||||
</Box>
|
||||
</LayoutThreeCol.Right>
|
||||
</LayoutThreeCol>
|
||||
</LayoutThreeColComponent.Right>
|
||||
</LayoutThreeColComponent>
|
||||
)
|
||||
Default.args = {}
|
||||
LayoutThreeCol.args = {}
|
||||
|
|
|
@ -3,10 +3,13 @@ import * as ReactDOM from "react-dom"
|
|||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {BaseLayout} from "./BaseLayout";
|
||||
import {BaseLayout, BaseLayoutProps} from "./BaseLayout";
|
||||
import {LayoutThreeColLeft} from "./LayoutThreeColLeft";
|
||||
import {LayoutThreeColCenter} from "./LayoutThreeColCenter";
|
||||
import {LayoutThreeColRight} from "./LayoutThreeColRight";
|
||||
|
||||
|
||||
interface LayoutThreeColProps {
|
||||
export interface LayoutThreeColProps extends BaseLayoutProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
@ -20,37 +23,6 @@ export function LayoutThreeCol({...props}: LayoutThreeColProps): JSX.Element {
|
|||
}
|
||||
|
||||
|
||||
interface LayoutThreeColLeftProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
LayoutThreeCol.Left = function({...props}: LayoutThreeColLeftProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-left")
|
||||
|
||||
return <BaseElement kind={"div"} {...props}/>
|
||||
}
|
||||
|
||||
|
||||
interface LayoutThreeColCenterProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
LayoutThreeCol.Center = function({...props}: LayoutThreeColCenterProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-center")
|
||||
|
||||
return <BaseElement kind={"div"} {...props}/>
|
||||
}
|
||||
|
||||
|
||||
interface LayoutThreeColRightProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
LayoutThreeCol.Right = function({...props}: LayoutThreeColRightProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-right")
|
||||
|
||||
return <BaseElement kind={"div"} {...props}/>
|
||||
}
|
||||
LayoutThreeCol.Left = LayoutThreeColLeft
|
||||
LayoutThreeCol.Center = LayoutThreeColCenter
|
||||
LayoutThreeCol.Right = LayoutThreeColRight
|
17
src/components/layouts/LayoutThreeColCenter.tsx
Normal file
17
src/components/layouts/LayoutThreeColCenter.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface LayoutThreeColCenterProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function LayoutThreeColCenter({...props}: LayoutThreeColCenterProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-center")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
17
src/components/layouts/LayoutThreeColLeft.tsx
Normal file
17
src/components/layouts/LayoutThreeColLeft.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface LayoutThreeColLeftProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function LayoutThreeColLeft({...props}: LayoutThreeColLeftProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-left")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
17
src/components/layouts/LayoutThreeColRight.tsx
Normal file
17
src/components/layouts/LayoutThreeColRight.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface LayoutThreeColRightProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||
|
||||
|
||||
export function LayoutThreeColRight({...props}: LayoutThreeColRightProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-right")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"div"} {...props}/>
|
||||
)
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { DescriptionList } from "./DescriptionList"
|
||||
|
||||
|
||||
export default {
|
||||
component: DescriptionList,
|
||||
title: "Lists/DescriptionList",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
disabled: {
|
||||
control: {type: "boolean"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Default = props => (
|
||||
<DescriptionList {...props}>
|
||||
<DescriptionList.Key>
|
||||
LOL
|
||||
</DescriptionList.Key>
|
||||
<DescriptionList.Value>
|
||||
Laughing out loud
|
||||
</DescriptionList.Value>
|
||||
<DescriptionList.Key>
|
||||
KEK
|
||||
</DescriptionList.Key>
|
||||
<DescriptionList.Value>
|
||||
Equivalent to lol, but said by a member of the Horde
|
||||
</DescriptionList.Value>
|
||||
<DescriptionList.Key>
|
||||
LUL
|
||||
</DescriptionList.Key>
|
||||
<DescriptionList.Value>
|
||||
Equivalent to lol, used by twitch.tv users to send an emoticon with the face of TotalBiscuit
|
||||
</DescriptionList.Value>
|
||||
</DescriptionList>
|
||||
)
|
||||
Default.args = {
|
||||
disabled: false,
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
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 DescriptionListProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function DescriptionList({...props}: DescriptionListProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"dl"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface DescriptionListKeyProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
DescriptionList.Key = function({...props}: DescriptionListKeyProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-key")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"dt"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface DescriptionListValueProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
DescriptionList.Value = function({...props}: DescriptionListValueProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-value")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"dd"} {...props}/>
|
||||
)
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { List } from "./List"
|
||||
|
||||
|
||||
export default {
|
||||
component: List,
|
||||
title: "Lists/List",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
disabled: {
|
||||
control: {type: "boolean"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
export const Unordered = props => (
|
||||
<List {...props}>
|
||||
<List.Item>Io</List.Item>
|
||||
<List.Item>Gyrocopter</List.Item>
|
||||
<List.Item>Chaos Knight</List.Item>
|
||||
</List>
|
||||
)
|
||||
Unordered.args = {
|
||||
disabled: false,
|
||||
ordered: false,
|
||||
}
|
||||
|
||||
|
||||
export const Ordered = Unordered.bind({})
|
||||
Ordered.args = {
|
||||
...Unordered.args,
|
||||
ordered: true,
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
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 ListProps {
|
||||
ordered: boolean,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function List({ordered, ...props}: ListProps): JSX.Element {
|
||||
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list", ordered ? "list-ordered" : "list-unordered")
|
||||
|
||||
return (
|
||||
<BaseElement kind={ordered ? "ol" : "ul"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface ListItemProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
List.Item = function({...props}: ListItemProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-item")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"li"} {...props}/>
|
||||
)
|
||||
}
|
36
src/components/lists/ListDescription.stories.jsx
Normal file
36
src/components/lists/ListDescription.stories.jsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { ListDescription as ListDescriptionComponent } from "./ListDescription"
|
||||
|
||||
|
||||
export default {
|
||||
component: ListDescriptionComponent,
|
||||
title: "Lists/List Description",
|
||||
decorators: [Decorators.Bluelib],
|
||||
}
|
||||
|
||||
|
||||
export const ListDescription = props => (
|
||||
<ListDescriptionComponent {...props}>
|
||||
<ListDescriptionComponent.Term>
|
||||
LOL
|
||||
</ListDescriptionComponent.Term>
|
||||
<ListDescriptionComponent.Details>
|
||||
Laughing out loud
|
||||
</ListDescriptionComponent.Details>
|
||||
<ListDescriptionComponent.Term>
|
||||
KEK
|
||||
</ListDescriptionComponent.Term>
|
||||
<ListDescriptionComponent.Details>
|
||||
Equivalent to lol, but said by a member of the Horde
|
||||
</ListDescriptionComponent.Details>
|
||||
<ListDescriptionComponent.Term>
|
||||
LUL
|
||||
</ListDescriptionComponent.Term>
|
||||
<ListDescriptionComponent.Details>
|
||||
Equivalent to lol, used by twitch.tv users to send an emoticon with the face of TotalBiscuit
|
||||
</ListDescriptionComponent.Details>
|
||||
</ListDescriptionComponent>
|
||||
)
|
||||
ListDescription.args = {}
|
23
src/components/lists/ListDescription.tsx
Normal file
23
src/components/lists/ListDescription.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"
|
||||
import {ListTerm} from "./ListTerm";
|
||||
import {ListDetails} from "./ListDetails";
|
||||
|
||||
|
||||
export interface ListDescriptionProps extends Types.BluelibHTMLProps<HTMLDListElement> {}
|
||||
|
||||
|
||||
export function ListDescription({...props}: ListDescriptionProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list", "list-description")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"dl"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
ListDescription.Term = ListTerm
|
||||
ListDescription.Details = ListDetails
|
17
src/components/lists/ListDetails.tsx
Normal file
17
src/components/lists/ListDetails.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface ListDetailsProps extends Types.BluelibHTMLProps<HTMLElement> {}
|
||||
|
||||
|
||||
export function ListDetails({...props}: ListDetailsProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-details")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"dd"} {...props}/>
|
||||
)
|
||||
}
|
17
src/components/lists/ListItem.tsx
Normal file
17
src/components/lists/ListItem.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface ListItemProps extends Types.BluelibHTMLProps<HTMLLIElement> {}
|
||||
|
||||
|
||||
export function ListItem({...props}: ListItemProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-item")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"li"} {...props}/>
|
||||
)
|
||||
}
|
25
src/components/lists/ListOrdered.stories.jsx
Normal file
25
src/components/lists/ListOrdered.stories.jsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { ListOrdered as ListOrderedComponent } from "./ListOrdered"
|
||||
import { ListItem } from "./ListItem"
|
||||
|
||||
|
||||
export default {
|
||||
component: ListOrderedComponent,
|
||||
subcomponents: {ListItem},
|
||||
title: "Lists/List Ordered",
|
||||
decorators: [Decorators.Bluelib],
|
||||
}
|
||||
|
||||
|
||||
export const ListOrdered = props => (
|
||||
<ListOrderedComponent {...props}>
|
||||
<ListOrderedComponent.Item>Gold</ListOrderedComponent.Item>
|
||||
<ListOrderedComponent.Item>Silver</ListOrderedComponent.Item>
|
||||
<ListOrderedComponent.Item>Bronze</ListOrderedComponent.Item>
|
||||
<ListOrderedComponent.Item>Iron</ListOrderedComponent.Item>
|
||||
<ListOrderedComponent.Item>Wood</ListOrderedComponent.Item>
|
||||
</ListOrderedComponent>
|
||||
)
|
||||
ListOrdered.args = {}
|
21
src/components/lists/ListOrdered.tsx
Normal file
21
src/components/lists/ListOrdered.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {ListItem} from "./ListItem";
|
||||
|
||||
|
||||
export interface ListOrderedProps extends Types.BluelibHTMLProps<HTMLOListElement> {}
|
||||
|
||||
|
||||
export function ListOrdered({...props}: ListOrderedProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list", "list-ordered")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"ol"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
ListOrdered.Item = ListItem
|
17
src/components/lists/ListTerm.tsx
Normal file
17
src/components/lists/ListTerm.tsx
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
export interface ListTermProps extends Types.BluelibHTMLProps<HTMLElement> {}
|
||||
|
||||
|
||||
export function ListTerm({...props}: ListTermProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-term")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"dt"} {...props}/>
|
||||
)
|
||||
}
|
24
src/components/lists/ListUnordered.stories.jsx
Normal file
24
src/components/lists/ListUnordered.stories.jsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { ListUnordered as ListUnorderedComponent } from "./ListUnordered"
|
||||
import { ListItem } from "./ListItem"
|
||||
|
||||
|
||||
export default {
|
||||
component: ListUnorderedComponent,
|
||||
subcomponents: {ListItem},
|
||||
title: "Lists/List Unordered",
|
||||
decorators: [Decorators.Bluelib],
|
||||
}
|
||||
|
||||
|
||||
export const ListUnordered = props => (
|
||||
<ListUnorderedComponent {...props}>
|
||||
<ListUnorderedComponent.Item>Mario</ListUnorderedComponent.Item>
|
||||
<ListUnorderedComponent.Item>Luigi</ListUnorderedComponent.Item>
|
||||
<ListUnorderedComponent.Item>Baby Mario</ListUnorderedComponent.Item>
|
||||
<ListUnorderedComponent.Item>Baby Luigi</ListUnorderedComponent.Item>
|
||||
</ListUnorderedComponent>
|
||||
)
|
||||
ListUnordered.args = {}
|
21
src/components/lists/ListUnordered.tsx
Normal file
21
src/components/lists/ListUnordered.tsx
Normal file
|
@ -0,0 +1,21 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {ListItem} from "./ListItem";
|
||||
|
||||
|
||||
export interface ListUnorderedProps extends Types.BluelibHTMLProps<HTMLUListElement> {}
|
||||
|
||||
|
||||
export function ListUnordered({...props}: ListUnorderedProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list", "list-unordered")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"ul"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
ListUnordered.Item = ListItem
|
|
@ -1,13 +1,11 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {Panel} from "./Panel";
|
||||
import {Panel, PanelProps} from "./Panel";
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface BoxProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
export interface BoxProps extends PanelProps {}
|
||||
|
||||
|
||||
export function Box({...props}: BoxProps): JSX.Element {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {Panel} from "./Panel";
|
||||
import {Panel, PanelProps} from "./Panel";
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface DialogProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
export interface DialogProps extends PanelProps {}
|
||||
|
||||
|
||||
export function Dialog({...props}: DialogProps): JSX.Element {
|
||||
|
|
|
@ -5,9 +5,7 @@ import {BaseElement} from "../BaseElement"
|
|||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface PanelProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
export interface PanelProps extends Types.BluelibHTMLProps<HTMLElement> {}
|
||||
|
||||
|
||||
export function Panel({...props}: PanelProps): JSX.Element {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {Panel} from "./Panel";
|
||||
import {Panel, PanelProps} from "./Panel";
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
interface ParenthesisProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
export interface ParenthesisProps extends PanelProps {}
|
||||
|
||||
|
||||
export function Parenthesis({...props}: ParenthesisProps): JSX.Element {
|
||||
|
|
|
@ -6,13 +6,8 @@ import { Separator } from "./Separator"
|
|||
|
||||
export default {
|
||||
component: Separator,
|
||||
title: "Separator/Separator",
|
||||
title: "Separators/Separator",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,20 +2,19 @@ import * as React from "react"
|
|||
import * as ReactDOM from "react-dom"
|
||||
import * as Decorators from "../../utils/Decorators"
|
||||
import { Table } from "./Table"
|
||||
import { TableCaption } from "./TableCaption"
|
||||
import { TableHeader } from "./TableHeader"
|
||||
import { TableBody } from "./TableBody"
|
||||
import { TableFooter } from "./TableFooter"
|
||||
import { TableRow } from "./TableRow"
|
||||
import { TableCell } from "./TableCell"
|
||||
|
||||
|
||||
export default {
|
||||
component: Table,
|
||||
subcomponents: {TableCaption, TableHeader, TableBody, TableFooter, TableRow, TableCell},
|
||||
title: "Tables/Table",
|
||||
decorators: [Decorators.Bluelib],
|
||||
argTypes: {
|
||||
customColor: {
|
||||
control: {type: "color"},
|
||||
},
|
||||
disabled: {
|
||||
control: {type: "boolean"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,7 +149,7 @@ export const TierList = props => (
|
|||
S
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
span
|
||||
<span>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
|
@ -158,7 +157,7 @@ export const TierList = props => (
|
|||
A
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
a
|
||||
<a>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
|
@ -166,7 +165,7 @@ export const TierList = props => (
|
|||
B
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
body
|
||||
<body>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
|
@ -174,7 +173,7 @@ export const TierList = props => (
|
|||
C
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
caption
|
||||
<caption>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
|
|
|
@ -3,11 +3,15 @@ import * as ReactDOM from "react-dom"
|
|||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {TableCaption} from "./TableCaption";
|
||||
import {TableHeader} from "./TableHeader";
|
||||
import {TableBody} from "./TableBody";
|
||||
import {TableFooter} from "./TableFooter";
|
||||
import {TableRow} from "./TableRow";
|
||||
import {TableCell} from "./TableCell";
|
||||
|
||||
|
||||
interface TableProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
interface TableProps extends Types.BluelibHTMLProps<HTMLTableElement> {}
|
||||
|
||||
|
||||
export function Table({...props}: TableProps): JSX.Element {
|
||||
|
@ -18,97 +22,9 @@ export function Table({...props}: TableProps): JSX.Element {
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
interface TableCaptionProps {
|
||||
position: "top" | "bottom",
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
const TABLE_CAPTION_CLASSES = {
|
||||
top: "table-caption-top",
|
||||
bottom: "table-caption-bottom",
|
||||
}
|
||||
|
||||
|
||||
Table.Caption = function({position, ...props}: TableCaptionProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-caption", TABLE_CAPTION_CLASSES[position])
|
||||
|
||||
return (
|
||||
<BaseElement kind={"caption"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface TableHeaderProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
Table.Header = function ({position, ...props}: TableHeaderProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-header")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"thead"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface TableBodyProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
Table.Body = function ({position, ...props}: TableBodyProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-body")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"tbody"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface TableFooterProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
Table.Footer = function ({position, ...props}: TableFooterProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-footer")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"tfoot"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface TableRowProps {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
Table.Row = function ({...props}: TableRowProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-row")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"tr"} {...props}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
interface TableCellProps {
|
||||
head?: boolean,
|
||||
mark?: boolean,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
Table.Cell = function ({head = false, mark = false, ...props}: TableCellProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, head ? "table-head" : "table-data", mark ? "table-mark" : "")
|
||||
|
||||
return (
|
||||
<BaseElement kind={head ? "th" : "td"} {...props}/>
|
||||
)
|
||||
}
|
||||
Table.Caption = TableCaption
|
||||
Table.Header = TableHeader
|
||||
Table.Body = TableBody
|
||||
Table.Footer = TableFooter
|
||||
Table.Row = TableRow
|
||||
Table.Cell = TableCell
|
||||
|
|
19
src/components/tables/TableBody.tsx
Normal file
19
src/components/tables/TableBody.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {Table} from "./Table";
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
|
||||
interface TableBodyProps extends Types.BluelibHTMLProps<HTMLTableSectionElement> {}
|
||||
|
||||
|
||||
export function TableBody({...props}: TableBodyProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-body")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"tbody"} {...props}/>
|
||||
)
|
||||
}
|
26
src/components/tables/TableCaption.tsx
Normal file
26
src/components/tables/TableCaption.tsx
Normal file
|
@ -0,0 +1,26 @@
|
|||
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 TableCaptionProps extends Types.BluelibHTMLProps<HTMLTableCaptionElement> {
|
||||
position: "top" | "bottom",
|
||||
}
|
||||
|
||||
|
||||
const TABLE_CAPTION_CLASSES = {
|
||||
top: "table-caption-top",
|
||||
bottom: "table-caption-bottom",
|
||||
}
|
||||
|
||||
|
||||
export function TableCaption({position = "top", ...props}: TableCaptionProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-caption", TABLE_CAPTION_CLASSES[position])
|
||||
|
||||
return (
|
||||
<BaseElement kind={"caption"} {...props}/>
|
||||
)
|
||||
}
|
23
src/components/tables/TableCell.tsx
Normal file
23
src/components/tables/TableCell.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"
|
||||
import {Table} from "./Table";
|
||||
|
||||
|
||||
interface TableCellProps extends Types.BluelibHTMLProps<HTMLTableCellElement> {
|
||||
head?: boolean,
|
||||
mark?: boolean,
|
||||
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function TableCell({head = false, mark = false, ...props}: TableCellProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, head ? "table-head" : "table-data", mark ? "table-mark" : "")
|
||||
|
||||
return (
|
||||
<BaseElement kind={head ? "th" : "td"} {...props}/>
|
||||
)
|
||||
}
|
19
src/components/tables/TableFooter.tsx
Normal file
19
src/components/tables/TableFooter.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {Table} from "./Table";
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
|
||||
interface TableFooterProps extends Types.BluelibHTMLProps<HTMLTableSectionElement> {}
|
||||
|
||||
|
||||
export function TableFooter({...props}: TableFooterProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-footer")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"tfoot"} {...props}/>
|
||||
)
|
||||
}
|
19
src/components/tables/TableHeader.tsx
Normal file
19
src/components/tables/TableHeader.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {Table} from "./Table";
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
|
||||
|
||||
|
||||
interface TableHeaderProps extends Types.BluelibHTMLProps<HTMLTableSectionElement> {}
|
||||
|
||||
|
||||
export function TableHeader({...props}: TableHeaderProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-header")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"thead"} {...props}/>
|
||||
)
|
||||
}
|
20
src/components/tables/TableRow.tsx
Normal file
20
src/components/tables/TableRow.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import * as React from "react"
|
||||
import * as ReactDOM from "react-dom"
|
||||
import * as Types from "../../types"
|
||||
import {BaseElement} from "../BaseElement"
|
||||
import mergeClassNames from "classnames"
|
||||
import {Table} from "./Table";
|
||||
|
||||
|
||||
interface TableRowProps extends Types.BluelibHTMLProps<HTMLTableRowElement> {
|
||||
[props: string]: any,
|
||||
}
|
||||
|
||||
|
||||
export function TableRow({...props}: TableRowProps): JSX.Element {
|
||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-row")
|
||||
|
||||
return (
|
||||
<BaseElement kind={"tr"} {...props}/>
|
||||
)
|
||||
}
|
31
src/types.ts
31
src/types.ts
|
@ -1,13 +1,24 @@
|
|||
import * as React from "react";
|
||||
|
||||
export type {Argument as ClassNames} from "classnames"
|
||||
|
||||
// export type IntrinsicComponentKind = JSX.IntrinsicElements
|
||||
// export type FunctionComponentKind = (props: object) => JSX.Element
|
||||
// export type ClassComponentKind = typeof React.Component
|
||||
// export type ComponentKind = IntrinsicComponentKind | FunctionComponentKind | ClassComponentKind
|
||||
export type ComponentKind = any
|
||||
import * as React from "react"
|
||||
import Color from "color"
|
||||
import {Argument as ClassNamesArgument} from "classnames"
|
||||
|
||||
|
||||
export type ClassNames = ClassNamesArgument
|
||||
|
||||
export type UseStateContext<S> = React.Context<null | [S, React.Dispatch<React.SetStateAction<S>>]>
|
||||
|
||||
export type State<Value> = [Value, React.Dispatch<React.SetStateAction<Value>>]
|
||||
export type StateContext<Value> = React.Context<State<Value> | undefined>
|
||||
|
||||
|
||||
export interface BluelibProps {
|
||||
bluelibClassNames?: ClassNames,
|
||||
customColor?: typeof Color,
|
||||
disabled?: boolean,
|
||||
}
|
||||
|
||||
|
||||
export interface BluelibHTMLProps<Element extends HTMLElement> extends BluelibProps, React.HTMLProps<Element> {}
|
||||
|
||||
|
||||
export type InputValue = readonly string[] | string | number | undefined
|
||||
export type Validity = boolean | null
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { Bluelib as BluelibComponent } from "../components/Bluelib"
|
||||
import { Box as BoxComponent } from "../components/panels/Box"
|
||||
import { Form as FormComponent } from "../components/forms/Form"
|
||||
|
||||
|
||||
export const Bluelib = Story => <BluelibComponent theme={"paper"} style={{backgroundColor: "transparent"}}><Story/></BluelibComponent>
|
||||
|
||||
export const Fill = Story => <div style={{height: "100vh"}}><Story/></div>
|
||||
|
||||
export const Box = Story => <BoxComponent><Story/></BoxComponent>
|
||||
export const Box = Story => <BoxComponent><Story/></BoxComponent>
|
||||
|
||||
export const Form = Story => <FormComponent><Story/></FormComponent>
|
||||
|
|
|
@ -3107,6 +3107,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
|
||||
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==
|
||||
|
||||
"@types/uuid@^8.3.1":
|
||||
version "8.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f"
|
||||
integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==
|
||||
|
||||
"@types/webpack-env@^1.16.0":
|
||||
version "1.16.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.2.tgz#8db514b059c1b2ae14ce9d7bb325296de6a9a0fa"
|
||||
|
@ -13998,7 +14003,7 @@ uuid@^3.3.2, uuid@^3.4.0:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
uuid@^8.3.0:
|
||||
uuid@^8.3.0, uuid@^8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
|
Loading…
Reference in a new issue