diff options
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 173 |
1 files changed, 104 insertions, 69 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 6647a1354..351fdce79 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1,13 +1,12 @@ /* eslint-disable no-use-before-define */ -/* eslint-disable react/jsx-props-no-spreading */ -/* eslint-disable jsx-a11y/no-static-element-interactions */ import { IconProp } from '@fortawesome/fontawesome-svg-core'; +import { Property } from 'csstype'; import { Howl } from 'howler'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Fade, JackInTheBox } from 'react-awesome-reveal'; -import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simulateMouseClick } from '../../../ClientUtils'; +import { ClientUtils, DivWidth, isTargetChildOf as isParentOf, lightOrDark, returnFalse, returnVal, simMouseEvent, simulateMouseClick } from '../../../ClientUtils'; import { Utils, emptyFunction } from '../../../Utils'; import { Doc, DocListCast, Field, FieldType, Opt, StrListCast } from '../../../fields/Doc'; import { AclAdmin, AclEdit, AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols'; @@ -33,7 +32,7 @@ import { UPDATE_SERVER_CACHE } from '../../util/LinkManager'; import { ScriptingGlobals } from '../../util/ScriptingGlobals'; import { SearchUtil } from '../../util/SearchUtil'; import { SnappingManager } from '../../util/SnappingManager'; -import { UndoManager, undoBatch, undoable } from '../../util/UndoManager'; +import { UndoManager, undoable } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { DocComponent } from '../DocComponent'; @@ -55,13 +54,6 @@ import { PresEffect, PresEffectDirection } from './trails/PresEnums'; import SpringAnimation from './trails/SlideEffect'; import { SpringType, springMappings } from './trails/SpringUtils'; -interface Window { - MediaRecorder: MediaRecorder; -} -declare class MediaRecorder { - constructor(e: any); // whatever MediaRecorder has -} - export interface DocumentViewProps extends FieldViewSharedProps { hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected hideResizeHandles?: boolean; // whether to suppress resized handles on doc decorations when this document is selected @@ -73,7 +65,7 @@ export interface DocumentViewProps extends FieldViewSharedProps { hideLinkAnchors?: boolean; hideLinkButton?: boolean; hideCaptions?: boolean; - contentPointerEvents?: 'none' | 'all' | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents + contentPointerEvents?: Property.PointerEvents | undefined; // pointer events allowed for content of a document view. eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents dontCenter?: 'x' | 'y' | 'xy'; childHideDecorationTitle?: boolean; childHideResizeHandles?: boolean; @@ -89,7 +81,7 @@ export interface DocumentViewProps extends FieldViewSharedProps { dragStarting?: () => void; dragEnding?: () => void; - parent?: any; // parent React component view (see CollectionFreeFormDocumentView) + reactParent?: React.Component; // parent React component view (see CollectionFreeFormDocumentView) } @observer export class DocumentViewInternal extends DocComponent<FieldViewProps & DocumentViewProps>() { @@ -105,7 +97,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document private _disposers: { [name: string]: IReactionDisposer } = {}; private _doubleClickTimeout: NodeJS.Timeout | undefined; - private _singleClickFunc: undefined | (() => any); + private _singleClickFunc: undefined | (() => void); private _longPressSelector: NodeJS.Timeout | undefined; private _downX: number = 0; private _downY: number = 0; @@ -125,7 +117,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document @observable _titleDropDownInnerWidth = 0; // width of menu dropdown when setting doc title @observable _mounted = false; // turn off all pointer events if component isn't yet mounted (enables nested Docs in alternate UI textboxes that appear on hover which otherwise would grab focus from the text box, reverting to the original UI ) @observable _isContentActive: boolean | undefined = undefined; - @observable _pointerEvents: 'none' | 'all' | 'visiblePainted' | undefined = undefined; + @observable _pointerEvents: Property.PointerEvents | undefined = undefined; @observable _componentView: Opt<ViewBoxInterface<FieldViewProps>> = undefined; // needs to be accessed from DocumentView wrapper class @observable _animateScaleTime: Opt<number> = undefined; // milliseconds for animating between views. defaults to 300 if not uset @observable _animateScalingTo = 0; @@ -135,16 +127,16 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document animateScaleTime = () => this._animateScaleTime ?? 100; style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop); - @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity); } // prettier-ignore - @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow); } // prettier-ignore - @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding); } // prettier-ignore - @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations); } // prettier-ignore - @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView'); } // prettier-ignore + @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity) as number; } // prettier-ignore + @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow) as string; } // prettier-ignore + @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding) as string; } // prettier-ignore + @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations) as JSX.Element; } // prettier-ignore + @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView') as string; } // prettier-ignore @computed get showTitle() { return this.style(this.layoutDoc, StyleProp.ShowTitle) as Opt<string>; } // prettier-ignore - @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) ?? 0; } // prettier-ignore - @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) ?? 0; } // prettier-ignore - @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) ?? 0; } // prettier-ignore - @computed get docContents() { return this.style(this.Document, StyleProp.DocContents); } // prettier-ignore + @computed get showCaption() { return this.style(this.layoutDoc, StyleProp.ShowCaption) as string ?? ""; } // prettier-ignore + @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) as number ?? 0; } // prettier-ignore + @computed get titleHeight() { return this.style(this.layoutDoc, StyleProp.TitleHeight) as number ?? 0; } // prettier-ignore + @computed get docContents() { return this.style(this.Document, StyleProp.DocContents) as JSX.Element; } // prettier-ignore @computed get highlighting() { return this.style(this.Document, StyleProp.Highlighting); } // prettier-ignore @computed get borderPath() { return this.style(this.Document, StyleProp.BorderPath); } // prettier-ignore @@ -165,13 +157,13 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document /// disable pointer events on content when there's an enabled onClick script (and not in explore mode) and the contents aren't forced active, or if contents are marked inactive @computed get _contentPointerEvents() { TraceMobx(); - return this._props.contentPointerEvents ?? + return (this._props.contentPointerEvents ?? ((!this.disableClickScriptFunc && // this.onClickHdlr && !SnappingManager.ExploreMode && !this.layoutDoc.layout_isSvg && this.isContentActive() !== true) || - this.isContentActive() === false) + this.isContentActive() === false)) ? 'none' : this._pointerEvents; } @@ -225,7 +217,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document { fireImmediately: true } ); this._disposers.pointerevents = reaction( - () => this.style(this.Document, StyleProp.PointerEvents), + () => this.style(this.Document, StyleProp.PointerEvents) as Property.PointerEvents | undefined, pointerevents => { this._pointerEvents = pointerevents; }, @@ -252,7 +244,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document Object.values(this._disposers).forEach(disposer => disposer?.()); } - startDragging(x: number, y: number, dropAction: dropActionType, hideSource = false) { + startDragging(x: number, y: number, dropAction: dropActionType | undefined, hideSource = false) { const docView = this._docView; if (this._mainCont.current && docView) { const views = DocumentView.Selected().filter(dv => dv.ContentDiv); @@ -319,7 +311,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick; undoable(() => { if (this.onDoubleClickHdlr?.script) { - this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false); + const res = this.onDoubleClickHdlr.script.run(scriptProps, console.log).result as { select: boolean }; + res.select && this._props.select(false); } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') { this._props.addDocTab(this.Document, OpenWhere.lightboxAlways); DocumentView.DeselectAll(); @@ -348,7 +341,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if ((clickFunc && waitForDblClick !== 'never') || waitForDblClick === 'always') { this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout); this._doubleClickTimeout = setTimeout(this._singleClickFunc, 300); - // eslint-disable-next-line no-use-before-define } else if (!SnappingManager.LongPress) { this._singleClickFunc(); this._singleClickFunc = undefined; @@ -361,7 +353,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document onPointerDown = (e: React.PointerEvent): void => { if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return; - // eslint-disable-next-line no-use-before-define this._longPressSelector = setTimeout(() => SnappingManager.LongPress && this._props.select(false), 1000); if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView; @@ -412,7 +403,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document this._doubleTap = (this.onDoubleClickHdlr?.script || this.Document.defaultDoubleClick !== 'ignore') && Date.now() - this._lastTap < ClientUtils.CLICK_TIME; if (!this.isContentActive()) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected } - // eslint-disable-next-line no-use-before-define if (SnappingManager.LongPress) e.preventDefault(); }; @@ -451,7 +441,11 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (this.Document === Doc.ActiveDashboard) { e.stopPropagation(); e.preventDefault(); - alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document." : 'Linking to document tabs not yet supported.'); + alert( + (e.target as HTMLElement)?.closest?.('*.lm_content') + ? "You can't perform this move most likely because you didn't drag the document's title bar to enable embedding in a different document." + : 'Linking to document tabs not yet supported.' + ); return true; } const annoData = de.complete.annoDragData; @@ -496,6 +490,21 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document input.click(); }; + askGPT = async (): Promise<string | undefined> => { + const queryText = RTFCast(DocCast(this.dataDoc[this.props.fieldKey + '_1']).text)?.Text; + try { + const res = await gptAPICall('Question: ' + StrCast(queryText), GPTCallType.CHATCARD); + if (!res) { + console.error('GPT call failed'); + return; + } + DocCast(this.dataDoc[this.props.fieldKey + '_0'])[DocData].text = res; + console.log(res); + } catch (err) { + console.error('GPT call failed', err); + } + }; + onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => { if (this._props.dontSelect?.()) return; if (e && this.layoutDoc.layout_hideContextMenu && Doc.noviceMode) { @@ -519,9 +528,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document } const cm = ContextMenu.Instance; - if (!cm || (e as any)?.nativeEvent?.SchemaHandled || SnappingManager.ExploreMode) return; + if (!cm || SnappingManager.ExploreMode) return; - if (e && !(e.nativeEvent as any).dash) { + if (e && !(e.nativeEvent instanceof simMouseEvent ? e.nativeEvent.dash : false)) { const onDisplay = () => { if (this.Document.type !== DocumentType.MAP) DocumentViewInternal.SelectAfterContextMenu && this._props.select(false); // on a mac, the context menu is triggered on mouse down, but a YouTube video becaomes interactive when selected which means that the context menu won't show up. by delaying the selection until hopefully after the pointer up, the context menu will appear. setTimeout(() => simulateMouseClick(document.elementFromPoint(e.clientX, e.clientY), e.clientX, e.clientY, e.screenX, e.screenY)); @@ -549,12 +558,15 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (!this.Document.isFolder) { const templateDoc = Cast(this.Document[StrCast(this.Document.layout_fieldKey)], Doc, null); const appearance = cm.findByDescription('Appearance...'); - const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : []; + const appearanceItems = appearance?.subitems ?? []; if (this._props.renderDepth === 0) { appearanceItems.splice(0, 0, { description: 'Open in Lightbox', event: () => DocumentView.SetLightboxDoc(this.Document), icon: 'external-link-alt' }); } - appearanceItems.push({ description: 'Pin', event: () => this._props.pinToPres(this.Document, {}), icon: 'eye' }); + appearanceItems.push({ description: 'Pin', event: () => this._props.pinToPres(this.Document, {}), icon: 'map-pin' }); + if (this.Document._layout_isFlashcard) { + appearanceItems.push({ description: 'Create ChatCard', event: () => this.askGPT(), icon: 'id-card' }); + } !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this._props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' }); !appearance && appearanceItems.length && cm.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'compass' }); @@ -570,15 +582,16 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (this._props.bringToFront) { const zorders = cm.findByDescription('ZOrder...'); - const zorderItems: ContextMenuProps[] = zorders && 'subitems' in zorders ? zorders.subitems : []; + const zorderItems = zorders?.subitems ?? []; zorderItems.push({ description: 'Bring to Front', event: () => DocumentView.Selected().forEach(dv => dv._props.bringToFront?.(dv.Document, false)), icon: 'arrow-up' }); zorderItems.push({ description: 'Send to Back', event: () => DocumentView.Selected().forEach(dv => dv._props.bringToFront?.(dv.Document, true)), icon: 'arrow-down' }); zorderItems.push({ description: !this.layoutDoc._keepZDragged ? 'Keep ZIndex when dragged' : 'Allow ZIndex to change when dragged', - event: undoBatch( + event: undoable( action(() => { this.layoutDoc._keepZWhenDragged = !this.layoutDoc._keepZWhenDragged; - }) + }), + 'set zIndex drag' ), icon: 'hand-point-up', }); @@ -587,7 +600,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (!Doc.IsSystem(this.Document) && !this.Document.hideClickBehaviors && !this._props.hideClickBehaviors) { const existingOnClick = cm.findByDescription('OnClick...'); - const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : []; + const onClicks = existingOnClick?.subitems ?? []; onClicks.push({ description: 'Enter Portal', event: undoable(() => DocUtils.makeIntoPortal(this.Document, this.layoutDoc, this._allLinks), 'make into portal'), icon: 'window-restore' }); !Doc.noviceMode && onClicks.push({ description: 'Toggle Detail', event: this.setToggleDetail, icon: 'concierge-bell' }); @@ -612,7 +625,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document } const more = cm.findByDescription('More...'); - const moreItems = more && 'subitems' in more ? more.subitems : []; + const moreItems = more?.subitems ?? []; if (!Doc.IsSystem(this.Document)) { if (!Doc.noviceMode) { moreItems.push({ description: 'Make View of Metadata Field', event: () => Doc.MakeMetadataFieldTemplate(this.Document, this._props.TemplateDataDocument), icon: 'concierge-bell' }); @@ -636,7 +649,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document cm.addItem({ description: 'General...', noexpand: false, subitems: constantItems, icon: 'question' }); const help = cm.findByDescription('Help...'); - const helpItems: ContextMenuProps[] = help && 'subitems' in help ? help.subitems : []; + const helpItems = help?.subitems ?? []; !Doc.noviceMode && helpItems.push({ description: 'Text Shortcuts Ctrl+/', event: () => this._props.addDocTab(Docs.Create.PdfDocument('/assets/cheat-sheet.pdf', { _width: 300, _height: 300 }), OpenWhere.addRight), icon: 'keyboard' }); !Doc.noviceMode && helpItems.push({ description: 'Print Document in Console', event: () => console.log(this.Document), icon: 'hand-point-right' }); !Doc.noviceMode && helpItems.push({ description: 'Print DataDoc in Console', event: () => console.log(this.dataDoc), icon: 'hand-point-right' }); @@ -706,7 +719,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document anchorPanelWidth = () => this._props.PanelWidth() || 1; anchorPanelHeight = () => this._props.PanelHeight() || 1; - anchorStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => { + anchorStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => { // prettier-ignore switch (property.split(':')[0]) { case StyleProp.ShowTitle: return ''; @@ -754,7 +767,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document captionStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); fieldsDropdown = (placeholder: string) => ( <div - ref={action((r: any) => { r && (this._titleDropDownInnerWidth = DivWidth(r));} )} // prettier-ignore + ref={r => { r && runInAction(() => (this._titleDropDownInnerWidth = DivWidth(r)));}} // prettier-ignore onPointerDown={action(() => { this._changingTitleField = true; })} // prettier-ignore style={{ width: 'max-content', background: SnappingManager.userBackgroundColor, color: SnappingManager.userColor, transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}> <FieldsDropdown @@ -832,7 +845,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document .map(field => Field.toKeyValueString(this.Document, field)) .join('\\') } - SetValue={undoBatch((input: string) => { + SetValue={undoable((input: string) => { if (input?.startsWith('$')) { if (this.layoutDoc.layout_showTitle) { this.layoutDoc._layout_showTitle = input?.substring(1) ? input.substring(1) : undefined; @@ -843,7 +856,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document Doc.SetField(targetDoc, showTitle, input); } return true; - })} + }, 'set title')} /> </div> </div> @@ -881,7 +894,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document const showTitle = this.showTitle?.split(':')[0]; return !DocCast(this.Document) || GetEffectiveAcl(this.dataDoc) === AclPrivate ? null - : this.docContents ?? ( + : (this.docContents ?? ( <div className="documentView-node" id={this.Document.type !== DocumentType.LINK ? this._docView?.DocUniqueId : undefined} @@ -907,27 +920,33 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document )} {this.widgetDecorations ?? null} </div> - ); + )); }; render() { TraceMobx(); const { highlighting, borderPath } = this; + const { highlightIndex, highlightStyle, highlightColor, highlightStroke } = (highlighting as { highlightIndex: number; highlightStyle: string; highlightColor: string; highlightStroke: boolean }) ?? { + highlightIndex: undefined, + highlightStyle: undefined, + highlightColor: undefined, + highlightStroke: undefined, + }; + const { clipPath, jsx } = (borderPath as { clipPath: string; jsx: JSX.Element }) ?? { clipPath: undefined, jsx: undefined }; const boxShadow = !highlighting ? this.boxShadow - : highlighting && this.borderRounding && highlighting.highlightStyle !== 'dashed' - ? `0 0 0 ${highlighting.highlightIndex}px ${highlighting.highlightColor}` + : highlighting && this.borderRounding && highlightStyle !== 'dashed' + ? `0 0 0 ${highlightIndex}px ${highlightColor}` : this.boxShadow || (this.Document.isTemplateForField ? 'black 0.2vw 0.2vw 0.8vw' : undefined); const renderDoc = this.renderDoc({ borderRadius: this.borderRounding, - outline: highlighting && !this.borderRounding && !highlighting.highlightStroke ? `${highlighting.highlightColor} ${highlighting.highlightStyle} ${highlighting.highlightIndex}px` : 'solid 0px', - border: highlighting && this.borderRounding && highlighting.highlightStyle === 'dashed' ? `${highlighting.highlightStyle} ${highlighting.highlightColor} ${highlighting.highlightIndex}px` : undefined, + outline: highlighting && !this.borderRounding && !highlightStroke ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px', + border: highlighting && this.borderRounding && highlightStyle === 'dashed' ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined, boxShadow, - clipPath: borderPath?.clipPath, + clipPath, }); return ( - // eslint-disable-next-line jsx-a11y/click-events-have-key-events <div className={`${DocumentView.ROOT_DIV} docView-hack`} ref={this._mainCont} @@ -941,8 +960,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document borderRadius: this.borderRounding, pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) }}> - {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} - {borderPath?.jsx} + {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG || !renderDoc ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} + {jsx} </div> ); } @@ -952,7 +971,22 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document * @param presEffectDoc presentation effects document that specifies the animation effect parameters * @returns a function that will wrap a JSX animation element wrapping any JSX element */ - public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) { + public static AnimationEffect( + renderDoc: JSX.Element, + presEffectDoc: Opt< + | Doc + | { + presentation_effectDirection?: string; + followLinkAnimDirection?: string; + presentation_transition?: number; + followLinkTransitionTime?: number; + presentation_effectTiming?: number; + presentation_effect?: string; + followLinkAnimEffect?: string; + } + >, + root: Doc + ) { const dir = ((presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) || PresEffectDirection.Center) as PresEffectDirection; const duration = Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)); const effectProps = { @@ -966,7 +1000,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document }; const timing = StrCast(presEffectDoc?.presentation_effectTiming); - const timingConfig = (timing ? JSON.parse(timing) : undefined) ?? { + const timingConfig = (timing ? JSON.parse(timing) : undefined) ?? { type: SpringType.GENTLE, ...springMappings.gentle, }; @@ -1038,7 +1072,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { public static allViews: () => DocumentView[]; public static addView: (dv: DocumentView) => void | undefined; public static removeView: (dv: DocumentView) => void | undefined; - public static addViewRenderedCb: (doc: Opt<Doc>, func: (dv: DocumentView) => any) => boolean; + public static addViewRenderedCb: (doc: Opt<Doc>, func: (dv: DocumentView) => void) => boolean; public static getViews = (doc?: Doc) => Array.from(doc?.[DocViews] ?? []) as DocumentView[]; public static getFirstDocumentView: (toFind: Doc) => DocumentView | undefined; public static getDocumentView: (target: Doc | undefined, preferredCollection?: DocumentView) => Opt<DocumentView>; @@ -1091,7 +1125,8 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { @observable private _htmlOverlayText: Opt<string> = undefined; @observable private _isHovering = false; @observable private _selected = false; - @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing + @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing + @observable public TagPanelHeight = 0; @computed private get shouldNotScale() { return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.(); @@ -1212,7 +1247,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { public setToggleDetail = (scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(scriptFieldKey); public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY); public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents(); - public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); + public startDragging = (x: number, y: number, dropAction: dropActionType | undefined, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource); public showContextMenu = (pageX: number, pageY: number) => this._docViewInternal?.onContextMenu(undefined, pageX, pageY); public toggleNativeDimensions = () => this._docViewInternal && this.Document.type !== DocumentType.INK && Doc.toggleNativeDimensions(this.layoutDoc, this.NativeDimScaling() ?? 1, this._props.PanelWidth(), this._props.PanelHeight()); @@ -1238,7 +1273,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { } public playAnnotation = () => { - const self = this; const audioAnnoState = this.dataDoc.audioAnnoState ?? AudioAnnoState.stopped; const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '_audioAnnotations'], listSpec(AudioField), null); const anno = audioAnnos?.lastElement(); @@ -1251,12 +1285,12 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { autoplay: true, loop: false, volume: 0.5, - onend: action(() => { self.dataDoc.audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore + onend: action(() => { this.dataDoc.audioAnnoState = AudioAnnoState.stopped; }), // prettier-ignore }); this.dataDoc.audioAnnoState = AudioAnnoState.playing; break; case AudioAnnoState.playing: - this.dataDoc[AudioPlay]?.stop(); + (this.dataDoc[AudioPlay] as Howl)?.stop(); this.dataDoc.audioAnnoState = AudioAnnoState.stopped; break; default: @@ -1410,9 +1444,10 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { <div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this._enableHtmlOverlayTransitions ? 0.9 : 0 }}> {DocumentViewInternal.AnimationEffect( <div className="webBox-textHighlight"> + {/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} <ObserverJsxParser autoCloseVoidElements key={42} onError={(e: any) => console.log('PARSE error', e)} renderInWrapper={false} jsx={StrCast(this._htmlOverlayText)} /> </div>, - { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand } as any as Doc, + { ...(this._htmlOverlayEffect ?? {}), presentation_effect: effect ?? PresEffect.Expand }, this.Document )} </div> @@ -1441,11 +1476,11 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { style={{ transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`, - height: this._props.forceAutoHeight ? undefined : yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`), + height: this._props.forceAutoHeight ? undefined : (yshift ?? (this.layout_fitWidth ? `${this.panelHeight}px` : `${(this.effectiveNativeHeight / this.effectiveNativeWidth) * this._props.PanelWidth()}px`)), }}> <DocumentViewInternal {...this._props} - parent={undefined} + reactParent={undefined} isHovering={this.isHovering} fieldKey={this.LayoutFieldKey} DataTransition={this.DataTransition} @@ -1503,7 +1538,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { ) ); } - // eslint-disable-next-line default-param-last + public static FocusOrOpen(docIn: Doc, optionsIn: FocusViewOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { let doc = docIn; const options = optionsIn; |