src/components/detailed-list/detailed-list-item.ts (161 lines of code) (raw):
import { DomBuilder, ExtendedHTMLElement } from '../../helper/dom';
import { cancelEvent } from '../../helper/events';
import testIds from '../../helper/test-ids';
import { ChatItemButton, DetailedListItem } from '../../static';
import { Button } from '../button';
import { Icon, MynahIcons } from '../icon';
import { Overlay, OverlayHorizontalDirection, OverlayVerticalDirection } from '../overlay';
import { parseMarkdown } from '../../helper/marked';
export interface DetailedListItemWrapperProps {
listItem: DetailedListItem;
descriptionTextDirection?: 'ltr' | 'rtl';
onSelect?: (detailedListItem: DetailedListItem) => void;
onActionClick?: (action: ChatItemButton) => void;
selectable?: boolean;
textDirection?: 'row' | 'column';
}
export class DetailedListItemWrapper {
render: ExtendedHTMLElement;
private readonly props: DetailedListItemWrapperProps;
private actionMenuOverlay: Overlay | undefined;
constructor (props: DetailedListItemWrapperProps) {
this.props = props;
this.render = DomBuilder.getInstance().build({
type: 'div',
testId: testIds.prompt.quickPickItem,
classNames: [ 'mynah-detailed-list-item' ],
attributes: {
disabled: this.props.listItem.disabled ?? 'false',
selectable: this.props.selectable ?? 'true',
},
events: {
click: (e) => {
cancelEvent(e);
if (this.props.listItem.disabled !== true && this.props.selectable !== false) {
this.props.onSelect?.(this.props.listItem);
}
}
},
children: [
...(this.props.listItem.icon != null
? [
{
type: 'div',
classNames: [ 'mynah-detailed-list-icon' ],
children: [
new Icon({
icon: this.props.listItem.icon
}).render
]
}
]
: []),
{
type: 'div',
classNames: [ 'mynah-detailed-list-item-text', 'mynah-detailed-list-item-text-direction-' + (this.props.textDirection ?? 'row') ],
children: [
...(this.props.listItem.title != null || this.props.listItem.name != null
? [ {
type: 'div',
classNames: [ 'mynah-detailed-list-item-name' ],
innerHTML: this.props.listItem.title ?? this.props.listItem.name
} ]
: []),
...(this.props.listItem.description != null
? [ {
type: 'div',
classNames: [ 'mynah-detailed-list-item-description', this.props.descriptionTextDirection ?? 'ltr' ],
innerHTML: `<bdi>${parseMarkdown(this.props.listItem.description.replace(/ /g, ' ').replace(/\n\s*\n/g, ' '), { includeLineBreaks: false, inline: true })}</bdi>`
} ]
: [])
]
},
...((this.props.listItem.children != null) && this.props.listItem.children.length > 0
? [
{
type: 'div',
classNames: [ 'mynah-detailed-list-item-arrow-icon' ],
children: [
new Icon({ icon: 'right-open' }).render
]
}
]
: []),
...(this.props.listItem.actions != null
? this.props.listItem.actions.length > 1
? [ {
type: 'div',
classNames: [ 'mynah-detailed-list-item-actions' ],
children: [ new Button({
testId: testIds.detailedList.actionMenu,
icon: new Icon({ icon: MynahIcons.ELLIPSIS }).render,
primary: false,
onClick: (e) => {
cancelEvent(e);
this.showActionMenuOverlay();
},
}).render ]
} ]
: [ {
type: 'div',
classNames: [ 'mynah-detailed-list-item-actions' ],
children: this.props.listItem.actions.map((action) => this.getActionButton(action, false))
} ]
: []),
]
});
}
public readonly setFocus = (isFocused: boolean, scrollIntoView: boolean): void => {
if (isFocused) {
this.render.addClass('target-command');
if (scrollIntoView) {
this.render.scrollIntoView(true);
}
} else {
this.render.removeClass('target-command');
}
};
public readonly getItem = (): DetailedListItem => {
return this.props.listItem;
};
private readonly showActionMenuOverlay = (): void => {
this.actionMenuOverlay = new Overlay({
background: true,
closeOnOutsideClick: true,
referenceElement: this.render,
dimOutside: false,
removeOtherOverlays: true,
verticalDirection: OverlayVerticalDirection.CENTER,
horizontalDirection: OverlayHorizontalDirection.END_TO_LEFT,
children: [
{
type: 'div',
classNames: [ 'mynah-detailed-list-item-actions-overlay' ],
children: this.props.listItem.actions?.map((action) => this.getActionButton(action, true))
}
],
});
};
private getActionButton (action: ChatItemButton, showText?: boolean): ExtendedHTMLElement {
return new Button({
testId: testIds.detailedList.action,
icon: action.icon ? new Icon({ icon: action.icon }).render : undefined,
...(action.text !== undefined && showText === true ? { label: action.text } : {}),
attributes: {
title: action.description ?? ''
},
primary: false,
onClick: (e) => {
cancelEvent(e);
this.props.onActionClick?.(action);
this.hideActionMenuOverlay();
},
}).render;
}
private readonly hideActionMenuOverlay = (): void => {
if (this.actionMenuOverlay !== undefined) {
this.actionMenuOverlay.close();
this.actionMenuOverlay = undefined;
}
};
}