diff --git a/.storybook/preview.js b/.storybook/preview.js
index 59142b7..2d67384 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -2,7 +2,43 @@ import { Bluelib } from "../src/components/Bluelib"
export const parameters = {
- actions: {
- argTypesRegex: "^on[A-Z][a-z]*$"
+ argTypes: {
+ bluelibClassNames: {
+ control: {type: "string"},
+ description: "Additional Bluelib classNames to be appended to the element's classNames",
+ table: {category: "Global props"}
+ },
+ customColor: {
+ control: {type: "color"},
+ description: "Apply a Bluelib custom color to the element",
+ table: {category: "Global props"}
+ },
+ disabled: {
+ control: {type: "boolean"},
+ description: "Apply the disabled status to an element",
+ table: {category: "Global props"}
+ }
+ },
+ options: {
+ storySort: {
+ order: [
+ "Core",
+ "Layouts",
+ "Panels",
+ "Chapters",
+ "Separators",
+ "Images",
+ "Tables",
+ "Lists",
+ "Status",
+ "Inputs",
+ "Forms",
+ "Common",
+ "Annotations",
+ "Semantics",
+ "Colors",
+ "Internals",
+ ]
+ }
},
}
\ No newline at end of file
diff --git a/package.json b/package.json
index 4059f96..74bc34d 100644
--- a/package.json
+++ b/package.json
@@ -13,12 +13,14 @@
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
+ "@types/uuid": "^8.3.1",
"classnames": "^2.3.1",
"color": "https://github.com/Steffo99/color",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"typescript": "^4.1.2",
+ "uuid": "^8.3.2",
"web-vitals": "^1.0.1"
},
"devDependencies": {
diff --git a/src/bluelib b/src/bluelib
index 0fe4c9e..48722dc 160000
--- a/src/bluelib
+++ b/src/bluelib
@@ -1 +1 @@
-Subproject commit 0fe4c9e477a681031c4d62fd9a7c39e94befa849
+Subproject commit 48722dcbfa0d6e9e1e5fe3bcb84b0be102d5db38
diff --git a/src/components/BaseElement.stories.jsx b/src/components/BaseElement.stories.jsx
index fe1c55f..40cf948 100644
--- a/src/components/BaseElement.stories.jsx
+++ b/src/components/BaseElement.stories.jsx
@@ -1,42 +1,23 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../utils/Decorators"
-import { BaseElement } from "./BaseElement"
+import { BaseElement as BaseElementComponent } from "./BaseElement"
import { Bluelib } from "./Bluelib"
export default {
- component: BaseElement,
- title: "Bluelib/BaseElement",
+ component: BaseElementComponent,
+ title: "Internals/Base Element",
decorators: [Decorators.Bluelib],
- argTypes: {
- customColor: {
- control: {type: "color"},
- },
- },
}
-export const Default = props => (
-
+export const BaseElement = props => (
+
This is a text node child.
-
+
)
-Default.args = {
+BaseElement.args = {
kind: "div",
disabled: false,
}
-
-
-export const CustomColor = Default.bind({})
-CustomColor.args = {
- ...Default.args,
- customColor: "#ff7f00",
-}
-
-
-export const Disabled = Default.bind({})
-Disabled.args = {
- ...Default.args,
- disabled: true,
-}
\ No newline at end of file
diff --git a/src/components/BaseElement.tsx b/src/components/BaseElement.tsx
index 56feffc..c46ebc1 100644
--- a/src/components/BaseElement.tsx
+++ b/src/components/BaseElement.tsx
@@ -7,29 +7,28 @@ import Color from "color"
import mergeClassNames, {Argument as ClassNamesArgument} from "classnames"
-export interface BaseElementProps {
- kind: Types.ComponentKind,
+export interface BaseElementProps extends React.HTMLProps {
+ kind: string,
bluelibClassNames?: Types.ClassNames,
- customColor?: typeof Color,
disabled?: boolean,
-
- [props: string]: any,
+ customColor?: typeof Color,
}
-export function BaseElement({kind, bluelibClassNames, customColor, ...props}: BaseElementProps): JSX.Element {
+export function BaseElement({kind = "div", bluelibClassNames, disabled = false, customColor, ...props}: BaseElementProps): JSX.Element {
// Set the Bluelib color
- if(customColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("color", customColor)}
+ if(customColor) {
+ props.style = {...props.style, ...Colors.colorToBluelibStyle("color", customColor)}
+ }
// Possibly disable the element
- if(props.disabled) bluelibClassNames = mergeClassNames(bluelibClassNames, "status-disabled")
+ bluelibClassNames = mergeClassNames(bluelibClassNames, disabled ? "status-disabled" : "")
+ // @ts-ignore
+ props.disabled = disabled
// Map regular class names to module class names
bluelibClassNames = BluelibMapper.rootToModule(bluelibClassNames)
props.className = mergeClassNames(props.className, bluelibClassNames)
- // Dynamically determine the element kind
- const Kind = kind
-
- return
+ return React.createElement(kind, props)
}
diff --git a/src/components/Bluelib.stories.jsx b/src/components/Bluelib.stories.jsx
index ef5654c..e09e1d0 100644
--- a/src/components/Bluelib.stories.jsx
+++ b/src/components/Bluelib.stories.jsx
@@ -7,7 +7,7 @@ import Color from "color"
export default {
component: Bluelib,
- title: "Bluelib/Bluelib",
+ title: "Core/Bluelib",
decorators: [Decorators.Fill],
parameters: {
layout: "fullscreen",
diff --git a/src/components/Bluelib.tsx b/src/components/Bluelib.tsx
index d479a5f..a87f86c 100644
--- a/src/components/Bluelib.tsx
+++ b/src/components/Bluelib.tsx
@@ -19,7 +19,7 @@ const BuiltinThemes = {
}
-export interface BluelibProps {
+export interface BluelibProps extends Types.BluelibHTMLProps {
theme: "paper" | "royalblue" | "hacker" | "sophon",
backgroundColor?: typeof Color,
@@ -38,8 +38,6 @@ export interface BluelibProps {
magentaColor?: typeof Color,
grayColor?: typeof Color,
polarity?: number,
-
- [props: string]: any,
}
@@ -81,7 +79,10 @@ export function Bluelib({
if(blueColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("blue", blueColor)}
if(magentaColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("magenta", magentaColor)}
if(grayColor) props.style = {...props.style, ...Colors.colorToBluelibStyle("gray", grayColor)}
- if(polarity) props.style["--bluelib-polarity"] = polarity
+ if(polarity) {
+ // @ts-ignore
+ props.style["--bluelib-polarity"] = polarity
+ }
return (
(
+export const Basic = props => (
First
Second
Third
)
-Default.args = {
- disabled: false,
-}
+Basic.args = {}
export const AutoWrap = props => (
@@ -46,14 +44,18 @@ export const AutoWrap = props => (
Tenth
Eleventh
Twelfth
- Thirtheenth
- Fourtheenth
- Fiftheenth
+ Thirteenth
+ Fourteenth
+ Fifteenth
+ Sixteenth
+ Seventeenth
+ Eighteenth
+ Ninteenth
+ Ninteenth
+ Twentieth
)
-AutoWrap.args = {
- disabled: false,
-}
+AutoWrap.args = {}
export const ForceWrap = props => (
@@ -65,6 +67,4 @@ export const ForceWrap = props => (
Fourth
)
-ForceWrap.args = {
- disabled: false,
-}
+ForceWrap.args = {}
diff --git a/src/components/chapters/Chapter.tsx b/src/components/chapters/Chapter.tsx
index 9abba97..c17e2a2 100644
--- a/src/components/chapters/Chapter.tsx
+++ b/src/components/chapters/Chapter.tsx
@@ -3,11 +3,10 @@ import * as ReactDOM from "react-dom"
import * as Types from "../../types"
import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
+import {ChapterForceWrap} from "./ChapterForceWrap";
-interface ChapterProps {
- [props: string]: any,
-}
+export interface ChapterProps extends Types.BluelibHTMLProps {}
export function Chapter({...props}: ChapterProps): JSX.Element {
@@ -19,15 +18,4 @@ export function Chapter({...props}: ChapterProps): JSX.Element {
}
-interface ChapterForceWrapProps {
- [props: string]: any,
-}
-
-
-Chapter.ForceWrap = function({...props}: ChapterForceWrapProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "chapter-forcewrap")
-
- return (
-
- )
-}
\ No newline at end of file
+Chapter.ForceWrap = ChapterForceWrap
\ No newline at end of file
diff --git a/src/components/chapters/ChapterForceWrap.tsx b/src/components/chapters/ChapterForceWrap.tsx
new file mode 100644
index 0000000..621ceb8
--- /dev/null
+++ b/src/components/chapters/ChapterForceWrap.tsx
@@ -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 {}
+
+
+export function ChapterForceWrap({...props}: ChapterForceWrapProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "chapter-forcewrap")
+
+ return (
+
+ )
+}
diff --git a/src/components/forms/Form.stories.jsx b/src/components/forms/Form.stories.jsx
new file mode 100644
index 0000000..5bb0239
--- /dev/null
+++ b/src/components/forms/Form.stories.jsx
@@ -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 => (
+
+
+
+
+ Enter the details of your characters below.
+
+
+
+
+
+
+
+
+
+
+
+
+ Throw fireball
+ Shoot a magic missile
+ Save character
+
+
+)
+Form.args = {}
diff --git a/src/components/forms/Form.tsx b/src/components/forms/Form.tsx
new file mode 100644
index 0000000..4a833b2
--- /dev/null
+++ b/src/components/forms/Form.tsx
@@ -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 {}
+
+
+export function Form({...props}: FormProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form")
+
+ return (
+
+ )
+}
+
+
+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,
+}
\ No newline at end of file
diff --git a/src/components/forms/FormArea.stories.jsx b/src/components/forms/FormArea.stories.jsx
new file mode 100644
index 0000000..2658647
--- /dev/null
+++ b/src/components/forms/FormArea.stories.jsx
@@ -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 => (
+
+)
+FormArea.args = {
+ label: "Bio",
+}
diff --git a/src/components/forms/FormArea.tsx b/src/components/forms/FormArea.tsx
new file mode 100644
index 0000000..d415d52
--- /dev/null
+++ b/src/components/forms/FormArea.tsx
@@ -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 (
+ {label}}
+ input={}
+ validity={validity}
+ {...pairProps}
+ />
+ )
+}
diff --git a/src/components/forms/FormCheckboxGroup.stories.jsx b/src/components/forms/FormCheckboxGroup.stories.jsx
new file mode 100644
index 0000000..5c58abb
--- /dev/null
+++ b/src/components/forms/FormCheckboxGroup.stories.jsx
@@ -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 => (
+
+)
+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"],
+}
diff --git a/src/components/forms/FormCheckboxGroup.tsx b/src/components/forms/FormCheckboxGroup.tsx
new file mode 100644
index 0000000..76ebeb3
--- /dev/null
+++ b/src/components/forms/FormCheckboxGroup.tsx
@@ -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) => 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(option => (
+
+ ))
+
+ 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 = (
+
+ {checkboxes}
+
+ )
+
+ return (
+ {label}}
+ input={group}
+ validity={validity}
+ bluelibClassNames={bluelibClassNames}
+ customColor={customColor}
+ {...pairProps}
+ />
+ )
+}
diff --git a/src/components/forms/FormField.stories.jsx b/src/components/forms/FormField.stories.jsx
new file mode 100644
index 0000000..967a87b
--- /dev/null
+++ b/src/components/forms/FormField.stories.jsx
@@ -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 => (
+
+)
+FormField.args = {
+ label: "Username",
+}
diff --git a/src/components/forms/FormField.tsx b/src/components/forms/FormField.tsx
new file mode 100644
index 0000000..b9aa0bc
--- /dev/null
+++ b/src/components/forms/FormField.tsx
@@ -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 (
+ {label}}
+ input={}
+ validity={validity}
+ {...pairProps}
+ />
+ )
+}
diff --git a/src/components/forms/FormGroup.tsx b/src/components/forms/FormGroup.tsx
new file mode 100644
index 0000000..d9d0399
--- /dev/null
+++ b/src/components/forms/FormGroup.tsx
@@ -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 {}
+
+
+export function FormGroup({...props}: FormGroupProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form-group")
+
+ return (
+
+ )
+}
diff --git a/src/components/forms/FormLabel.tsx b/src/components/forms/FormLabel.tsx
new file mode 100644
index 0000000..525b22c
--- /dev/null
+++ b/src/components/forms/FormLabel.tsx
@@ -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 {}
+
+
+export function FormLabel({...props}: FormLabelProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form-label")
+
+ return (
+
+ )
+}
diff --git a/src/components/forms/FormMultiselect.stories.jsx b/src/components/forms/FormMultiselect.stories.jsx
new file mode 100644
index 0000000..8d3dec9
--- /dev/null
+++ b/src/components/forms/FormMultiselect.stories.jsx
@@ -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 => (
+
+
+)
+FormMultiselect.args = {
+ label: "Favourite colors",
+}
diff --git a/src/components/forms/FormMultiselect.tsx b/src/components/forms/FormMultiselect.tsx
new file mode 100644
index 0000000..1d08c0f
--- /dev/null
+++ b/src/components/forms/FormMultiselect.tsx
@@ -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 (
+ {label}}
+ input={}
+ validity={validity}
+ {...pairProps}
+ />
+ )
+}
+
+
+FormMultiselect.Option = Multiselect.Option
\ No newline at end of file
diff --git a/src/components/forms/FormPair.tsx b/src/components/forms/FormPair.tsx
new file mode 100644
index 0000000..a2ffa5c
--- /dev/null
+++ b/src/components/forms/FormPair.tsx
@@ -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}
+ >
+}
diff --git a/src/components/forms/FormRadioGroup.stories.jsx b/src/components/forms/FormRadioGroup.stories.jsx
new file mode 100644
index 0000000..67ef021
--- /dev/null
+++ b/src/components/forms/FormRadioGroup.stories.jsx
@@ -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 => (
+
+)
+FormRadioGroup.args = {
+ label: "Size",
+ options: ["XS", "S", "M", "L", "XL"],
+ row: false,
+ disabled: false,
+}
diff --git a/src/components/forms/FormRadioGroup.tsx b/src/components/forms/FormRadioGroup.tsx
new file mode 100644
index 0000000..f44129e
--- /dev/null
+++ b/src/components/forms/FormRadioGroup.tsx
@@ -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) => 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(option => (
+
+ ))
+
+ const onChangeWrapped = React.useCallback(
+ event => {
+ if(onChange) onChange(event)
+ if(onSimpleChange) onSimpleChange(event.target.value)
+ },
+ [onChange, onSimpleChange]
+ )
+
+ const group = (
+
+ {radios}
+
+ )
+
+ return (
+ {label}}
+ input={group}
+ validity={validity}
+ bluelibClassNames={bluelibClassNames}
+ customColor={customColor}
+ {...pairProps}
+ />
+ )
+}
diff --git a/src/components/forms/FormRow.stories.jsx b/src/components/forms/FormRow.stories.jsx
new file mode 100644
index 0000000..71e36ac
--- /dev/null
+++ b/src/components/forms/FormRow.stories.jsx
@@ -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 => (
+
+ By logging in, you accept our Terms of Service.
+
+)
+WithText.args = {}
+
+
+export const WithButtons = props => (
+
+
+
+
+
+)
+WithButtons.args = {}
diff --git a/src/components/forms/FormRow.tsx b/src/components/forms/FormRow.tsx
new file mode 100644
index 0000000..8724a13
--- /dev/null
+++ b/src/components/forms/FormRow.tsx
@@ -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 {}
+
+
+export function FormRow({...props}: FormRowProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "form-row")
+
+ return (
+
+ )
+}
diff --git a/src/components/forms/FormSelect.stories.jsx b/src/components/forms/FormSelect.stories.jsx
new file mode 100644
index 0000000..1684f2a
--- /dev/null
+++ b/src/components/forms/FormSelect.stories.jsx
@@ -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 => (
+
+
+
+
+
+)
+FormSelect.args = {
+ label: "Ready check",
+}
diff --git a/src/components/forms/FormSelect.tsx b/src/components/forms/FormSelect.tsx
new file mode 100644
index 0000000..06d47c0
--- /dev/null
+++ b/src/components/forms/FormSelect.tsx
@@ -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 (
+ {label}}
+ input={}
+ validity={validity}
+ {...pairProps}
+ />
+ )
+}
+
+FormSelect.Option = Select.Option
diff --git a/src/components/images/Image.stories.jsx b/src/components/images/Image.stories.jsx
index 8f392e3..f242a81 100644
--- a/src/components/images/Image.stories.jsx
+++ b/src/components/images/Image.stories.jsx
@@ -17,25 +17,28 @@ export default {
}
-export const NoLimit = props => (
+export const FullLimit = props => (
)
-NoLimit.args = {
+FullLimit.args = {
src: PineappleWithSunglasses,
+
limit: "no",
disabled: false,
}
-export const HalfLimit = NoLimit.bind({})
+export const HalfLimit = FullLimit.bind({})
HalfLimit.args = {
- ...NoLimit.args,
+ ...FullLimit.args,
+
limit: "half",
}
-export const QuarterLimit = NoLimit.bind({})
+export const QuarterLimit = FullLimit.bind({})
QuarterLimit.args = {
- ...NoLimit.args,
+ ...FullLimit.args,
+
limit: "quarter",
}
\ No newline at end of file
diff --git a/src/components/images/Image.tsx b/src/components/images/Image.tsx
index 582f487..132b30f 100644
--- a/src/components/images/Image.tsx
+++ b/src/components/images/Image.tsx
@@ -5,29 +5,25 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface ImageProps {
- src: string,
- limit?: "no" | "half" | "quarter",
-
- [props: string]: any,
+export interface ImageProps extends Types.BluelibHTMLProps {
+ limit?: "full" | "half" | "quarter",
}
const LIMIT_CLASSES = {
- no: "",
+ full: "",
half: "image-limit-half",
quarter: "image-limit-quarter",
}
-export function Image({limit = "no", ...props}: ImageProps): JSX.Element {
+export function Image({limit = "full", ...props}: ImageProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "image")
if(limit) {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, LIMIT_CLASSES[limit])
}
-
- // TODO: Capture the src and make the image clickable
+
return (
)
diff --git a/src/components/inputs/Area.stories.jsx b/src/components/inputs/Area.stories.jsx
index 2f0e2da..b0ddb61 100644
--- a/src/components/inputs/Area.stories.jsx
+++ b/src/components/inputs/Area.stories.jsx
@@ -1,25 +1,24 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
-import { Area } from "./Area"
+import { Area as AreaComponent } from "./Area"
export default {
- component: Area,
+ component: AreaComponent,
title: "Inputs/Area",
decorators: [Decorators.Bluelib],
argTypes: {
- customColor: {
- control: {type: "color"},
- },
+ onChange: {action: "Change"},
+ onSimpleChange: {action: "SimpleChange"},
},
}
-export const Default = props => (
-
+export const Area = props => (
+
)
-Default.args = {
+Area.args = {
placeholder: "Enter multiline text here\n\nThis component can be resized",
disabled: false,
required: false,
diff --git a/src/components/inputs/Area.tsx b/src/components/inputs/Area.tsx
index 9f2d5d2..fc83879 100644
--- a/src/components/inputs/Area.tsx
+++ b/src/components/inputs/Area.tsx
@@ -5,37 +5,25 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface AreaProps {
- placeholder: string,
- required?: boolean,
- disabled?: boolean,
-
- onChange: (contents: string) => boolean,
+export interface AreaProps extends Types.BluelibHTMLProps {
+ onChange?: (event: React.ChangeEvent) => void,
+ onSimpleChange?: (value: string) => void,
value?: string,
-
- [props: string]: any,
}
-export function Area({onChange, ...props}: AreaProps): JSX.Element {
+export function Area({onChange, onSimpleChange, ...props}: AreaProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-area")
- const onChangeWrapper = React.useCallback(
-
- (event: React.ChangeEvent): boolean => {
- const contents = event.target.value
-
- if(onChange) {
- return onChange(contents)
- }
-
- return false
+ const onChangeWrapped = React.useCallback(
+ event => {
+ if(onChange) onChange(event)
+ if(onSimpleChange) onSimpleChange(event.target.value)
},
-
- [onChange]
+ [onChange, onSimpleChange]
)
return (
-
+
)
}
diff --git a/src/components/inputs/Button.stories.jsx b/src/components/inputs/Button.stories.jsx
new file mode 100644
index 0000000..3677eb6
--- /dev/null
+++ b/src/components/inputs/Button.stories.jsx
@@ -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 {children}
+}
+Button.args = {
+ children: "Click me!",
+ disabled: false,
+}
diff --git a/src/components/inputs/Button.tsx b/src/components/inputs/Button.tsx
new file mode 100644
index 0000000..9ca736c
--- /dev/null
+++ b/src/components/inputs/Button.tsx
@@ -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 {
+ onClick?: (event: React.MouseEvent) => 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 (
+ {children}
+ )
+}
diff --git a/src/components/inputs/Checkbox.stories.jsx b/src/components/inputs/Checkbox.stories.jsx
index 1e6e145..9c19cae 100644
--- a/src/components/inputs/Checkbox.stories.jsx
+++ b/src/components/inputs/Checkbox.stories.jsx
@@ -1,50 +1,26 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
-import { Checkbox } from "./Checkbox"
+import { Checkbox as CheckboxComponent } from "./Checkbox"
import { Box } from "../panels/Box"
import { BaseElement } from "../BaseElement"
export default {
- component: Checkbox,
+ component: CheckboxComponent,
title: "Inputs/Checkbox",
decorators: [Decorators.Bluelib],
argTypes: {
- customColor: {
- control: {type: "color"},
- },
+ onChange: {action: "Change"},
+ onSimpleChange: {action: "SimpleChange"},
},
}
-export const Default = props => (
-
+export const Checkbox = props => (
+
)
-
-
-
-export const ThreeCheckboxes = props => (
-
-
- Suicune
-
-
- Raikou
-
-
- Entei
-
-
-)
-ThreeCheckboxes.args = {
- name: "example"
+Checkbox.args = {
+ name: "what",
+ value: "this-checkbox-right-here",
}
-ThreeCheckboxes.argTypes = {
- customColor: {
- control: {type: "color"},
- },
- value: {
- control: {type: "null"},
- },
-}
\ No newline at end of file
diff --git a/src/components/inputs/Checkbox.tsx b/src/components/inputs/Checkbox.tsx
index 72ef213..0b56544 100644
--- a/src/components/inputs/Checkbox.tsx
+++ b/src/components/inputs/Checkbox.tsx
@@ -5,38 +5,26 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface CheckboxProps {
- disabled?: boolean,
-
- onChange?: (value: string, checked: boolean) => boolean,
-
- name: string,
+export interface CheckboxProps extends Types.BluelibHTMLProps {
+ onChange?: (event: React.ChangeEvent) => void,
+ onSimpleChange?: (value: string, checked: boolean) => void,
+ checked?: boolean,
value: string,
-
- [props: string]: any,
}
-export function Checkbox({onChange, ...props}: CheckboxProps): JSX.Element {
+export function Checkbox({onChange, onSimpleChange, ...props}: CheckboxProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-checkbox")
- const onChangeWrapper = React.useCallback(
-
- (event: React.ChangeEvent): boolean => {
- const checked = event.target.checked
- const value = event.target.value
-
- if(onChange) {
- return onChange(value, checked)
- }
-
- return false
+ const onChangeWrapped = React.useCallback(
+ event => {
+ if(onChange) onChange(event)
+ if(onSimpleChange) onSimpleChange(event.target.value, event.target.checked)
},
-
- [onChange]
+ [onChange, onSimpleChange]
)
return (
-
+
)
}
diff --git a/src/components/inputs/Field.stories.jsx b/src/components/inputs/Field.stories.jsx
index 94ba8a8..2dfa3c3 100644
--- a/src/components/inputs/Field.stories.jsx
+++ b/src/components/inputs/Field.stories.jsx
@@ -1,25 +1,24 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
-import { Field } from "./Field"
+import { Field as FieldComponent } from "./Field"
export default {
- component: Field,
+ component: FieldComponent,
title: "Inputs/Field",
decorators: [Decorators.Bluelib],
argTypes: {
- customColor: {
- control: {type: "color"},
- },
+ onChange: {action: "Change"},
+ onSimpleChange: {action: "SimpleChange"},
},
}
-export const Default = props => (
-
+export const Field = props => (
+
)
-Default.args = {
+Field.args = {
placeholder: "Enter text here",
disabled: false,
required: false,
diff --git a/src/components/inputs/Field.tsx b/src/components/inputs/Field.tsx
index c27b452..36fa162 100644
--- a/src/components/inputs/Field.tsx
+++ b/src/components/inputs/Field.tsx
@@ -5,37 +5,25 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface FieldProps {
- placeholder: string,
- required?: boolean,
- disabled?: boolean,
-
- onChange: (contents: string) => boolean,
+export interface FieldProps extends Types.BluelibHTMLProps {
+ onChange?: (event: React.ChangeEvent) => void,
+ onSimpleChange?: (value: string) => void,
value?: string,
-
- [props: string]: any,
}
-export function Field({onChange, value, ...props}: FieldProps): JSX.Element {
+export function Field({onChange, onSimpleChange, ...props}: FieldProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-field")
- const onChangeWrapper = React.useCallback(
-
- (event: React.ChangeEvent): boolean => {
- const contents = event.target.value
-
- if(onChange) {
- return onChange(contents)
- }
-
- return false
+ const onChangeWrapped = React.useCallback(
+ event => {
+ if(onChange) onChange(event)
+ if(onSimpleChange) onSimpleChange(event.target.value)
},
-
- [onChange]
+ [onChange, onSimpleChange]
)
return (
-
+
)
}
diff --git a/src/components/inputs/InputLabel.tsx b/src/components/inputs/InputLabel.tsx
new file mode 100644
index 0000000..c4af066
--- /dev/null
+++ b/src/components/inputs/InputLabel.tsx
@@ -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 {}
+
+
+export function InputLabel({...props}: InputLabelProps): JSX.Element {
+ return (
+
+ )
+}
diff --git a/src/components/inputs/LabelledCheckbox.stories.jsx b/src/components/inputs/LabelledCheckbox.stories.jsx
new file mode 100644
index 0000000..578c34b
--- /dev/null
+++ b/src/components/inputs/LabelledCheckbox.stories.jsx
@@ -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 => (
+
+)
+LabelledCheckbox.args = {
+ label: "This",
+ name: "what",
+ value: "this",
+}
diff --git a/src/components/inputs/LabelledCheckbox.tsx b/src/components/inputs/LabelledCheckbox.tsx
new file mode 100644
index 0000000..592eb1f
--- /dev/null
+++ b/src/components/inputs/LabelledCheckbox.tsx
@@ -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 (
+
+
+ {label}
+
+ )
+}
diff --git a/src/components/inputs/LabelledRadio.stories.jsx b/src/components/inputs/LabelledRadio.stories.jsx
new file mode 100644
index 0000000..d1628bf
--- /dev/null
+++ b/src/components/inputs/LabelledRadio.stories.jsx
@@ -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 => (
+
+)
+LabelledRadio.args = {
+ label: "This",
+ name: "what",
+ value: "this",
+}
diff --git a/src/components/inputs/LabelledRadio.tsx b/src/components/inputs/LabelledRadio.tsx
new file mode 100644
index 0000000..e580934
--- /dev/null
+++ b/src/components/inputs/LabelledRadio.tsx
@@ -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 (
+
+
+ {label}
+
+ )
+}
diff --git a/src/components/inputs/Multiselect.stories.jsx b/src/components/inputs/Multiselect.stories.jsx
index 78b60cd..725b4fb 100644
--- a/src/components/inputs/Multiselect.stories.jsx
+++ b/src/components/inputs/Multiselect.stories.jsx
@@ -8,40 +8,40 @@ import { Multiselect } from "./Multiselect"
export default {
component: Multiselect,
+ subcomponents: {Option, OptionGroup},
title: "Inputs/Multiselect",
decorators: [Decorators.Bluelib],
argTypes: {
- customColor: {
- control: {type: "color"},
- },
+ onChange: {action: "Change"},
+ onSimpleChange: {action: "SimpleChange"},
},
}
-export const Default = props => (
+export const Basic = props => (
-
)
-Default.args = {
+Basic.args = {
disabled: false,
}
export const WithGroups = props => (
-
-
-
-
+
+
+
+
+
+
+
+
+
+
)
WithGroups.args = {
diff --git a/src/components/inputs/Multiselect.tsx b/src/components/inputs/Multiselect.tsx
index 970df5a..6045aa6 100644
--- a/src/components/inputs/Multiselect.tsx
+++ b/src/components/inputs/Multiselect.tsx
@@ -3,39 +3,33 @@ import * as ReactDOM from "react-dom"
import * as Types from "../../types"
import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
+import {Option} from "./Option";
+import {OptionGroup} from "./OptionGroup";
-interface MultiselectProps {
- disabled?: boolean,
-
- onChange?: (contents: string[]) => boolean,
-
- children: React.ReactNode,
-
- [props: string]: any,
+export interface MultiselectProps extends Types.BluelibHTMLProps {
+ onChange?: (event: React.ChangeEvent) => void,
+ onSimpleChange?: (value: string[]) => void,
+ value?: string[],
}
-export function Multiselect({onChange, ...props}: MultiselectProps): JSX.Element {
+export function Multiselect({onChange, onSimpleChange, ...props}: MultiselectProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-multiselect")
- const onChangeWrapper = React.useCallback(
-
- (event: React.ChangeEvent): boolean => {
- const options = Array.from(event.target.selectedOptions)
- const contents = options.map((option: HTMLOptionElement) => option.value)
-
- if(onChange) {
- return onChange(contents)
- }
-
- return false
+ const onChangeWrapped = React.useCallback(
+ event => {
+ if(onChange) onChange(event)
+ if(onSimpleChange) onSimpleChange(Array.from(event.target.selectedOptions).map(option => option.value))
},
-
- [onChange]
+ [onChange, onSimpleChange]
)
return (
-
+
)
}
+
+
+Multiselect.Option = Option
+Multiselect.Group = OptionGroup
diff --git a/src/components/inputs/MultiselectContext.ts b/src/components/inputs/MultiselectContext.ts
deleted file mode 100644
index 0311e80..0000000
--- a/src/components/inputs/MultiselectContext.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as React from "react"
-import * as Types from "../../types"
-
-
-export const MultiselectContext: Types.UseStateContext = React.createContext(null) as Types.UseStateContext
diff --git a/src/components/inputs/Option.tsx b/src/components/inputs/Option.tsx
index 413a1cf..8a900a0 100644
--- a/src/components/inputs/Option.tsx
+++ b/src/components/inputs/Option.tsx
@@ -5,19 +5,19 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface OptionProps {
- label: string,
+export interface OptionProps {
+ value: string,
[props: string]: any,
}
-export function Option({label, ...props}: OptionProps): JSX.Element {
+export function Option({value, ...props}: OptionProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input-option")
return (
- {label}
+ {value}
)
}
diff --git a/src/components/inputs/OptionGroup.tsx b/src/components/inputs/OptionGroup.tsx
index 9ec12a4..49ae2bc 100644
--- a/src/components/inputs/OptionGroup.tsx
+++ b/src/components/inputs/OptionGroup.tsx
@@ -5,7 +5,7 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface OptionGroupProps {
+export interface OptionGroupProps {
label: string,
[props: string]: any,
diff --git a/src/components/inputs/Radio.stories.jsx b/src/components/inputs/Radio.stories.jsx
index d097eff..1195303 100644
--- a/src/components/inputs/Radio.stories.jsx
+++ b/src/components/inputs/Radio.stories.jsx
@@ -1,50 +1,26 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
-import { Radio } from "./Radio"
+import { Radio as RadioComponent } from "./Radio"
import { Box } from "../panels/Box"
import { BaseElement } from "../BaseElement"
export default {
- component: Radio,
+ component: RadioComponent,
title: "Inputs/Radio",
decorators: [Decorators.Bluelib],
argTypes: {
- customColor: {
- control: {type: "color"},
- },
+ onChange: {action: "Change"},
+ onSimpleChange: {action: "SimpleChange"},
},
}
-export const Default = props => (
-
+export const Radio = props => (
+
)
-
-
-
-export const ThreeRadios = props => (
-
-
- Articuno
-
-
- Zapdos
-
-
- Moltres
-
-
-)
-ThreeRadios.args = {
- name: "example"
+Radio.args = {
+ name: "what",
+ value: "this-radio-right-here",
}
-ThreeRadios.argTypes = {
- customColor: {
- control: {type: "color"},
- },
- value: {
- control: {type: "null"},
- },
-}
\ No newline at end of file
diff --git a/src/components/inputs/Radio.tsx b/src/components/inputs/Radio.tsx
index 9f60dd0..244ba86 100644
--- a/src/components/inputs/Radio.tsx
+++ b/src/components/inputs/Radio.tsx
@@ -5,37 +5,26 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface RadioProps {
- disabled?: boolean,
-
- onChange?: (value: string) => boolean,
-
- name: string,
+export interface RadioProps extends Types.BluelibHTMLProps {
+ onChange?: (event: React.ChangeEvent) => void,
+ onSimpleChange?: (value: string) => void,
+ checked?: boolean,
value: string,
-
- [props: string]: any,
}
-export function Radio({onChange, ...props}: RadioProps): JSX.Element {
+export function Radio({onChange, onSimpleChange, ...props}: RadioProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-radio")
- const onChangeWrapper = React.useCallback(
-
- (event: React.ChangeEvent): boolean => {
- const value = event.target.value
-
- if(onChange) {
- return onChange(value)
- }
-
- return false
+ const onChangeWrapped = React.useCallback(
+ event => {
+ if(onChange) onChange(event)
+ if(onSimpleChange) onSimpleChange(event.target.value)
},
-
- [onChange]
+ [onChange, onSimpleChange]
)
return (
-
+
)
}
diff --git a/src/components/inputs/Select.stories.jsx b/src/components/inputs/Select.stories.jsx
index b9f3298..06a2b97 100644
--- a/src/components/inputs/Select.stories.jsx
+++ b/src/components/inputs/Select.stories.jsx
@@ -1,49 +1,48 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
-import { Select } from "./Select"
+import { Select, Select as SelectComponent } from "./Select"
import { Option } from "./Option"
import { OptionGroup } from "./OptionGroup"
export default {
- component: Select,
+ component: SelectComponent,
title: "Inputs/Select",
decorators: [Decorators.Bluelib],
argTypes: {
- customColor: {
- control: {type: "color"},
- },
+ onChange: {action: "Change"},
+ onSimpleChange: {action: "SimpleChange"},
},
}
-export const Default = props => (
-
+export const Basic = props => (
+
+
+
+
+
)
-Default.args = {
+Basic.args = {
disabled: false,
}
export const WithGroups = props => (
-
+
+
+
+
+
+
+
+
+
+
+
+
+
)
WithGroups.args = {
disabled: false,
diff --git a/src/components/inputs/Select.tsx b/src/components/inputs/Select.tsx
index 1c5f391..68fa3a4 100644
--- a/src/components/inputs/Select.tsx
+++ b/src/components/inputs/Select.tsx
@@ -3,40 +3,33 @@ import * as ReactDOM from "react-dom"
import * as Types from "../../types"
import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-import {SelectContext} from "./SelectContext";
+import {Option} from "./Option"
+import {OptionGroup} from "./OptionGroup"
-interface SelectProps {
- disabled?: boolean,
-
- onChange?: (contents: string) => boolean,
-
- children: React.ReactNode,
-
- [props: string]: any,
+export interface SelectProps extends Types.BluelibHTMLProps {
+ onChange?: (event: React.ChangeEvent) => void,
+ onSimpleChange?: (value: string) => void,
+ value?: string,
}
-export function Select({onChange, ...props}: SelectProps): JSX.Element {
-
+export function Select({onChange, onSimpleChange, ...props}: SelectProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "input", "input-select")
- const onChangeWrapper = React.useCallback(
-
- (event: React.ChangeEvent): boolean => {
- const contents = event.target.value
-
- if(onChange) {
- return onChange(contents)
- }
-
- return false
+ const onChangeWrapped = React.useCallback(
+ event => {
+ if(onChange) onChange(event)
+ if(onSimpleChange) onSimpleChange(event.target.value)
},
-
- [onChange]
+ [onChange, onSimpleChange]
)
return (
-
+
)
}
+
+
+Select.Option = Option
+Select.Group = OptionGroup
diff --git a/src/components/inputs/SelectContext.ts b/src/components/inputs/SelectContext.ts
deleted file mode 100644
index 7dc71a5..0000000
--- a/src/components/inputs/SelectContext.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as React from "react"
-import * as Types from "../../types"
-
-
-export const SelectContext: Types.UseStateContext = React.createContext(null) as Types.UseStateContext
diff --git a/src/components/layouts/BaseLayout.tsx b/src/components/layouts/BaseLayout.tsx
index 64d524b..664381c 100644
--- a/src/components/layouts/BaseLayout.tsx
+++ b/src/components/layouts/BaseLayout.tsx
@@ -5,14 +5,10 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface LayoutProps {
-
- [props: string]: any,
-}
+export interface BaseLayoutProps extends Types.BluelibHTMLProps {}
-export function BaseLayout({...props}: LayoutProps): JSX.Element {
-
+export function BaseLayout({...props}: BaseLayoutProps): JSX.Element {
props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout")
return (
diff --git a/src/components/layouts/LayoutFill.stories.jsx b/src/components/layouts/LayoutFill.stories.jsx
index 40141ac..787a208 100644
--- a/src/components/layouts/LayoutFill.stories.jsx
+++ b/src/components/layouts/LayoutFill.stories.jsx
@@ -1,14 +1,15 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
-import { LayoutFill } from "./LayoutFill"
-import { Bluelib } from "../Bluelib"
+import { LayoutFill as LayoutFillComponent } from "./LayoutFill"
+import { LayoutFillSingle } from "./LayoutFillSingle"
import { Box } from "../panels/Box"
export default {
- component: LayoutFill,
- title: "Layouts/LayoutFill",
+ component: LayoutFillComponent,
+ subcomponents: {LayoutFillSingle},
+ title: "Layouts/Layout Fill",
decorators: [Decorators.Bluelib, Decorators.Fill],
parameters: {
layout: "fullscreen",
@@ -16,13 +17,13 @@ export default {
}
-export const Default = props => (
-
-
+export const LayoutFill = props => (
+
+
Single
-
-
+
+
)
-Default.args = {}
+LayoutFill.args = {}
diff --git a/src/components/layouts/LayoutFill.tsx b/src/components/layouts/LayoutFill.tsx
index d85cdd8..c77aed4 100644
--- a/src/components/layouts/LayoutFill.tsx
+++ b/src/components/layouts/LayoutFill.tsx
@@ -3,12 +3,11 @@ import * as ReactDOM from "react-dom"
import * as Types from "../../types"
import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-import {BaseLayout} from "./BaseLayout";
+import {BaseLayout, BaseLayoutProps} from "./BaseLayout";
+import {LayoutFillSingle} from "./LayoutFillSingle";
-interface LayoutFillProps {
- [props: string]: any,
-}
+export interface LayoutFillProps extends BaseLayoutProps {}
export function LayoutFill({...props}: LayoutFillProps): JSX.Element {
@@ -18,12 +17,4 @@ export function LayoutFill({...props}: LayoutFillProps): JSX.Element {
}
-interface LayoutFillSingleProps {
- [props: string]: any,
-}
-
-LayoutFill.Single = function({...props}: LayoutFillSingleProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-fill-single")
-
- return
-}
\ No newline at end of file
+LayoutFill.Single = LayoutFillSingle
\ No newline at end of file
diff --git a/src/components/layouts/LayoutFillSingle.tsx b/src/components/layouts/LayoutFillSingle.tsx
new file mode 100644
index 0000000..cc5fc86
--- /dev/null
+++ b/src/components/layouts/LayoutFillSingle.tsx
@@ -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 {}
+
+
+export function LayoutFillSingle({...props}: LayoutFillSingleProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-fill-single")
+
+ return (
+
+ )
+}
diff --git a/src/components/layouts/LayoutThreeCol.stories.jsx b/src/components/layouts/LayoutThreeCol.stories.jsx
index 732015b..0835843 100644
--- a/src/components/layouts/LayoutThreeCol.stories.jsx
+++ b/src/components/layouts/LayoutThreeCol.stories.jsx
@@ -1,13 +1,17 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
-import { LayoutThreeCol } from "./LayoutThreeCol"
+import { LayoutThreeCol as LayoutThreeColComponent } from "./LayoutThreeCol"
+import { LayoutThreeColLeft } from "./LayoutThreeColLeft"
+import { LayoutThreeColCenter } from "./LayoutThreeColCenter"
+import { LayoutThreeColRight } from "./LayoutThreeColRight"
import { Box } from "../panels/Box"
export default {
- component: LayoutThreeCol,
- title: "Layouts/LayoutThreeCol",
+ component: LayoutThreeColComponent,
+ subcomponents: {LayoutThreeColLeft, LayoutThreeColCenter, LayoutThreeColRight},
+ title: "Layouts/Layout Three Col",
decorators: [Decorators.Bluelib, Decorators.Fill],
parameters: {
layout: "fullscreen",
@@ -15,23 +19,23 @@ export default {
}
-export const Default = props => (
-
-
+export const LayoutThreeCol = props => (
+
+
Left
-
-
+
+
Center
-
-
+
+
Right
-
-
+
+
)
-Default.args = {}
+LayoutThreeCol.args = {}
diff --git a/src/components/layouts/LayoutThreeCol.tsx b/src/components/layouts/LayoutThreeCol.tsx
index 5d2c338..c983ad2 100644
--- a/src/components/layouts/LayoutThreeCol.tsx
+++ b/src/components/layouts/LayoutThreeCol.tsx
@@ -3,10 +3,13 @@ import * as ReactDOM from "react-dom"
import * as Types from "../../types"
import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-import {BaseLayout} from "./BaseLayout";
+import {BaseLayout, BaseLayoutProps} from "./BaseLayout";
+import {LayoutThreeColLeft} from "./LayoutThreeColLeft";
+import {LayoutThreeColCenter} from "./LayoutThreeColCenter";
+import {LayoutThreeColRight} from "./LayoutThreeColRight";
-interface LayoutThreeColProps {
+export interface LayoutThreeColProps extends BaseLayoutProps {
[props: string]: any,
}
@@ -20,37 +23,6 @@ export function LayoutThreeCol({...props}: LayoutThreeColProps): JSX.Element {
}
-interface LayoutThreeColLeftProps {
- [props: string]: any,
-}
-
-
-LayoutThreeCol.Left = function({...props}: LayoutThreeColLeftProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-left")
-
- return
-}
-
-
-interface LayoutThreeColCenterProps {
- [props: string]: any,
-}
-
-
-LayoutThreeCol.Center = function({...props}: LayoutThreeColCenterProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-center")
-
- return
-}
-
-
-interface LayoutThreeColRightProps {
- [props: string]: any,
-}
-
-
-LayoutThreeCol.Right = function({...props}: LayoutThreeColRightProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-right")
-
- return
-}
+LayoutThreeCol.Left = LayoutThreeColLeft
+LayoutThreeCol.Center = LayoutThreeColCenter
+LayoutThreeCol.Right = LayoutThreeColRight
\ No newline at end of file
diff --git a/src/components/layouts/LayoutThreeColCenter.tsx b/src/components/layouts/LayoutThreeColCenter.tsx
new file mode 100644
index 0000000..cfaa194
--- /dev/null
+++ b/src/components/layouts/LayoutThreeColCenter.tsx
@@ -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 {}
+
+
+export function LayoutThreeColCenter({...props}: LayoutThreeColCenterProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-center")
+
+ return (
+
+ )
+}
diff --git a/src/components/layouts/LayoutThreeColLeft.tsx b/src/components/layouts/LayoutThreeColLeft.tsx
new file mode 100644
index 0000000..e7b3bb6
--- /dev/null
+++ b/src/components/layouts/LayoutThreeColLeft.tsx
@@ -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 {}
+
+
+export function LayoutThreeColLeft({...props}: LayoutThreeColLeftProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-left")
+
+ return (
+
+ )
+}
diff --git a/src/components/layouts/LayoutThreeColRight.tsx b/src/components/layouts/LayoutThreeColRight.tsx
new file mode 100644
index 0000000..6a13971
--- /dev/null
+++ b/src/components/layouts/LayoutThreeColRight.tsx
@@ -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 {}
+
+
+export function LayoutThreeColRight({...props}: LayoutThreeColRightProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "layout-threecol-right")
+
+ return (
+
+ )
+}
diff --git a/src/components/lists/DescriptionList.stories.jsx b/src/components/lists/DescriptionList.stories.jsx
deleted file mode 100644
index 811e0da..0000000
--- a/src/components/lists/DescriptionList.stories.jsx
+++ /dev/null
@@ -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 => (
-
-
- LOL
-
-
- Laughing out loud
-
-
- KEK
-
-
- Equivalent to lol, but said by a member of the Horde
-
-
- LUL
-
-
- Equivalent to lol, used by twitch.tv users to send an emoticon with the face of TotalBiscuit
-
-
-)
-Default.args = {
- disabled: false,
-}
diff --git a/src/components/lists/DescriptionList.tsx b/src/components/lists/DescriptionList.tsx
deleted file mode 100644
index a8e4cb9..0000000
--- a/src/components/lists/DescriptionList.tsx
+++ /dev/null
@@ -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 (
-
- )
-}
-
-
-interface DescriptionListKeyProps {
- [props: string]: any,
-}
-
-
-DescriptionList.Key = function({...props}: DescriptionListKeyProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-key")
-
- return (
-
- )
-}
-
-
-interface DescriptionListValueProps {
- [props: string]: any,
-}
-
-
-DescriptionList.Value = function({...props}: DescriptionListValueProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-value")
-
- return (
-
- )
-}
diff --git a/src/components/lists/List.stories.jsx b/src/components/lists/List.stories.jsx
deleted file mode 100644
index 811d755..0000000
--- a/src/components/lists/List.stories.jsx
+++ /dev/null
@@ -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 => (
-
- Io
- Gyrocopter
- Chaos Knight
-
-)
-Unordered.args = {
- disabled: false,
- ordered: false,
-}
-
-
-export const Ordered = Unordered.bind({})
-Ordered.args = {
- ...Unordered.args,
- ordered: true,
-}
diff --git a/src/components/lists/List.tsx b/src/components/lists/List.tsx
deleted file mode 100644
index 6931648..0000000
--- a/src/components/lists/List.tsx
+++ /dev/null
@@ -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 (
-
- )
-}
-
-
-interface ListItemProps {
- [props: string]: any,
-}
-
-
-List.Item = function({...props}: ListItemProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-item")
-
- return (
-
- )
-}
diff --git a/src/components/lists/ListDescription.stories.jsx b/src/components/lists/ListDescription.stories.jsx
new file mode 100644
index 0000000..4e071a8
--- /dev/null
+++ b/src/components/lists/ListDescription.stories.jsx
@@ -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 => (
+
+
+ LOL
+
+
+ Laughing out loud
+
+
+ KEK
+
+
+ Equivalent to lol, but said by a member of the Horde
+
+
+ LUL
+
+
+ Equivalent to lol, used by twitch.tv users to send an emoticon with the face of TotalBiscuit
+
+
+)
+ListDescription.args = {}
diff --git a/src/components/lists/ListDescription.tsx b/src/components/lists/ListDescription.tsx
new file mode 100644
index 0000000..5d7af63
--- /dev/null
+++ b/src/components/lists/ListDescription.tsx
@@ -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 {}
+
+
+export function ListDescription({...props}: ListDescriptionProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list", "list-description")
+
+ return (
+
+ )
+}
+
+
+ListDescription.Term = ListTerm
+ListDescription.Details = ListDetails
diff --git a/src/components/lists/ListDetails.tsx b/src/components/lists/ListDetails.tsx
new file mode 100644
index 0000000..8ac4de5
--- /dev/null
+++ b/src/components/lists/ListDetails.tsx
@@ -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 {}
+
+
+export function ListDetails({...props}: ListDetailsProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-details")
+
+ return (
+
+ )
+}
diff --git a/src/components/lists/ListItem.tsx b/src/components/lists/ListItem.tsx
new file mode 100644
index 0000000..fbb9053
--- /dev/null
+++ b/src/components/lists/ListItem.tsx
@@ -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 {}
+
+
+export function ListItem({...props}: ListItemProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-item")
+
+ return (
+
+ )
+}
diff --git a/src/components/lists/ListOrdered.stories.jsx b/src/components/lists/ListOrdered.stories.jsx
new file mode 100644
index 0000000..2f79873
--- /dev/null
+++ b/src/components/lists/ListOrdered.stories.jsx
@@ -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 => (
+
+ Gold
+ Silver
+ Bronze
+ Iron
+ Wood
+
+)
+ListOrdered.args = {}
diff --git a/src/components/lists/ListOrdered.tsx b/src/components/lists/ListOrdered.tsx
new file mode 100644
index 0000000..9942f26
--- /dev/null
+++ b/src/components/lists/ListOrdered.tsx
@@ -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 {}
+
+
+export function ListOrdered({...props}: ListOrderedProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list", "list-ordered")
+
+ return (
+
+ )
+}
+
+
+ListOrdered.Item = ListItem
\ No newline at end of file
diff --git a/src/components/lists/ListTerm.tsx b/src/components/lists/ListTerm.tsx
new file mode 100644
index 0000000..31245fc
--- /dev/null
+++ b/src/components/lists/ListTerm.tsx
@@ -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 {}
+
+
+export function ListTerm({...props}: ListTermProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list-description-term")
+
+ return (
+
+ )
+}
diff --git a/src/components/lists/ListUnordered.stories.jsx b/src/components/lists/ListUnordered.stories.jsx
new file mode 100644
index 0000000..90c4d29
--- /dev/null
+++ b/src/components/lists/ListUnordered.stories.jsx
@@ -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 => (
+
+ Mario
+ Luigi
+ Baby Mario
+ Baby Luigi
+
+)
+ListUnordered.args = {}
diff --git a/src/components/lists/ListUnordered.tsx b/src/components/lists/ListUnordered.tsx
new file mode 100644
index 0000000..25d4577
--- /dev/null
+++ b/src/components/lists/ListUnordered.tsx
@@ -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 {}
+
+
+export function ListUnordered({...props}: ListUnorderedProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "list", "list-unordered")
+
+ return (
+
+ )
+}
+
+
+ListUnordered.Item = ListItem
diff --git a/src/components/panels/Box.tsx b/src/components/panels/Box.tsx
index 58ad875..c5ffb32 100644
--- a/src/components/panels/Box.tsx
+++ b/src/components/panels/Box.tsx
@@ -1,13 +1,11 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Types from "../../types"
-import {Panel} from "./Panel";
+import {Panel, PanelProps} from "./Panel";
import mergeClassNames from "classnames"
-interface BoxProps {
- [props: string]: any,
-}
+export interface BoxProps extends PanelProps {}
export function Box({...props}: BoxProps): JSX.Element {
diff --git a/src/components/panels/Dialog.tsx b/src/components/panels/Dialog.tsx
index ceb02a0..4cdd748 100644
--- a/src/components/panels/Dialog.tsx
+++ b/src/components/panels/Dialog.tsx
@@ -1,13 +1,11 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Types from "../../types"
-import {Panel} from "./Panel";
+import {Panel, PanelProps} from "./Panel";
import mergeClassNames from "classnames"
-interface DialogProps {
- [props: string]: any,
-}
+export interface DialogProps extends PanelProps {}
export function Dialog({...props}: DialogProps): JSX.Element {
diff --git a/src/components/panels/Panel.tsx b/src/components/panels/Panel.tsx
index cdd54b8..f4d140b 100644
--- a/src/components/panels/Panel.tsx
+++ b/src/components/panels/Panel.tsx
@@ -5,9 +5,7 @@ import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
-interface PanelProps {
- [props: string]: any,
-}
+export interface PanelProps extends Types.BluelibHTMLProps {}
export function Panel({...props}: PanelProps): JSX.Element {
diff --git a/src/components/panels/Parenthesis.tsx b/src/components/panels/Parenthesis.tsx
index 5f716e2..ba4882c 100644
--- a/src/components/panels/Parenthesis.tsx
+++ b/src/components/panels/Parenthesis.tsx
@@ -1,13 +1,11 @@
import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Types from "../../types"
-import {Panel} from "./Panel";
+import {Panel, PanelProps} from "./Panel";
import mergeClassNames from "classnames"
-interface ParenthesisProps {
- [props: string]: any,
-}
+export interface ParenthesisProps extends PanelProps {}
export function Parenthesis({...props}: ParenthesisProps): JSX.Element {
diff --git a/src/components/separators/Separator.stories.jsx b/src/components/separators/Separator.stories.jsx
index 58ce41c..e5d3276 100644
--- a/src/components/separators/Separator.stories.jsx
+++ b/src/components/separators/Separator.stories.jsx
@@ -6,13 +6,8 @@ import { Separator } from "./Separator"
export default {
component: Separator,
- title: "Separator/Separator",
+ title: "Separators/Separator",
decorators: [Decorators.Bluelib],
- argTypes: {
- customColor: {
- control: {type: "color"},
- },
- },
}
diff --git a/src/components/tables/Table.stories.jsx b/src/components/tables/Table.stories.jsx
index 2758512..98e13f1 100644
--- a/src/components/tables/Table.stories.jsx
+++ b/src/components/tables/Table.stories.jsx
@@ -2,20 +2,19 @@ import * as React from "react"
import * as ReactDOM from "react-dom"
import * as Decorators from "../../utils/Decorators"
import { Table } from "./Table"
+import { TableCaption } from "./TableCaption"
+import { TableHeader } from "./TableHeader"
+import { TableBody } from "./TableBody"
+import { TableFooter } from "./TableFooter"
+import { TableRow } from "./TableRow"
+import { TableCell } from "./TableCell"
export default {
component: Table,
+ subcomponents: {TableCaption, TableHeader, TableBody, TableFooter, TableRow, TableCell},
title: "Tables/Table",
decorators: [Decorators.Bluelib],
- argTypes: {
- customColor: {
- control: {type: "color"},
- },
- disabled: {
- control: {type: "boolean"},
- },
- },
}
@@ -150,7 +149,7 @@ export const TierList = props => (
S
- span
+ <span>
@@ -158,7 +157,7 @@ export const TierList = props => (
A
- a
+ <a>
@@ -166,7 +165,7 @@ export const TierList = props => (
B
- body
+ <body>
@@ -174,7 +173,7 @@ export const TierList = props => (
C
- caption
+ <caption>
diff --git a/src/components/tables/Table.tsx b/src/components/tables/Table.tsx
index 52fcbe9..fc545bd 100644
--- a/src/components/tables/Table.tsx
+++ b/src/components/tables/Table.tsx
@@ -3,11 +3,15 @@ import * as ReactDOM from "react-dom"
import * as Types from "../../types"
import {BaseElement} from "../BaseElement"
import mergeClassNames from "classnames"
+import {TableCaption} from "./TableCaption";
+import {TableHeader} from "./TableHeader";
+import {TableBody} from "./TableBody";
+import {TableFooter} from "./TableFooter";
+import {TableRow} from "./TableRow";
+import {TableCell} from "./TableCell";
-interface TableProps {
- [props: string]: any,
-}
+interface TableProps extends Types.BluelibHTMLProps {}
export function Table({...props}: TableProps): JSX.Element {
@@ -18,97 +22,9 @@ export function Table({...props}: TableProps): JSX.Element {
)
}
-
-interface TableCaptionProps {
- position: "top" | "bottom",
-
- [props: string]: any,
-}
-
-
-const TABLE_CAPTION_CLASSES = {
- top: "table-caption-top",
- bottom: "table-caption-bottom",
-}
-
-
-Table.Caption = function({position, ...props}: TableCaptionProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-caption", TABLE_CAPTION_CLASSES[position])
-
- return (
-
- )
-}
-
-
-interface TableHeaderProps {
- [props: string]: any,
-}
-
-
-Table.Header = function ({position, ...props}: TableHeaderProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-header")
-
- return (
-
- )
-}
-
-
-interface TableBodyProps {
- [props: string]: any,
-}
-
-
-Table.Body = function ({position, ...props}: TableBodyProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-body")
-
- return (
-
- )
-}
-
-
-interface TableFooterProps {
- [props: string]: any,
-}
-
-
-Table.Footer = function ({position, ...props}: TableFooterProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-footer")
-
- return (
-
- )
-}
-
-
-interface TableRowProps {
- [props: string]: any,
-}
-
-
-Table.Row = function ({...props}: TableRowProps): JSX.Element {
- props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-row")
-
- return (
-
- )
-}
-
-
-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 (
-
- )
-}
+Table.Caption = TableCaption
+Table.Header = TableHeader
+Table.Body = TableBody
+Table.Footer = TableFooter
+Table.Row = TableRow
+Table.Cell = TableCell
diff --git a/src/components/tables/TableBody.tsx b/src/components/tables/TableBody.tsx
new file mode 100644
index 0000000..63123db
--- /dev/null
+++ b/src/components/tables/TableBody.tsx
@@ -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 {}
+
+
+export function TableBody({...props}: TableBodyProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-body")
+
+ return (
+
+ )
+}
diff --git a/src/components/tables/TableCaption.tsx b/src/components/tables/TableCaption.tsx
new file mode 100644
index 0000000..1eb519e
--- /dev/null
+++ b/src/components/tables/TableCaption.tsx
@@ -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 {
+ 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 (
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/tables/TableCell.tsx b/src/components/tables/TableCell.tsx
new file mode 100644
index 0000000..45405b2
--- /dev/null
+++ b/src/components/tables/TableCell.tsx
@@ -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 {
+ 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 (
+
+ )
+}
diff --git a/src/components/tables/TableFooter.tsx b/src/components/tables/TableFooter.tsx
new file mode 100644
index 0000000..46c1850
--- /dev/null
+++ b/src/components/tables/TableFooter.tsx
@@ -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 {}
+
+
+export function TableFooter({...props}: TableFooterProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-footer")
+
+ return (
+
+ )
+}
diff --git a/src/components/tables/TableHeader.tsx b/src/components/tables/TableHeader.tsx
new file mode 100644
index 0000000..9e9d366
--- /dev/null
+++ b/src/components/tables/TableHeader.tsx
@@ -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 {}
+
+
+export function TableHeader({...props}: TableHeaderProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-header")
+
+ return (
+
+ )
+}
diff --git a/src/components/tables/TableRow.tsx b/src/components/tables/TableRow.tsx
new file mode 100644
index 0000000..2be6d3e
--- /dev/null
+++ b/src/components/tables/TableRow.tsx
@@ -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 {
+ [props: string]: any,
+}
+
+
+export function TableRow({...props}: TableRowProps): JSX.Element {
+ props.bluelibClassNames = mergeClassNames(props.bluelibClassNames, "table-row")
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
index 14430dd..58cdcb9 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,13 +1,24 @@
-import * as React from "react";
-
-export type {Argument as ClassNames} from "classnames"
-
-// export type IntrinsicComponentKind = JSX.IntrinsicElements
-// export type FunctionComponentKind = (props: object) => JSX.Element
-// export type ClassComponentKind = typeof React.Component
-// export type ComponentKind = IntrinsicComponentKind | FunctionComponentKind | ClassComponentKind
-export type ComponentKind = any
+import * as React from "react"
+import Color from "color"
+import {Argument as ClassNamesArgument} from "classnames"
+export type ClassNames = ClassNamesArgument
-export type UseStateContext = React.Context>]>
\ No newline at end of file
+
+export type State = [Value, React.Dispatch>]
+export type StateContext = React.Context | undefined>
+
+
+export interface BluelibProps {
+ bluelibClassNames?: ClassNames,
+ customColor?: typeof Color,
+ disabled?: boolean,
+}
+
+
+export interface BluelibHTMLProps extends BluelibProps, React.HTMLProps {}
+
+
+export type InputValue = readonly string[] | string | number | undefined
+export type Validity = boolean | null
diff --git a/src/utils/Decorators.jsx b/src/utils/Decorators.jsx
index a85f1f3..011ccdd 100644
--- a/src/utils/Decorators.jsx
+++ b/src/utils/Decorators.jsx
@@ -1,9 +1,12 @@
import { Bluelib as BluelibComponent } from "../components/Bluelib"
import { Box as BoxComponent } from "../components/panels/Box"
+import { Form as FormComponent } from "../components/forms/Form"
export const Bluelib = Story =>
export const Fill = Story =>
-export const Box = Story =>
\ No newline at end of file
+export const Box = Story =>
+
+export const Form = Story =>
diff --git a/yarn.lock b/yarn.lock
index 3c14179..b71c077 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3107,6 +3107,11 @@
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==
+"@types/uuid@^8.3.1":
+ version "8.3.1"
+ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f"
+ integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg==
+
"@types/webpack-env@^1.16.0":
version "1.16.2"
resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.2.tgz#8db514b059c1b2ae14ce9d7bb325296de6a9a0fa"
@@ -13998,7 +14003,7 @@ uuid@^3.3.2, uuid@^3.4.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-uuid@^8.3.0:
+uuid@^8.3.0, uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==