A styled button
element.
This is a simple wrapper around the native button
element,
so you can replace <button { ...props } />
with <UI.Button { ...props } />
for better looking, easily stylable buttons for your application.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ count, setCount ] = useState(0)
return (
<div { ...props }>
<p>
The button was clicked {count} times.
</p>
<UI.Button onClick={() => setCount(count => count + 1)}>
<span>
Click me
</span>
</UI.Button>
</div>
)
}
A styled div
using flex box CSS to center its contents both horizonally and vertically.
A custom "combo" box. Looks like a select menu, but you can type into it like it's an input.
The value
prop represents the selected value, while the inputValue
prop represents the value of the input.
What you do with the input/selection is up to you - e.g., filtering, adding/removing options, etc.
You can replace <select { ...props } />
with <UI.Combo { ...props } />
for filterable, better looking, easily stylable select menus with inputs for your application.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ value, setValue ] = useState('')
const [ inputValue, setInputValue ] = useState('')
const options = [
'',
'foo',
'bar'
]
return (
<div { ...props }>
<p>
Type into the combo box and select an option.
</p>
<UI.Combo
placeholder='Hello, World!'
name='example'
value={value}
inputValue={inputValue}
onInput={event => {
setInputValue(event.currentTarget.value)
}}
onChange={event => {
setValue(event.currentTarget.value)
}}
>
{options.map(option => inputValue && option.indexOf(inputValue) < 0 ? null : (
<option key={option} value={option}>
{option}
</option>
))}
</UI.Combo>
</div>
)
}
The styled arrow icon for the combo box.
The styled input
element for the combo box.
The combo box's list of selectable options.
The styled placeholder element for the combo box.
Displays a readable error message from some Error
.
You can pass the error as a property or as children.
If there is no error, the element will be hidden using display: none
.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ error, setError ] = useState<null | Error>(null)
return (
<div { ...props }>
<p>
Click the button to produce an error.
</p>
<UI.Button onClick={() => setError(new Error(`This is an error!`))}>
<span>
Click me
</span>
</UI.Button>
<p>
<UI.Error>
{error}
</UI.Error>
</p>
</div>
)
}
A styled footer
element.
This is a simple wrapper around the native footer
element,
so you can replace <footer { ...props } />
with <UI.Footer { ...props } />
for better looking, easily stylable footers for your application.
Example usage:
import React from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
return (
<div { ...props }>
<UI.Footer>
<span>
Hello, World!
</span>
</UI.Footer>
</div>
)
}
A styled header
element.
This is a simple wrapper around the native header
element,
so you can replace <header { ...props } />
with <UI.Header { ...props } />
for better looking, easily stylable headers for your application.
Example usage:
import React from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
return (
<div { ...props }>
<UI.Header>
<span>
Hello, World!
</span>
</UI.Header>
</div>
)
}
A styled iframe
element which attempts to adjust its height depending on its contents.
You may also optionally mutate its contents for the same domain.
Example usage:
import React from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
const mutateAnchor = (anchor: HTMLAnchorElement) => {
anchor.setAttribute(`target`, `_blank`)
anchor.setAttribute(`rel`, `noopener noreferrer`)
}
export const Example = (props: ExampleProps): React.ReactElement => {
return (
<div { ...props }>
<p>
The link in the iframe below is mutated upon render to open in a new window.
</p>
<UI.Iframe
title='Hello, World!'
srcDoc={`
<!DOCTYPE html>
<html>
<body>
<a href='https://www.molecule.dev'>
Molecule.dev
</a>
</body>
</html>
`}
mutate={element => {
const iframe = element?.firstElementChild as HTMLIFrameElement
const body = iframe?.contentWindow?.document?.body
const anchors = body?.querySelectorAll(`a`)
if (anchors?.length) {
for (let i = 0; i < anchors.length; i++) {
mutateAnchor(anchors[i])
}
}
}}
/>
</div>
)
}
A styled input
element.
This is a simple wrapper around the native input
element,
so you can replace <input { ...props } />
with <UI.Input { ...props } />
for better looking, easily stylable inputs for your application.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ value, setValue ] = useState('')
return (
<div { ...props }>
<p>
Type something into the input.
</p>
<UI.Input
placeholder='Hello, World!'
name='example'
value={value}
onInput={event => {
setValue(event.currentTarget.value)
}}
/>
</div>
)
}
The input's styled placeholder element.
A custom modal component, defaults to a center position
with 'left' or 'right' options.
If onClose
and/or onBack
handlers are provided, the corresponding buttons will be added
within the ModalHeader
, plus the ModalUnderlay
.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ visible, setVisible ] = useState(false)
return (
<div { ...props }>
<p>
Click the button to show the modal.
</p>
<UI.Button onClick={() => setVisible(true)}>
<span>
Click me
</span>
</UI.Button>
{visible && (
<UI.Modal onClose={() => setVisible(false)}>
<p>
This is a centered modal.
</p>
<p>
Click the X at the top right to close it.
</p>
</UI.Modal>
)}
</div>
)
}
A button icon which can be rendered with an onClick
handler, usually within a ModalHeader
.
A full-sized, semi-transparent underlay which can be rendered before your Modal
with an onClick
handler, usually to close the modal.
A custom rich text editor using Quill.
Aims to be similar in function to the native textarea
element,
but the value is an object containing both text
and html
instead of a string.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ value, setValue ] = useState({
html: `<p><br></p>`,
text: `\n`
})
return (
<div { ...props }>
<p>
Type something into the rich text editor and see console logs for value changes.
</p>
<UI.RTE
placeholder='Hello, World!'
name='example'
value={value}
onInput={event => {
console.log(event.currentTarget.value)
setValue(event.currentTarget.value)
}}
/>
</div>
)
}
A styled select
element, normalized to look the same for every major browser.
You can replace <select { ...props } />
with <UI.Select { ...props } />
for filterable, better looking, easily stylable select menus for your application.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ value, setValue ] = useState('')
const options = [
'',
'foo',
'bar'
]
return (
<div { ...props }>
<p>
Select an option.
</p>
<UI.Select
style={{ width: 200 }}
placeholder='Hello, World!'
name='example'
value={value}
onChange={event => {
setValue(event.currentTarget.value)
}}
>
{options.map(option => (
<option key={option} value={option}>
{option}
</option>
))}
</UI.Select>
</div>
)
}
The styled arrow icon for the select menu.
The styled placeholder element for the select menu.
To achieve the same style across browsers, the selected option's text
is rendered on top of the select
element.
A spinning icon to indicate loading/pending state.
Provide spin
as false
stop the spinning.
Example usage:
import React from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
return (
<div { ...props }>
<UI.Spinner />
</div>
)
}
An icon to represent the state of some promise.
Designed to be paired with the usePromise
hook.
Example usage:
import React from 'react'
import { usePromise } from '../../hooks/usePromise'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ randomNumberRequest, requestRandomNumber ] = usePromise(async () => {
await new Promise(resolve => setTimeout(resolve, 1000))
if (Math.random() < 0.5) {
return Math.random()
} else {
throw new Error(`Try again!`)
}
})
const isPending = randomNumberRequest.status === 'pending'
return (
<div style={{ textAlign: `center` }} { ...props }>
<p>
Click the button to asynchronously set a random number. It has a 50% chance of throwing an error.
</p>
<p>
Current random number: {randomNumberRequest.value || `?`}
</p>
<UI.Button onClick={() => requestRandomNumber()} disabled={isPending}>
<span>
{isPending
? `Wait a second...`
: `Get a random number`
}
</span>
</UI.Button>
<UI.StatusIcon status={randomNumberRequest.status} />
<UI.Error>
{randomNumberRequest.error}
</UI.Error>
</div>
)
}
A styled span
element to quickly color some text using the current theme
.
This is a simple wrapper around the native span
element,
so you can replace <span { ...props } />
with <UI.Text color='primary' { ...props } />
for better looking, easily stylable inline text for your application.
Example usage:
import React from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
return (
<div { ...props }>
Hello, <UI.Text color='primary'>World</UI.Text>!
</div>
)
}
A styled textarea
element.
This is a simple wrapper around the native textarea
element,
so you can replace <textarea { ...props } />
with <UI.Textarea { ...props } />
for better looking, easily stylable textareas for your application.
Example usage:
import React, { useState } from 'react'
import * as UI from '../../UI'
export type ExampleProps = React.HTMLProps<HTMLDivElement>
export const Example = (props: ExampleProps): React.ReactElement => {
const [ value, setValue ] = useState('')
return (
<div { ...props }>
<p>
Type something into the textarea.
</p>
<UI.Textarea
placeholder='Hello, World!'
name='example'
value={value}
onInput={event => {
setValue(event.currentTarget.value)
}}
/>
</div>
)
}
The styled placeholder element for the textarea
.
Example usage:
<UI.Tip color='green'>
<LightBulbIcon size={20} />
<span>
Some tip here.
</span>
</UI.Tip>
A wrapper around the native form
element with some helpful additions.
Intercepts onSubmit
and onInput
to pass an extra formData
parameter
which is a JSON object containing the state of the form data,
which can be as complex (deep) or as simple as you need it to be.
By default, the form data is determined from elements with a name
attribute,
where name can be a "deep" string. For example, consider the following:
return (
<UI.Form onSubmit={(event, formData) => logger.info(formData)}>
<UI.Input
name='foo.bar.baz'
value='Hello, World!'
/>
<UI.Button type='submit'>
<span>
Submit
</span>
</UI.Button>
</UI.Form>
)
// Submitting the form would log the following:
const formData: JSONObject = {
foo: {
bar: {
baz: 'Hello, World!"
}
}
}
You can also use a data-json
attribute to specify JSON values, if necessary:
const [ value, setValue ] = useState('')
return (
<UI.Form onSubmit={(event, formData) => logger.info(formData)}>
<UI.Input
name='foo'
value={value}
onInput={event => setValue(event.currentTarget.value)}
data-json={JSON.stringify({ bar: { baz: value } })}
/>
<UI.Button type='submit'>
<span>
Submit
</span>
</UI.Button>
</UI.Form>
)
If you're managing the state of the form elsewhere, then you probably don't need any of this, but wrapping your inputs in a form is generally a good idea to avoid any confusion, even if the form submission functionality goes unused.
Two input elements designed to normalize datetime inputs across different browsers.
Assigns the value to a potentially deep key.
The keyPath
can be just one - e.g., foo
- or it can be deep - e.g., foo.bar.baz
.
Gets form data with some helpful additions/shortcuts.
By default, all elements with a name
attribute are used (i.e., the selector
argument defaults to [name]
),
regardless of being a valid form element.
Any elements with a data-json
attribute will have this attribute parsed as JSON and used as its value.
If an element does not have a value
attribute but has innerText
, the innerText
is used as its value.
The value
attribute of checkboxes will be used if checked, empty string if not.
The value
attribute of radio buttons will be set only if the radio button is selected.
You can include periods within elements names to create "deep" form data which matches the original object.
For example, <UI.Input name='foo.bar.baz' value={foo.bar.baz} /> will result in form data which looks like { foo: { bar: { baz } } }
.
Initializes the iframe
to optionally mutate its contents
and add event listeners for adjusting its height.
Attempts to set the height of the iframe
to match the height of its contents.
Generated using TypeDoc
Basic user interface components designed to simplify custom styling of the application.
Most UI components are drop-in replacements for their native counterparts, as they are mostly wrappers around their native counterparts using
styled-components
.For example,
<input />
can be replaced with<UI.Input />
using all of the sameprops
.Other components (e.g.,
Modal
,Spinner
, etc.) don't typically have native counterparts but are common and generic enough to be considered a user interface component.