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 = {
|
export const parameters = {
|
||||||
actions: {
|
argTypes: {
|
||||||
argTypesRegex: "^on[A-Z][a-z]*$"
|
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/node": "^12.0.0",
|
||||||
"@types/react": "^17.0.0",
|
"@types/react": "^17.0.0",
|
||||||
"@types/react-dom": "^17.0.0",
|
"@types/react-dom": "^17.0.0",
|
||||||
|
"@types/uuid": "^8.3.1",
|
||||||
"classnames": "^2.3.1",
|
"classnames": "^2.3.1",
|
||||||
"color": "https://github.com/Steffo99/color",
|
"color": "https://github.com/Steffo99/color",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"typescript": "^4.1.2",
|
"typescript": "^4.1.2",
|
||||||
|
"uuid": "^8.3.2",
|
||||||
"web-vitals": "^1.0.1"
|
"web-vitals": "^1.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0fe4c9e477a681031c4d62fd9a7c39e94befa849
|
Subproject commit 48722dcbfa0d6e9e1e5fe3bcb84b0be102d5db38
|
|
@ -1,42 +1,23 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../utils/Decorators"
|
import * as Decorators from "../utils/Decorators"
|
||||||
import { BaseElement } from "./BaseElement"
|
import { BaseElement as BaseElementComponent } from "./BaseElement"
|
||||||
import { Bluelib } from "./Bluelib"
|
import { Bluelib } from "./Bluelib"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: BaseElement,
|
component: BaseElementComponent,
|
||||||
title: "Bluelib/BaseElement",
|
title: "Internals/Base Element",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
|
||||||
customColor: {
|
|
||||||
control: {type: "color"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const BaseElement = props => (
|
||||||
<BaseElement kind={"div"} {...props}>
|
<BaseElementComponent kind={"div"} {...props}>
|
||||||
This is a text node child.
|
This is a text node child.
|
||||||
</BaseElement>
|
</BaseElementComponent>
|
||||||
)
|
)
|
||||||
Default.args = {
|
BaseElement.args = {
|
||||||
kind: "div",
|
kind: "div",
|
||||||
disabled: false,
|
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"
|
import mergeClassNames, {Argument as ClassNamesArgument} from "classnames"
|
||||||
|
|
||||||
|
|
||||||
export interface BaseElementProps {
|
export interface BaseElementProps extends React.HTMLProps<any> {
|
||||||
kind: Types.ComponentKind,
|
kind: string,
|
||||||
bluelibClassNames?: Types.ClassNames,
|
bluelibClassNames?: Types.ClassNames,
|
||||||
customColor?: typeof Color,
|
|
||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
|
customColor?: typeof Color,
|
||||||
[props: string]: any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
// 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
|
// 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
|
// Map regular class names to module class names
|
||||||
bluelibClassNames = BluelibMapper.rootToModule(bluelibClassNames)
|
bluelibClassNames = BluelibMapper.rootToModule(bluelibClassNames)
|
||||||
props.className = mergeClassNames(props.className, bluelibClassNames)
|
props.className = mergeClassNames(props.className, bluelibClassNames)
|
||||||
|
|
||||||
// Dynamically determine the element kind
|
return React.createElement(kind, props)
|
||||||
const Kind = kind
|
|
||||||
|
|
||||||
return <Kind {...props}/>
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Color from "color"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Bluelib,
|
component: Bluelib,
|
||||||
title: "Bluelib/Bluelib",
|
title: "Core/Bluelib",
|
||||||
decorators: [Decorators.Fill],
|
decorators: [Decorators.Fill],
|
||||||
parameters: {
|
parameters: {
|
||||||
layout: "fullscreen",
|
layout: "fullscreen",
|
||||||
|
|
|
@ -19,7 +19,7 @@ const BuiltinThemes = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface BluelibProps {
|
export interface BluelibProps extends Types.BluelibHTMLProps<HTMLDivElement> {
|
||||||
theme: "paper" | "royalblue" | "hacker" | "sophon",
|
theme: "paper" | "royalblue" | "hacker" | "sophon",
|
||||||
|
|
||||||
backgroundColor?: typeof Color,
|
backgroundColor?: typeof Color,
|
||||||
|
@ -38,8 +38,6 @@ export interface BluelibProps {
|
||||||
magentaColor?: typeof Color,
|
magentaColor?: typeof Color,
|
||||||
grayColor?: typeof Color,
|
grayColor?: typeof Color,
|
||||||
polarity?: number,
|
polarity?: number,
|
||||||
|
|
||||||
[props: string]: any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +79,10 @@ export function Bluelib({
|
||||||
if(blueColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("blue", blueColor)}
|
if(blueColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("blue", blueColor)}
|
||||||
if(magentaColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("magenta", magentaColor)}
|
if(magentaColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("magenta", magentaColor)}
|
||||||
if(grayColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("gray", grayColor)}
|
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 (
|
return (
|
||||||
<BaseElement
|
<BaseElement
|
||||||
|
|
|
@ -20,16 +20,14 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const Basic = props => (
|
||||||
<Chapter {...props}>
|
<Chapter {...props}>
|
||||||
<Box>First</Box>
|
<Box>First</Box>
|
||||||
<Box>Second</Box>
|
<Box>Second</Box>
|
||||||
<Box>Third</Box>
|
<Box>Third</Box>
|
||||||
</Chapter>
|
</Chapter>
|
||||||
)
|
)
|
||||||
Default.args = {
|
Basic.args = {}
|
||||||
disabled: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const AutoWrap = props => (
|
export const AutoWrap = props => (
|
||||||
|
@ -46,14 +44,18 @@ export const AutoWrap = props => (
|
||||||
<Box>Tenth</Box>
|
<Box>Tenth</Box>
|
||||||
<Box>Eleventh</Box>
|
<Box>Eleventh</Box>
|
||||||
<Box>Twelfth</Box>
|
<Box>Twelfth</Box>
|
||||||
<Box>Thirtheenth</Box>
|
<Box>Thirteenth</Box>
|
||||||
<Box>Fourtheenth</Box>
|
<Box>Fourteenth</Box>
|
||||||
<Box>Fiftheenth</Box>
|
<Box>Fifteenth</Box>
|
||||||
|
<Box>Sixteenth</Box>
|
||||||
|
<Box>Seventeenth</Box>
|
||||||
|
<Box>Eighteenth</Box>
|
||||||
|
<Box>Ninteenth</Box>
|
||||||
|
<Box>Ninteenth</Box>
|
||||||
|
<Box>Twentieth</Box>
|
||||||
</Chapter>
|
</Chapter>
|
||||||
)
|
)
|
||||||
AutoWrap.args = {
|
AutoWrap.args = {}
|
||||||
disabled: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const ForceWrap = props => (
|
export const ForceWrap = props => (
|
||||||
|
@ -65,6 +67,4 @@ export const ForceWrap = props => (
|
||||||
<Box>Fourth</Box>
|
<Box>Fourth</Box>
|
||||||
</Chapter>
|
</Chapter>
|
||||||
)
|
)
|
||||||
ForceWrap.args = {
|
ForceWrap.args = {}
|
||||||
disabled: false,
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,11 +3,10 @@ import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {BaseElement} from "../BaseElement"
|
import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
import {ChapterForceWrap} from "./ChapterForceWrap";
|
||||||
|
|
||||||
|
|
||||||
interface ChapterProps {
|
export interface ChapterProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function Chapter({...props}: ChapterProps): JSX.Element {
|
export function Chapter({...props}: ChapterProps): JSX.Element {
|
||||||
|
@ -19,15 +18,4 @@ export function Chapter({...props}: ChapterProps): JSX.Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface ChapterForceWrapProps {
|
Chapter.ForceWrap = ChapterForceWrap
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Chapter.ForceWrap = function({...props}: ChapterForceWrapProps): JSX.Element {
|
|
||||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "chapter-forcewrap")
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BaseElement kind={"div"} {...props}/>
|
|
||||||
)
|
|
||||||
}
|
|
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}/>
|
<Image {...props}/>
|
||||||
)
|
)
|
||||||
NoLimit.args = {
|
FullLimit.args = {
|
||||||
src: PineappleWithSunglasses,
|
src: PineappleWithSunglasses,
|
||||||
|
|
||||||
limit: "no",
|
limit: "no",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const HalfLimit = NoLimit.bind({})
|
export const HalfLimit = FullLimit.bind({})
|
||||||
HalfLimit.args = {
|
HalfLimit.args = {
|
||||||
...NoLimit.args,
|
...FullLimit.args,
|
||||||
|
|
||||||
limit: "half",
|
limit: "half",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const QuarterLimit = NoLimit.bind({})
|
export const QuarterLimit = FullLimit.bind({})
|
||||||
QuarterLimit.args = {
|
QuarterLimit.args = {
|
||||||
...NoLimit.args,
|
...FullLimit.args,
|
||||||
|
|
||||||
limit: "quarter",
|
limit: "quarter",
|
||||||
}
|
}
|
|
@ -5,29 +5,25 @@ import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface ImageProps {
|
export interface ImageProps extends Types.BluelibHTMLProps<HTMLImageElement> {
|
||||||
src: string,
|
limit?: "full" | "half" | "quarter",
|
||||||
limit?: "no" | "half" | "quarter",
|
|
||||||
|
|
||||||
[props: string]: any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const LIMIT_CLASSES = {
|
const LIMIT_CLASSES = {
|
||||||
no: "",
|
full: "",
|
||||||
half: "image-limit-half",
|
half: "image-limit-half",
|
||||||
quarter: "image-limit-quarter",
|
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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "image")
|
||||||
|
|
||||||
if(limit) {
|
if(limit) {
|
||||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, LIMIT_CLASSES[limit])
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, LIMIT_CLASSES[limit])
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Capture the src and make the image clickable
|
|
||||||
return (
|
return (
|
||||||
<BaseElement kind={"img"} {...props}/>
|
<BaseElement kind={"img"} {...props}/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,25 +1,24 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
import * as Decorators from "../../utils/Decorators"
|
||||||
import { Area } from "./Area"
|
import { Area as AreaComponent } from "./Area"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Area,
|
component: AreaComponent,
|
||||||
title: "Inputs/Area",
|
title: "Inputs/Area",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
customColor: {
|
onChange: {action: "Change"},
|
||||||
control: {type: "color"},
|
onSimpleChange: {action: "SimpleChange"},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const Area = props => (
|
||||||
<Area {...props}/>
|
<AreaComponent {...props}/>
|
||||||
)
|
)
|
||||||
Default.args = {
|
Area.args = {
|
||||||
placeholder: "Enter multiline text here\n\nThis component can be resized",
|
placeholder: "Enter multiline text here\n\nThis component can be resized",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
required: false,
|
required: false,
|
||||||
|
|
|
@ -5,37 +5,25 @@ import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface AreaProps {
|
export interface AreaProps extends Types.BluelibHTMLProps<HTMLTextAreaElement> {
|
||||||
placeholder: string,
|
onChange?: (event: React.ChangeEvent<HTMLTextAreaElement>) => void,
|
||||||
required?: boolean,
|
onSimpleChange?: (value: string) => void,
|
||||||
disabled?: boolean,
|
|
||||||
|
|
||||||
onChange: (contents: string) => boolean,
|
|
||||||
value?: string,
|
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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-area")
|
||||||
|
|
||||||
const onChangeWrapper = React.useCallback(
|
const onChangeWrapped = React.useCallback(
|
||||||
|
event => {
|
||||||
(event: React.ChangeEvent<HTMLTextAreaElement>): boolean => {
|
if(onChange) onChange(event)
|
||||||
const contents = event.target.value
|
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||||
|
|
||||||
if(onChange) {
|
|
||||||
return onChange(contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
[onChange, onSimpleChange]
|
||||||
[onChange]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
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 React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
import * as Decorators from "../../utils/Decorators"
|
||||||
import { Checkbox } from "./Checkbox"
|
import { Checkbox as CheckboxComponent } from "./Checkbox"
|
||||||
import { Box } from "../panels/Box"
|
import { Box } from "../panels/Box"
|
||||||
import { BaseElement } from "../BaseElement"
|
import { BaseElement } from "../BaseElement"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Checkbox,
|
component: CheckboxComponent,
|
||||||
title: "Inputs/Checkbox",
|
title: "Inputs/Checkbox",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
customColor: {
|
onChange: {action: "Change"},
|
||||||
control: {type: "color"},
|
onSimpleChange: {action: "SimpleChange"},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const Checkbox = props => (
|
||||||
<Checkbox value={"zero"} {...props}/>
|
<CheckboxComponent {...props}/>
|
||||||
)
|
)
|
||||||
|
Checkbox.args = {
|
||||||
|
name: "what",
|
||||||
|
value: "this-checkbox-right-here",
|
||||||
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"
|
|
||||||
}
|
}
|
||||||
ThreeCheckboxes.argTypes = {
|
|
||||||
customColor: {
|
|
||||||
control: {type: "color"},
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
control: {type: "null"},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -5,38 +5,26 @@ import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface CheckboxProps {
|
export interface CheckboxProps extends Types.BluelibHTMLProps<HTMLInputElement> {
|
||||||
disabled?: boolean,
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||||
|
onSimpleChange?: (value: string, checked: boolean) => void,
|
||||||
onChange?: (value: string, checked: boolean) => boolean,
|
checked?: boolean,
|
||||||
|
|
||||||
name: string,
|
|
||||||
value: string,
|
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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-checkbox")
|
||||||
|
|
||||||
const onChangeWrapper = React.useCallback(
|
const onChangeWrapped = React.useCallback(
|
||||||
|
event => {
|
||||||
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
if(onChange) onChange(event)
|
||||||
const checked = event.target.checked
|
if(onSimpleChange) onSimpleChange(event.target.value, event.target.checked)
|
||||||
const value = event.target.value
|
|
||||||
|
|
||||||
if(onChange) {
|
|
||||||
return onChange(value, checked)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
[onChange, onSimpleChange]
|
||||||
[onChange]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
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 React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
import * as Decorators from "../../utils/Decorators"
|
||||||
import { Field } from "./Field"
|
import { Field as FieldComponent } from "./Field"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Field,
|
component: FieldComponent,
|
||||||
title: "Inputs/Field",
|
title: "Inputs/Field",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
customColor: {
|
onChange: {action: "Change"},
|
||||||
control: {type: "color"},
|
onSimpleChange: {action: "SimpleChange"},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const Field = props => (
|
||||||
<Field {...props}/>
|
<FieldComponent {...props}/>
|
||||||
)
|
)
|
||||||
Default.args = {
|
Field.args = {
|
||||||
placeholder: "Enter text here",
|
placeholder: "Enter text here",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
required: false,
|
required: false,
|
||||||
|
|
|
@ -5,37 +5,25 @@ import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface FieldProps {
|
export interface FieldProps extends Types.BluelibHTMLProps<HTMLInputElement> {
|
||||||
placeholder: string,
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||||
required?: boolean,
|
onSimpleChange?: (value: string) => void,
|
||||||
disabled?: boolean,
|
|
||||||
|
|
||||||
onChange: (contents: string) => boolean,
|
|
||||||
value?: string,
|
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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-field")
|
||||||
|
|
||||||
const onChangeWrapper = React.useCallback(
|
const onChangeWrapped = React.useCallback(
|
||||||
|
event => {
|
||||||
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
if(onChange) onChange(event)
|
||||||
const contents = event.target.value
|
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||||
|
|
||||||
if(onChange) {
|
|
||||||
return onChange(contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
[onChange, onSimpleChange]
|
||||||
[onChange]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
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 {
|
export default {
|
||||||
component: Multiselect,
|
component: Multiselect,
|
||||||
|
subcomponents: {Option, OptionGroup},
|
||||||
title: "Inputs/Multiselect",
|
title: "Inputs/Multiselect",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
customColor: {
|
onChange: {action: "Change"},
|
||||||
control: {type: "color"},
|
onSimpleChange: {action: "SimpleChange"},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const Basic = props => (
|
||||||
<Multiselect {...props}>
|
<Multiselect {...props}>
|
||||||
<Option label={"Yes"}/>
|
<Multiselect.Option value={"Yes"}/>
|
||||||
<Option label={"Maybe"}/>
|
<Multiselect.Option value={"Maybe"}/>
|
||||||
<Option label={"No"}/>
|
<Multiselect.Option value={"No"}/>
|
||||||
</Multiselect>
|
</Multiselect>
|
||||||
)
|
)
|
||||||
Default.args = {
|
Basic.args = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const WithGroups = props => (
|
export const WithGroups = props => (
|
||||||
<Multiselect {...props}>
|
<Multiselect {...props}>
|
||||||
<OptionGroup label={"A"}>
|
<Multiselect.Group label={"A"}>
|
||||||
<Option label={"Anchor"}/>
|
<Multiselect.Option value={"Anchor"}/>
|
||||||
<Option label={"Angel"}/>
|
<Multiselect.Option value={"Angel"}/>
|
||||||
<Option label={"Anti-air"}/>
|
<Multiselect.Option value={"Anti-air"}/>
|
||||||
</OptionGroup>
|
</Multiselect.Group>
|
||||||
<OptionGroup label={"B"}>
|
<Multiselect.Group label={"B"}>
|
||||||
<Option label={"Banana"}/>
|
<Multiselect.Option value={"Banana"}/>
|
||||||
<Option label={"Boat"}/>
|
<Multiselect.Option value={"Boat"}/>
|
||||||
<Option label={"Bus"}/>
|
<Multiselect.Option value={"Bus"}/>
|
||||||
</OptionGroup>
|
</Multiselect.Group>
|
||||||
</Multiselect>
|
</Multiselect>
|
||||||
)
|
)
|
||||||
WithGroups.args = {
|
WithGroups.args = {
|
||||||
|
|
|
@ -3,39 +3,33 @@ import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {BaseElement} from "../BaseElement"
|
import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
import {Option} from "./Option";
|
||||||
|
import {OptionGroup} from "./OptionGroup";
|
||||||
|
|
||||||
|
|
||||||
interface MultiselectProps {
|
export interface MultiselectProps extends Types.BluelibHTMLProps<HTMLSelectElement> {
|
||||||
disabled?: boolean,
|
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void,
|
||||||
|
onSimpleChange?: (value: string[]) => void,
|
||||||
onChange?: (contents: string[]) => boolean,
|
value?: string[],
|
||||||
|
|
||||||
children: React.ReactNode,
|
|
||||||
|
|
||||||
[props: string]: any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-multiselect")
|
||||||
|
|
||||||
const onChangeWrapper = React.useCallback(
|
const onChangeWrapped = React.useCallback(
|
||||||
|
event => {
|
||||||
(event: React.ChangeEvent<HTMLSelectElement>): boolean => {
|
if(onChange) onChange(event)
|
||||||
const options = Array.from(event.target.selectedOptions)
|
if(onSimpleChange) onSimpleChange(Array.from<HTMLOptionElement>(event.target.selectedOptions).map(option => option.value))
|
||||||
const contents = options.map((option: HTMLOptionElement) => option.value)
|
|
||||||
|
|
||||||
if(onChange) {
|
|
||||||
return onChange(contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
[onChange, onSimpleChange]
|
||||||
[onChange]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
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"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface OptionProps {
|
export interface OptionProps {
|
||||||
label: string,
|
value: string,
|
||||||
|
|
||||||
[props: string]: any,
|
[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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input-option")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BaseElement kind={"option"} {...props}>
|
<BaseElement kind={"option"} {...props}>
|
||||||
{label}
|
{value}
|
||||||
</BaseElement>
|
</BaseElement>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface OptionGroupProps {
|
export interface OptionGroupProps {
|
||||||
label: string,
|
label: string,
|
||||||
|
|
||||||
[props: string]: any,
|
[props: string]: any,
|
||||||
|
|
|
@ -1,50 +1,26 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
import * as Decorators from "../../utils/Decorators"
|
||||||
import { Radio } from "./Radio"
|
import { Radio as RadioComponent } from "./Radio"
|
||||||
import { Box } from "../panels/Box"
|
import { Box } from "../panels/Box"
|
||||||
import { BaseElement } from "../BaseElement"
|
import { BaseElement } from "../BaseElement"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Radio,
|
component: RadioComponent,
|
||||||
title: "Inputs/Radio",
|
title: "Inputs/Radio",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
customColor: {
|
onChange: {action: "Change"},
|
||||||
control: {type: "color"},
|
onSimpleChange: {action: "SimpleChange"},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const Radio = props => (
|
||||||
<Radio value={"zero"} {...props}/>
|
<RadioComponent {...props}/>
|
||||||
)
|
)
|
||||||
|
Radio.args = {
|
||||||
|
name: "what",
|
||||||
|
value: "this-radio-right-here",
|
||||||
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"
|
|
||||||
}
|
}
|
||||||
ThreeRadios.argTypes = {
|
|
||||||
customColor: {
|
|
||||||
control: {type: "color"},
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
control: {type: "null"},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -5,37 +5,26 @@ import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface RadioProps {
|
export interface RadioProps extends Types.BluelibHTMLProps<HTMLInputElement> {
|
||||||
disabled?: boolean,
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void,
|
||||||
|
onSimpleChange?: (value: string) => void,
|
||||||
onChange?: (value: string) => boolean,
|
checked?: boolean,
|
||||||
|
|
||||||
name: string,
|
|
||||||
value: string,
|
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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-radio")
|
||||||
|
|
||||||
const onChangeWrapper = React.useCallback(
|
const onChangeWrapped = React.useCallback(
|
||||||
|
event => {
|
||||||
(event: React.ChangeEvent<HTMLInputElement>): boolean => {
|
if(onChange) onChange(event)
|
||||||
const value = event.target.value
|
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||||
|
|
||||||
if(onChange) {
|
|
||||||
return onChange(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
[onChange, onSimpleChange]
|
||||||
[onChange]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
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 React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
import * as Decorators from "../../utils/Decorators"
|
||||||
import { Select } from "./Select"
|
import { Select, Select as SelectComponent } from "./Select"
|
||||||
import { Option } from "./Option"
|
import { Option } from "./Option"
|
||||||
import { OptionGroup } from "./OptionGroup"
|
import { OptionGroup } from "./OptionGroup"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Select,
|
component: SelectComponent,
|
||||||
title: "Inputs/Select",
|
title: "Inputs/Select",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
customColor: {
|
onChange: {action: "Change"},
|
||||||
control: {type: "color"},
|
onSimpleChange: {action: "SimpleChange"},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const Basic = props => (
|
||||||
<Select {...props}>
|
<SelectComponent {...props}>
|
||||||
<Option label={"Yes"}/>
|
<SelectComponent.Option value={"Yes"}/>
|
||||||
<Option label={"Maybe"}/>
|
<SelectComponent.Option value={"Maybe"}/>
|
||||||
<Option label={"No"}/>
|
<SelectComponent.Option value={"No"}/>
|
||||||
</Select>
|
</SelectComponent>
|
||||||
)
|
)
|
||||||
Default.args = {
|
Basic.args = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const WithGroups = props => (
|
export const WithGroups = props => (
|
||||||
<Select {...props}>
|
<SelectComponent {...props}>
|
||||||
<Option label={"Ungrouped"}/>
|
<SelectComponent.Option value={"Ungrouped"}/>
|
||||||
<OptionGroup label={"A"}>
|
<SelectComponent.Group label={"A"}>
|
||||||
<Option label={"Anchor"}/>
|
<SelectComponent.Option value={"Anchor"}/>
|
||||||
<Option label={"Angel"}/>
|
<SelectComponent.Option value={"Angel"}/>
|
||||||
<Option label={"Anti-air"}/>
|
<SelectComponent.Option value={"Anti-air"}/>
|
||||||
</OptionGroup>
|
</SelectComponent.Group>
|
||||||
<OptionGroup label={"B"}>
|
<SelectComponent.Group label={"B"}>
|
||||||
<Option label={"Banana"}/>
|
<SelectComponent.Option value={"Banana"}/>
|
||||||
<Option label={"Boat"}/>
|
<SelectComponent.Option value={"Boat"}/>
|
||||||
<Option label={"Bus"}/>
|
<SelectComponent.Option value={"Bus"}/>
|
||||||
</OptionGroup>
|
</SelectComponent.Group>
|
||||||
</Select>
|
</SelectComponent>
|
||||||
)
|
)
|
||||||
WithGroups.args = {
|
WithGroups.args = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
|
|
@ -3,40 +3,33 @@ import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {BaseElement} from "../BaseElement"
|
import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
import {SelectContext} from "./SelectContext";
|
import {Option} from "./Option"
|
||||||
|
import {OptionGroup} from "./OptionGroup"
|
||||||
|
|
||||||
|
|
||||||
interface SelectProps {
|
export interface SelectProps extends Types.BluelibHTMLProps<HTMLSelectElement> {
|
||||||
disabled?: boolean,
|
onChange?: (event: React.ChangeEvent<HTMLSelectElement>) => void,
|
||||||
|
onSimpleChange?: (value: string) => void,
|
||||||
onChange?: (contents: string) => boolean,
|
value?: string,
|
||||||
|
|
||||||
children: React.ReactNode,
|
|
||||||
|
|
||||||
[props: string]: any,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-select")
|
||||||
|
|
||||||
const onChangeWrapper = React.useCallback(
|
const onChangeWrapped = React.useCallback(
|
||||||
|
event => {
|
||||||
(event: React.ChangeEvent<HTMLSelectElement>): boolean => {
|
if(onChange) onChange(event)
|
||||||
const contents = event.target.value
|
if(onSimpleChange) onSimpleChange(event.target.value)
|
||||||
|
|
||||||
if(onChange) {
|
|
||||||
return onChange(contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
},
|
},
|
||||||
|
[onChange, onSimpleChange]
|
||||||
[onChange]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
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"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface LayoutProps {
|
export interface BaseLayoutProps extends Types.BluelibHTMLProps<HTMLDivElement> {}
|
||||||
|
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function BaseLayout({...props}: LayoutProps): JSX.Element {
|
export function BaseLayout({...props}: BaseLayoutProps): JSX.Element {
|
||||||
|
|
||||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout")
|
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout")
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
import * as Decorators from "../../utils/Decorators"
|
||||||
import { LayoutFill } from "./LayoutFill"
|
import { LayoutFill as LayoutFillComponent } from "./LayoutFill"
|
||||||
import { Bluelib } from "../Bluelib"
|
import { LayoutFillSingle } from "./LayoutFillSingle"
|
||||||
import { Box } from "../panels/Box"
|
import { Box } from "../panels/Box"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: LayoutFill,
|
component: LayoutFillComponent,
|
||||||
title: "Layouts/LayoutFill",
|
subcomponents: {LayoutFillSingle},
|
||||||
|
title: "Layouts/Layout Fill",
|
||||||
decorators: [Decorators.Bluelib, Decorators.Fill],
|
decorators: [Decorators.Bluelib, Decorators.Fill],
|
||||||
parameters: {
|
parameters: {
|
||||||
layout: "fullscreen",
|
layout: "fullscreen",
|
||||||
|
@ -16,13 +17,13 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const LayoutFill = props => (
|
||||||
<LayoutFill {...props}>
|
<LayoutFillComponent {...props}>
|
||||||
<LayoutFill.Single>
|
<LayoutFillComponent.Single>
|
||||||
<Box>
|
<Box>
|
||||||
Single
|
Single
|
||||||
</Box>
|
</Box>
|
||||||
</LayoutFill.Single>
|
</LayoutFillComponent.Single>
|
||||||
</LayoutFill>
|
</LayoutFillComponent>
|
||||||
)
|
)
|
||||||
Default.args = {}
|
LayoutFill.args = {}
|
||||||
|
|
|
@ -3,12 +3,11 @@ import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {BaseElement} from "../BaseElement"
|
import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
import {BaseLayout} from "./BaseLayout";
|
import {BaseLayout, BaseLayoutProps} from "./BaseLayout";
|
||||||
|
import {LayoutFillSingle} from "./LayoutFillSingle";
|
||||||
|
|
||||||
|
|
||||||
interface LayoutFillProps {
|
export interface LayoutFillProps extends BaseLayoutProps {}
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function LayoutFill({...props}: LayoutFillProps): JSX.Element {
|
export function LayoutFill({...props}: LayoutFillProps): JSX.Element {
|
||||||
|
@ -18,12 +17,4 @@ export function LayoutFill({...props}: LayoutFillProps): JSX.Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface LayoutFillSingleProps {
|
LayoutFill.Single = LayoutFillSingle
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
LayoutFill.Single = function({...props}: LayoutFillSingleProps): JSX.Element {
|
|
||||||
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-fill-single")
|
|
||||||
|
|
||||||
return <BaseElement kind={"div"} {...props}/>
|
|
||||||
}
|
|
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 React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
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"
|
import { Box } from "../panels/Box"
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: LayoutThreeCol,
|
component: LayoutThreeColComponent,
|
||||||
title: "Layouts/LayoutThreeCol",
|
subcomponents: {LayoutThreeColLeft, LayoutThreeColCenter, LayoutThreeColRight},
|
||||||
|
title: "Layouts/Layout Three Col",
|
||||||
decorators: [Decorators.Bluelib, Decorators.Fill],
|
decorators: [Decorators.Bluelib, Decorators.Fill],
|
||||||
parameters: {
|
parameters: {
|
||||||
layout: "fullscreen",
|
layout: "fullscreen",
|
||||||
|
@ -15,23 +19,23 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const Default = props => (
|
export const LayoutThreeCol = props => (
|
||||||
<LayoutThreeCol {...props}>
|
<LayoutThreeColComponent {...props}>
|
||||||
<LayoutThreeCol.Left>
|
<LayoutThreeColComponent.Left>
|
||||||
<Box>
|
<Box>
|
||||||
Left
|
Left
|
||||||
</Box>
|
</Box>
|
||||||
</LayoutThreeCol.Left>
|
</LayoutThreeColComponent.Left>
|
||||||
<LayoutThreeCol.Center>
|
<LayoutThreeColComponent.Center>
|
||||||
<Box>
|
<Box>
|
||||||
Center
|
Center
|
||||||
</Box>
|
</Box>
|
||||||
</LayoutThreeCol.Center>
|
</LayoutThreeColComponent.Center>
|
||||||
<LayoutThreeCol.Right>
|
<LayoutThreeColComponent.Right>
|
||||||
<Box>
|
<Box>
|
||||||
Right
|
Right
|
||||||
</Box>
|
</Box>
|
||||||
</LayoutThreeCol.Right>
|
</LayoutThreeColComponent.Right>
|
||||||
</LayoutThreeCol>
|
</LayoutThreeColComponent>
|
||||||
)
|
)
|
||||||
Default.args = {}
|
LayoutThreeCol.args = {}
|
||||||
|
|
|
@ -3,10 +3,13 @@ import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {BaseElement} from "../BaseElement"
|
import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
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,
|
[props: string]: any,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,37 +23,6 @@ export function LayoutThreeCol({...props}: LayoutThreeColProps): JSX.Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
interface LayoutThreeColLeftProps {
|
LayoutThreeCol.Left = LayoutThreeColLeft
|
||||||
[props: string]: any,
|
LayoutThreeCol.Center = LayoutThreeColCenter
|
||||||
}
|
LayoutThreeCol.Right = LayoutThreeColRight
|
||||||
|
|
||||||
|
|
||||||
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}/>
|
|
||||||
}
|
|
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 React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {Panel} from "./Panel";
|
import {Panel, PanelProps} from "./Panel";
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface BoxProps {
|
export interface BoxProps extends PanelProps {}
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function Box({...props}: BoxProps): JSX.Element {
|
export function Box({...props}: BoxProps): JSX.Element {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {Panel} from "./Panel";
|
import {Panel, PanelProps} from "./Panel";
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface DialogProps {
|
export interface DialogProps extends PanelProps {}
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function Dialog({...props}: DialogProps): JSX.Element {
|
export function Dialog({...props}: DialogProps): JSX.Element {
|
||||||
|
|
|
@ -5,9 +5,7 @@ import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface PanelProps {
|
export interface PanelProps extends Types.BluelibHTMLProps<HTMLElement> {}
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function Panel({...props}: PanelProps): JSX.Element {
|
export function Panel({...props}: PanelProps): JSX.Element {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as ReactDOM from "react-dom"
|
import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {Panel} from "./Panel";
|
import {Panel, PanelProps} from "./Panel";
|
||||||
import mergeClassNames from "classnames"
|
import mergeClassNames from "classnames"
|
||||||
|
|
||||||
|
|
||||||
interface ParenthesisProps {
|
export interface ParenthesisProps extends PanelProps {}
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function Parenthesis({...props}: ParenthesisProps): JSX.Element {
|
export function Parenthesis({...props}: ParenthesisProps): JSX.Element {
|
||||||
|
|
|
@ -6,13 +6,8 @@ import { Separator } from "./Separator"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: Separator,
|
component: Separator,
|
||||||
title: "Separator/Separator",
|
title: "Separators/Separator",
|
||||||
decorators: [Decorators.Bluelib],
|
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 ReactDOM from "react-dom"
|
||||||
import * as Decorators from "../../utils/Decorators"
|
import * as Decorators from "../../utils/Decorators"
|
||||||
import { Table } from "./Table"
|
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 {
|
export default {
|
||||||
component: Table,
|
component: Table,
|
||||||
|
subcomponents: {TableCaption, TableHeader, TableBody, TableFooter, TableRow, TableCell},
|
||||||
title: "Tables/Table",
|
title: "Tables/Table",
|
||||||
decorators: [Decorators.Bluelib],
|
decorators: [Decorators.Bluelib],
|
||||||
argTypes: {
|
|
||||||
customColor: {
|
|
||||||
control: {type: "color"},
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
control: {type: "boolean"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,7 +149,7 @@ export const TierList = props => (
|
||||||
S
|
S
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
span
|
<span>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
|
@ -158,7 +157,7 @@ export const TierList = props => (
|
||||||
A
|
A
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
a
|
<a>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
|
@ -166,7 +165,7 @@ export const TierList = props => (
|
||||||
B
|
B
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
body
|
<body>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
<Table.Row>
|
<Table.Row>
|
||||||
|
@ -174,7 +173,7 @@ export const TierList = props => (
|
||||||
C
|
C
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
<Table.Cell>
|
<Table.Cell>
|
||||||
caption
|
<caption>
|
||||||
</Table.Cell>
|
</Table.Cell>
|
||||||
</Table.Row>
|
</Table.Row>
|
||||||
</Table.Body>
|
</Table.Body>
|
||||||
|
|
|
@ -3,11 +3,15 @@ import * as ReactDOM from "react-dom"
|
||||||
import * as Types from "../../types"
|
import * as Types from "../../types"
|
||||||
import {BaseElement} from "../BaseElement"
|
import {BaseElement} from "../BaseElement"
|
||||||
import mergeClassNames from "classnames"
|
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 {
|
interface TableProps extends Types.BluelibHTMLProps<HTMLTableElement> {}
|
||||||
[props: string]: any,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function Table({...props}: TableProps): JSX.Element {
|
export function Table({...props}: TableProps): JSX.Element {
|
||||||
|
@ -18,97 +22,9 @@ export function Table({...props}: TableProps): JSX.Element {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Table.Caption = TableCaption
|
||||||
interface TableCaptionProps {
|
Table.Header = TableHeader
|
||||||
position: "top" | "bottom",
|
Table.Body = TableBody
|
||||||
|
Table.Footer = TableFooter
|
||||||
[props: string]: any,
|
Table.Row = TableRow
|
||||||
}
|
Table.Cell = TableCell
|
||||||
|
|
||||||
|
|
||||||
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}/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
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";
|
import * as React from "react"
|
||||||
|
import Color from "color"
|
||||||
export type {Argument as ClassNames} from "classnames"
|
import {Argument as ClassNamesArgument} 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
|
|
||||||
|
|
||||||
|
|
||||||
|
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 { Bluelib as BluelibComponent } from "../components/Bluelib"
|
||||||
import { Box as BoxComponent } from "../components/panels/Box"
|
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 Bluelib = Story => <BluelibComponent theme={"paper"} style={{backgroundColor: "transparent"}}><Story/></BluelibComponent>
|
||||||
|
|
||||||
export const Fill = Story => <div style={{height: "100vh"}}><Story/></div>
|
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"
|
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
|
||||||
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==
|
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":
|
"@types/webpack-env@^1.16.0":
|
||||||
version "1.16.2"
|
version "1.16.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.2.tgz#8db514b059c1b2ae14ce9d7bb325296de6a9a0fa"
|
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"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||||
|
|
||||||
uuid@^8.3.0:
|
uuid@^8.3.0, uuid@^8.3.2:
|
||||||
version "8.3.2"
|
version "8.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||||
|
|
Loading…
Reference in a new issue