import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, DocListCast } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { listSpec } from '../../../fields/Schema'; import { Cast, StrCast, NumCast, BoolCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxBaseComponent } from '../DocComponent'; import { StyleProp } from '../StyleProvider'; import { FieldView, FieldViewProps } from './FieldView'; import BigText from './LabelBigText'; import './LabelBox.scss'; export interface LabelBoxProps { label?: string; } @observer export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxProps)>() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); } public static LayoutStringWithTitle(fieldStr: string, label?: string) { return !label ? LabelBox.LayoutString(fieldStr) : ``; //e.g., "" } private dropDisposer?: DragManager.DragDropDisposer; private _timeout: any; componentDidMount() { this.props.setContentView?.(this); } componentWillUnMount() { this._timeout && clearTimeout(this._timeout); } getTitle() { return this.rootDoc["title-custom"] ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label : typeof this.rootDoc[this.fieldKey] === "string" ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title); } protected createDropTarget = (ele: HTMLDivElement) => { this.dropDisposer?.(); if (ele) { this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document); } } get paramsDoc() { return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc; } specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; !Doc.noviceMode && funcs.push({ description: "Clear Script Params", event: () => { const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); params?.map(p => this.paramsDoc[p] = undefined); }, icon: "trash" }); funcs.length && ContextMenu.Instance.addItem({ description: "OnClick...", noexpand: true, subitems: funcs, icon: "mouse-pointer" }); } @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { const docDragData = de.complete.docDragData; const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); const missingParams = params?.filter(p => !this.paramsDoc[p]); if (docDragData && missingParams?.includes((e.target as any).textContent)) { this.paramsDoc[(e.target as any).textContent] = new List(docDragData.droppedDocuments.map((d, i) => d.onDragStart ? docDragData.draggedDocuments[i] : d)); e.stopPropagation(); } } @observable _mouseOver = false; @computed get hoverColor() { return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : "unset"; } fitTextToBox = (r: any): any => { const singleLine = BoolCast(this.rootDoc._singleLine, true); const params = { rotateText: null, fontSizeFactor: 1, minimumFontSize: NumCast(this.rootDoc._minFontSize, 8), maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000), limitingDimension: "both", horizontalAlign: "center", verticalAlign: "center", textAlign: "center", singleLine, whiteSpace: singleLine ? "nowrap" : "pre-wrap" }; this._timeout = undefined; if (!r) return params; if (!r.offsetHeight || !r.offsetWidth) return this._timeout = setTimeout(() => this.fitTextToBox(r)); const parent = r.parentNode; const parentStyle = parent.style; parentStyle.display = ""; parentStyle.alignItems = ""; r.setAttribute("style", ""); r.style.width = singleLine ? "" : "100%"; r.style.textOverflow = "ellipsis"; r.style.overflow = "hidden"; BigText(r, params); return params; } // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")") render() { const boxParams = this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); const missingParams = params?.filter(p => !this.paramsDoc[p]); params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ... const label = this.getTitle(); return (
this._mouseOver = false)} onMouseOver={action(() => this._mouseOver = true)} ref={this.createDropTarget} onContextMenu={this.specificContextMenu} style={{ boxShadow: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BoxShadow) }}>
this.fitTextToBox(r))}> {label.startsWith("#") ? (null) : label.replace(/([^a-zA-Z])/g, "$1\u200b")}
{!missingParams?.length ? (null) : missingParams.map(m =>
{m}
)}
); } }