Commit 3aedb154 authored by Loïc Correnson's avatar Loïc Correnson

[dome] port toolbars to TS

parent 188bfe75
......@@ -116,8 +116,7 @@ const LABEL = ({ disabled, label }: LABELprops) => (
);
export type ButtonKind =
undefined | 'default' |
'active' | 'primary' | 'warning' | 'positive' | 'negative';
'default' | 'active' | 'primary' | 'warning' | 'positive' | 'negative';
export interface ButtonProps {
/** Text of the label. Prepend to other children elements. */
......
// --------------------------------------------------------------------------
// --- ToolBars
// --------------------------------------------------------------------------
/**
@packageDocumentation
@module dome/frame/toolbars
*/
import React from 'react' ;
import './style.css' ;
// --------------------------------------------------------------------------
// --- ToolBar Container
// --------------------------------------------------------------------------
/**
@class
@summary Container for toolbar items.
*/
export class ToolBar extends React.Component {
constructor(props) {
super(props);
}
render() {
const children = this.props.children ;
return React.Children.count(children) > 0 && (
<div className='dome-xToolBar dome-color-frame'>
<div className='dome-xToolBar-inset'/>
{children}
<div className='dome-xToolBar-inset'/>
</div>
);
}
}
// --------------------------------------------------------------------------
// --- ToolBar Spaces
// --------------------------------------------------------------------------
/**
@summary Fixed (tiny) space.
*/
export const Inset = (() => <div className='dome-xToolBar-inset'/>);
/**
@summary Fixed space.
*/
export const Space = (() => <div className='dome-xToolBar-space'/>);
/**
@summary Extensible space (can be used to right-align controls).
*/
export const Filler = (() => <div className='dome-xToolBar-filler'/>);
/**
@summary Vertical rule.
*/
export const Separator = () => (
<div className='dome-xToolBar-separator'>
<div className='dome-xToolBar-vrule'/>
</div>
);
// --------------------------------------------------------------------------
// --- ToolBar Button
// --------------------------------------------------------------------------
import { SVG } from 'dome/controls/icons' ;
const SELECT = 'dome-xToolBar-Control dome-selected' ;
const BUTTON = 'dome-xToolBar-Control dome-color-frame' ;
const KIND = (kind) => kind ? ' dome-xToolBar-' + kind : '';
const isSelected = ( { selected , selection , value } ) => (
selected !== undefined ? selected : ( value !== undefined && value === selection )
);
const isDisabled = ( { enabled=true, disabled=false } ) => (disabled || !enabled) ;
const onClick = ( { onClick , value } ) => onClick ? (() => onClick(value)) : undefined ;
/**
@summary Toolbar Button.
@property {string} [icon] - Button icon name (See [gallery](gallery-icons.html))
@property {string} [label] - Button label
@property {string} [title] - Button tooltip
@property {string} [kind] - Styled button (see below)
@property {boolean} [selected] - Selected button (default: `false`)
@property {boolean} [disabled] - Disabled button (default: `false`)
@property {boolean} [enabled] - Enabled button (default: `true`)
@property {any} [value] - button's value
@property {any} [selection] - Currently selected value
@property {function} [onClick] - Button callback (receives the current value)
@description
By default, the propery `selected` is computed from properties `value`
and `selection`, when provided.
The callback is given the `value` property, if any.
The different available kinds for styling a (non-selected) button are:
- `'default'`: normal button;
- `'cancel'`: normal button, in dark grey;
- `'warning'`: warning button, in orange;
- `'positive'`: positive button, in green;
- `'negative'`: negative button, in red.
*/
export const Button = ( props ) => (
<button
disabled={isDisabled(props)}
className={isSelected(props) ? SELECT : (BUTTON + KIND(props.kind))}
onClick={onClick(props)}
title={props.title}
>
{props.icon && <SVG id={props.icon} />}
{props.label && <label>{props.label}</label>}
</button>
);
// --------------------------------------------------------------------------
// --- ToolBar Button Group
// --------------------------------------------------------------------------
/**
@summary Toolbar Button Group.
@property {Button[]} children - Buttons in the group
@property {any} [value] - Passed to children as `selection` property
@property {any} [onChange] - Passed to children as `onClick` property
@property {any} [...props] - Properties passed to all children
*/
export const ButtonGroup = (props) => {
const { children, value, onChange, ...otherProps } = props;
if (value !== undefined) otherProps.selection = value;
if (onChange !== undefined) otherProps.onClick = onChange;
return (
<div className='dome-xToolBar-Group'>
{React.Children.map(children, (elt) => React.cloneElement(elt, otherProps))}
</div>
);
};
// --------------------------------------------------------------------------
// --- ToolBar Menu
// --------------------------------------------------------------------------
/**
@summary Toolbar Selector Menu.
@property {any} [value] - selected option's value
@property {function} [onChange] - selection callback (receives option value)
@property {boolean} [disabled] - disable the selector (default: `false`)
@property {boolean} [enabled] - enable the selector (default: `true`)
@property {option[]} children - Array of menu options
@description
Behaves likes a standard `<select>` element, except that callback directly
receives the select value, not the entire event.
The list of options shall be given with standard `<option value={...} label={...}>`
elements.
*/
export const Select = (props) => (
<select className='dome-xToolBar-Control dome-color-frame'
value={props.value}
disabled={isDisabled(props)}
onChange={(props.onChange && ((evt) => props.onChange(evt.target.value)))}
>
{props.children}
</select>
);
// --------------------------------------------------------------------------
// --- Export & Registration
// --------------------------------------------------------------------------
import { register } from 'dome/misc/register' ;
register( ToolBar, 'DOME_TOOLBAR' );
register( Inset , 'DOME_TOOLBAR_ITEM' );
register( Space , 'DOME_TOOLBAR_ITEM' );
register( Separator , 'DOME_TOOLBAR_ITEM' );
register( Filler , 'DOME_TOOLBAR_ITEM' );
register( Button , 'DOME_TOOLBAR_ITEM' );
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --- ToolBars
// --------------------------------------------------------------------------
/**
@packageDocumentation
@module dome/frame/toolbars
*/
import React from 'react';
import { classes } from 'dome/misc/utils';
import './style.css';
// --------------------------------------------------------------------------
// --- ToolBar Button
// --------------------------------------------------------------------------
import { SVG } from 'dome/controls/icons';
// --------------------------------------------------------------------------
// --- ToolBar Container
// --------------------------------------------------------------------------
export interface ToolBarProps {
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
}
/**
@class
@summary Container for toolbar items.
*/
export function ToolBar(props: ToolBarProps) {
const { children } = props;
const n = React.Children.count(children);
if (n === 0) return null;
const className = classes(
'dome-xToolBar',
'dome-color-frame',
props.className,
);
return (
<div className={className} style={props.style}>
<div className="dome-xToolBar-inset" />
{children}
<div className="dome-xToolBar-inset" />
</div>
);
}
// --------------------------------------------------------------------------
// --- ToolBar Spaces
// --------------------------------------------------------------------------
/** Fixed (tiny) space. */
export const Inset = (() => <div className="dome-xToolBar-inset" />);
/** Fixed space. */
export const Space = (() => <div className="dome-xToolBar-space" />);
/** Auto-extensible space. */
export const Filler = (() => <div className="dome-xToolBar-filler" />);
/** Fixed space with vertical rule. */
export const Separator = () => (
<div className="dome-xToolBar-separator">
<div className="dome-xToolBar-vrule" />
</div>
);
const SELECT = 'dome-xToolBar-Control dome-selected';
const BUTTON = 'dome-xToolBar-Control dome-color-frame';
const KIND = (kind: undefined | string) => (
kind ? ` dome-xToolBar-${kind}` : ''
);
interface SELECT<A> {
selected?: boolean;
selection?: A;
value?: A;
}
export type ButtonKind =
| 'default' | 'cancel' | 'warning' | 'positive' | 'negative';
export interface ButtonProps<A> {
/** Button icon, Cf. [gallery](gallery-icons.html). */
icon?: string;
/** Button label. */
label?: string;
/** Button tooltip text. */
title?: string;
/** Button kind. */
kind?: ButtonKind;
/** Enabled State (default `true`). */
enabled?: boolean;
/** Disabled State (default `false`). */
disabled?: boolean;
/** Selection State (defaults to `false` or `selection` equal to `value`). */
selected?: boolean;
/** Button's value. */
value?: A;
/** Currently selected value. */
selection?: A;
/** Selection callback. Receives the button's value. */
onClick?: (value: A | undefined) => void;
}
/** Toolbar Button. */
export function Button<A = undefined>(props: ButtonProps<A>) {
const { selected, value, selection, onClick } = props;
const { enabled = true, disabled = false } = props;
const isSelected = selected !== undefined
? selected
: (value !== undefined && value === selection);
return (
<button
type="button"
disabled={disabled || !enabled}
className={isSelected ? SELECT : (BUTTON + KIND(props.kind))}
onClick={onClick && (() => onClick(value))}
title={props.title}
>
{props.icon && <SVG id={props.icon} />}
{props.label && <label>{props.label}</label>}
</button>
);
}
// --------------------------------------------------------------------------
// --- Selection Props
// --------------------------------------------------------------------------
export interface SelectionProps<A> {
/** Enabled Group (default `true`). */
enabled?: boolean;
/** Disabled Group (default `false`). */
disabled?: boolean;
/** Currently selected button. */
value?: A;
/** Callback on clicked buttons. */
onChange?: (value: undefined | A) => void;
/** Buttons array. */
children: React.ReactElement[];
}
// --------------------------------------------------------------------------
// --- ToolBar Button Group
// --------------------------------------------------------------------------
/**
Toolbar Button Group.
Properties of the button group are passed down the buttons of the group
as appropriate defaults.
*/
export function ButtonGroup<A>(props: SelectionProps<A>) {
const { children, value, onChange, enabled, disabled } = props;
const baseProps: ButtonProps<A> = {
enabled,
disabled,
selection: value,
onClick: onChange,
};
return (
<div className="dome-xToolBar-Group">
{React.Children.map(children, (elt) => React.cloneElement(
elt,
{ ...baseProps, ...elt.props },
))}
</div>
);
}
// --------------------------------------------------------------------------
// --- ToolBar Menu
// --------------------------------------------------------------------------
/** Toolbar Selector Menu.
Behaves likes a standard `<select>` element, except that callback directly
receives the select value, not the entire event.
The list of options shall be given with standard
`<option value={...} label={...}>` elements.
*/
export function Select(props: SelectionProps<string>) {
const { enabled = true, disabled = false, onChange } = props;
const callback = (evt: React.ChangeEvent<HTMLSelectElement>) => {
if (onChange) onChange(evt.target.value);
};
return (
<select
className="dome-xToolBar-Control dome-color-frame"
value={props.value}
disabled={disabled || !enabled}
onChange={callback}
>
{props.children}
</select>
);
}
// --------------------------------------------------------------------------
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment