You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.6 KiB
JavaScript
96 lines
2.6 KiB
JavaScript
"use strict";
|
|
|
|
const React = require("react");
|
|
const asExpression = require("as-expression");
|
|
|
|
const defaultStyle = require("./style.css");
|
|
const useTheme = require("../../util/themeable");
|
|
const ListItemContext = require("../../contexts/list-item");
|
|
const comparePath = require("../../util/compare-path");
|
|
const useClickTimer = require("../../util/use-click-timer");
|
|
|
|
function Expander({ expanded, onClick }) {
|
|
let { withTheme } = useTheme({ control: "list", defaultStyle });
|
|
|
|
return (
|
|
<div className={withTheme("expander")} onClick={onClick}>
|
|
{(expanded === true)
|
|
? "▼"
|
|
: "▶"}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function ExpanderPlaceholder() {
|
|
let { withTheme } = useTheme({ control: "list", defaultStyle });
|
|
|
|
return <div className={withTheme("expanderPlaceholder")} />;
|
|
}
|
|
|
|
module.exports = function ListItem({ label, id, children }) {
|
|
let { onClick, onDoubleClick, path, selectedPath } = React.useContext(ListItemContext);
|
|
let [ expanded, setExpanded ] = React.useState(true);
|
|
let { withTheme } = useTheme({ control: "list", defaultStyle });
|
|
let doubleClickTimer = useClickTimer(500);
|
|
|
|
let depth = path.length;
|
|
let indent = depth * 11; // FIXME: Figure out a way to do this with CSS instead, eg. via value exports?
|
|
let ownPath = path.concat([ id ]);
|
|
let isSelected = comparePath(selectedPath, ownPath);
|
|
|
|
function handleClick() {
|
|
if (doubleClickTimer.click()) {
|
|
if (onDoubleClick != null) {
|
|
onDoubleClick(ownPath);
|
|
} else if (children != null) {
|
|
// TODO: Check whether we really only want to do this when no onDoubleClick handler is specified, ie. only as a default behaviour
|
|
toggleExpanded();
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleMouseDown() {
|
|
if (doubleClickTimer.mouseDown()) {
|
|
onClick(ownPath);
|
|
}
|
|
}
|
|
|
|
function toggleExpanded() {
|
|
setExpanded((expanded) => !expanded);
|
|
}
|
|
|
|
let style = {
|
|
paddingLeft: `${indent}px`
|
|
};
|
|
|
|
return (
|
|
<React.Fragment>
|
|
{/* FIXME: item_selected capitalization */}
|
|
<div className={withTheme(["item", { item_selected: isSelected }])} style={style} onMouseDown={handleMouseDown} onClick={handleClick}>
|
|
{(children != null)
|
|
? <Expander expanded={expanded} onClick={toggleExpanded} />
|
|
: <ExpanderPlaceholder />}
|
|
<div className={withTheme("label")}>
|
|
{label}
|
|
</div>
|
|
</div>
|
|
{(children != null && expanded === true)
|
|
? asExpression(() => {
|
|
let itemContext = {
|
|
path: ownPath,
|
|
selectedPath: selectedPath,
|
|
onClick: onClick,
|
|
onDoubleClick: onDoubleClick
|
|
};
|
|
|
|
return (
|
|
<ListItemContext.Provider value={itemContext}>
|
|
{children}
|
|
</ListItemContext.Provider>
|
|
);
|
|
})
|
|
: null}
|
|
</React.Fragment>
|
|
);
|
|
};
|