diagram-js
Version:
A toolbox for displaying and modifying diagrams on the web
107 lines (92 loc) • 3.17 kB
JavaScript
import classNames from 'clsx';
import {
html,
useMemo
} from '../../ui';
/**
* @typedef {import('./PopupMenuProvider').PopupMenuHeaderEntry} PopupMenuHeaderEntry
*/
/**
* Component that renders a popup menu header.
*
* @param {Object} props
* @param {PopupMenuHeaderEntry[]} props.headerEntries
* @param {PopupMenuHeaderEntry} props.selectedEntry
* @param {(event: MouseEvent, entry: PopupMenuHeaderEntry) => void} props.onSelect
* @param {(entry: PopupMenuHeaderEntry | null) => void} props.setSelectedEntry
* @param {string} props.title
*/
export default function PopupMenuHeader(props) {
const {
headerEntries,
onSelect,
selectedEntry,
setSelectedEntry,
title
} = props;
const groups = useMemo(() => groupEntries(headerEntries), [ headerEntries ]);
const isActionable = (entry) => {
return entry.action && !entry.disabled;
};
const handleClick = (event, entry) => {
if (!isActionable(entry)) {
return;
}
return onSelect(event, entry);
};
return html`
<div class="djs-popup-header">
<h3 class="djs-popup-title" title=${ title }>${ title }</h3>
${ groups.map((group) => html`
<ul key=${ group.id } class="djs-popup-header-group" data-header-group=${ group.id }>
${ group.entries.map(entry => html`
<li key=${ entry.id }>
<${ isActionable(entry) ? 'button' : 'span' }
class=${ getHeaderClasses(entry, entry === selectedEntry) }
onClick=${ event => handleClick(event, entry) }
title=${ entry.title || entry.label }
data-id=${ entry.id }
aria-disabled=${ entry.disabled || undefined }
onMouseEnter=${ () => isActionable(entry) && setSelectedEntry(entry) }
onMouseLeave=${ () => isActionable(entry) && setSelectedEntry(null) }
onFocus=${ () => isActionable(entry) && setSelectedEntry(entry) }
onBlur=${ () => isActionable(entry) && setSelectedEntry(null) }
>
${(entry.imageUrl && html`<img class="djs-popup-entry-icon" src=${ entry.imageUrl } alt="" />`) ||
(entry.imageHtml && html`<div class="djs-popup-entry-icon" dangerouslySetInnerHTML=${ { __html: entry.imageHtml } } />`)}
${ entry.label ? html`
<span class="djs-popup-label">${ entry.label }</span>
` : null }
</${ entry.action ? 'button' : 'span' }>
</li>
`) }
</ul>
`) }
</div>
`;
}
// helpers
function groupEntries(entries) {
return entries.reduce((groups, entry) => {
const groupId = entry.group || 'default';
const group = groups.find(group => group.id === groupId);
if (group) {
group.entries.push(entry);
} else {
groups.push({
id: groupId,
entries: [ entry ]
});
}
return groups;
}, []);
}
function getHeaderClasses(entry, selected) {
return classNames(
'entry',
entry.className,
entry.active ? 'active' : '',
entry.disabled ? 'disabled' : '',
selected ? 'selected' : ''
);
}