jiro-ui
Version:
A Mithril.js UI library based from construct-ui
115 lines (91 loc) • 3.16 kB
text/typescript
import m from 'mithril';
import classnames from 'classnames';
import { Classes, safeCall, getClosest, IAttrs } from '../../_shared';
import { Icon, Icons } from '../icon';
export interface ITreeNodeAttrs extends IAttrs {
key: number | string;
/** Right-justified content */
contentRight?: m.Children;
/** Left-justified content */
contentLeft?: m.Children;
/** Array of TreeNodes */
children?: m.Vnode<ITreeNodeAttrs>[];
/** Toggles caret visiblity */
hasCaret?: boolean;
/** Wether children are expanded */
isExpanded?: boolean;
/** Wether node is selected */
isSelected?: boolean;
/** Inner label or children */
label?: m.Children;
/** Callback invoked on tree node click */
onClick?: (node: ITreeNodeAttrs, e: Event) => void;
/** Callback invoked when caret is collapsed */
onCollapse?: (node: ITreeNodeAttrs, e: Event) => void;
/** Callback invoked when caret is expanded */
onExpand?: (node: ITreeNodeAttrs, e: Event) => void;
[htmlAttrs: string]: any;
}
export class TreeNode implements m.Component<ITreeNodeAttrs> {
public view({ attrs }: m.Vnode<ITreeNodeAttrs>) {
const {
contentLeft,
contentRight,
class: className,
children,
hasCaret,
isExpanded,
isSelected,
label,
onClick,
onCollapse,
onExpand,
...htmlAttrs
} = attrs;
const caretClasses = classnames(
Classes.TREE_NODE_CARET,
!hasCaret && Classes.TREE_NODE_CARET_NONE,
hasCaret && (isExpanded ? Classes.TREE_NODE_CARET_OPEN : Classes.TREE_NODE_CARET_CLOSED)
);
const caret = m(Icon, {
class: caretClasses,
name: Icons.CHEVRON_RIGHT,
onclick: (e: Event) => this.handleCaretClick(e, attrs)
});
const innerContent = [
caret,
contentLeft && m('', { class: Classes.TREE_NODE_CONTENT_LEFT }, contentLeft),
label && m('', { class: Classes.TREE_NODE_LABEL }, label),
contentRight && m('', { class: Classes.TREE_NODE_CONTENT_RIGHT }, contentRight)
];
const content = m('', {
class: Classes.TREE_NODE_CONTENT,
onclick: (e: Event) => this.handleClick(e, attrs)
}, innerContent);
const treeNodeClasses = classnames(
Classes.TREE_NODE,
isSelected && Classes.TREE_NODE_SELECTED,
isExpanded && Classes.TREE_NODE_EXPANDED,
className
);
return m('li', { class: treeNodeClasses, ...htmlAttrs }, [
content,
isExpanded && m('ul', { class: Classes.TREE_NODE_LIST }, children)
]);
}
private handleCaretClick(e: Event, attrs: ITreeNodeAttrs) {
const { onCollapse, onExpand, isExpanded } = attrs;
if (onCollapse || onExpand) {
e.stopPropagation();
safeCall(isExpanded ? onCollapse : onExpand, attrs, e);
} else (e as any).redraw = false;
}
private handleClick(e: Event, attrs: ITreeNodeAttrs) {
const { onClick } = attrs;
const el = e.target as HTMLElement;
const isClickOnRightContent = getClosest(el, `.${Classes.TREE_NODE_CONTENT_RIGHT}`);
if (onClick && !isClickOnRightContent) {
safeCall(onClick, attrs, e);
} else (e as any).redraw = false;
}
}