diff options
Diffstat (limited to 'src/client/views/nodes/DocumentView.tsx')
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 319 |
1 files changed, 198 insertions, 121 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index eb7f333b9..cac276535 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -52,6 +52,7 @@ import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails/PresEnums'; import SpringAnimation from './trails/SlideEffect'; import { SpringType, springMappings } from './trails/SpringUtils'; +import { TagsView } from '../TagsView'; export interface DocumentViewProps extends FieldViewSharedProps { hideDecorations?: boolean; // whether to suppress all DocumentDecorations when doc is selected @@ -85,7 +86,7 @@ export interface DocumentViewProps extends FieldViewSharedProps { reactParent?: React.Component; // parent React component view (see CollectionFreeFormDocumentView) } @observer -export class DocumentViewInternal extends DocComponent<FieldViewProps & DocumentViewProps>() { +export class DocumentViewInternal extends DocComponent<FieldViewProps & DocumentViewProps & { showAIEditor: boolean }>() { // this makes mobx trace() statements more descriptive public get displayName() { return 'DocumentViewInternal(' + this.Document.title + ')'; } // prettier-ignore public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered. @@ -109,7 +110,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document private _mainCont = React.createRef<HTMLDivElement>(); private _titleRef = React.createRef<EditableView>(); private _dropDisposer?: DragManager.DragDropDisposer; - constructor(props: FieldViewProps & DocumentViewProps) { + constructor(props: FieldViewProps & DocumentViewProps & { showAIEditor: boolean }) { super(props); makeObservable(this); } @@ -130,9 +131,10 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document style = (doc: Doc, sprop: StyleProp | string) => this._props.styleProvider?.(doc, this._props, sprop); @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 border() { return this.style(this.layoutDoc, StyleProp.Border) 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 backgroundBoxColor(){ return this.style(this.Document, 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) as string ?? ""; } // prettier-ignore @computed get headerMargin() { return this.style(this.layoutDoc, StyleProp.HeaderMargin) as number ?? 0; } // prettier-ignore @@ -277,16 +279,17 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document setTimeout(() => this._titleRef.current?.setIsFocused(true)); // use timeout in case title wasn't shown to allow re-render so that titleref will be defined }; onBrowseClick = (e: React.MouseEvent) => { - const browseTransitionTime = 500; + //const browseTransitionTime = 500; DocumentView.DeselectAll(); DocumentView.showDocument(this.Document, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => { - const options: FocusViewOptions = { pointFocus: { X: e.clientX, Y: e.clientY }, zoomTime: browseTransitionTime }; + // const options: FocusViewOptions = { pointFocus: { X: e.clientX, Y: e.clientY }, zoomTime: browseTransitionTime }; if (!focused && this._docView) { - this._docView - .docViewPath() - .reverse() - .forEach(cont => cont.ComponentView?.focus?.(cont.Document, options)); - Doc.linkFollowHighlight(this.Document, false); + DocumentView.showDocument(this.Document, { zoomScale: 0.3, willZoomCentered: true }); + // this._docView + // .docViewPath() + // .reverse() + // .forEach(cont => cont.ComponentView?.focus?.(cont.Document, options)); + // Doc.linkFollowHighlight(this.Document, false); } }); e.stopPropagation(); @@ -355,7 +358,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document onPointerDown = (e: React.PointerEvent): void => { if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return; this._longPressSelector = setTimeout(() => SnappingManager.LongPress && this._props.select(false), 1000); - if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView; this._downX = e.clientX; this._downY = e.clientY; @@ -380,7 +382,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document }; onPointerMove = (e: PointerEvent): void => { - if (e.buttons !== 1 || [InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) return; + if (e.buttons !== 1 || Doc.ActiveTool === InkTool.Ink) return; if (!ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) { this.cleanupPointerEvents(); @@ -459,10 +461,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document } if (annoData || this.Document !== linkdrag.linkSourceDoc.embedContainer) { const dropDoc = annoData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.Document; - const linkDoc = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]); + const linkDoc = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, { layout_isSvg: true }, undefined, [de.x, de.y - 50]); if (linkDoc) { de.complete.linkDocument = linkDoc; - linkDoc.layout_isSvg = true; DocumentView.linkCommonAncestor(linkDoc)?.ComponentView?.addDocument?.(linkDoc); } } @@ -553,6 +554,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document 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: 'map-pin' }); + appearanceItems.push({ description: 'AI view', event: () => this._docView?.toggleAIEditor(), icon: 'map-pin' }); !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' }); @@ -684,10 +686,14 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document }; rootSelected = () => this._rootSelected; - panelHeight = () => this._props.PanelHeight() - this.headerMargin; - screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin); + panelHeight = () => this._props.PanelHeight() - this.headerMargin - 2 * NumCast(this.Document.borderWidth); + screenToLocalContent = () => + this._props + .ScreenToLocalTransform() + .translate(-NumCast(this.Document.borderWidth), -this.headerMargin - NumCast(this.Document.borderWidth)) + .scale(this._props.showAIEditor ? (this._props.PanelHeight() || 1) / this.aiContentsHeight() : 1); onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHdlr; - setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height)); } // prettier-ignore + setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height + 2 * NumCast(this.Document.borderWidth))); } // prettier-ignore setContentView = action((view: ViewBoxInterface<FieldViewProps>) => { this._componentView = view; }); // prettier-ignore isContentActive = (): boolean | undefined => this._isContentActive; childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; @@ -711,35 +717,112 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document return this._props.styleProvider?.(doc, props, property); }; + @observable _aiWinHeight = 88; + + private _tagsBtnHeight = 22; + @computed get currentScale() { + const viewXfScale = this._props.DocumentView!().screenToLocalScale(); + const x = NumCast(this.Document.height) / viewXfScale / 80; + const xscale = x >= 1 ? 0 : 1 / (1 + x * (viewXfScale - 1)); + const y = NumCast(this.Document.width) / viewXfScale / 200; + const yscale = y >= 1 ? 0 : 1 / (1 + y * viewXfScale - 1); + return Math.max(xscale, yscale, 1 / viewXfScale); + } + /** + * How much the content of the view is being scaled based on its nesting and its fit-to-width settings + */ + @computed get viewScaling() { return 1 / this.currentScale; } // prettier-ignore + /** + * The maximum size a UI widget can be scaled so that it won't be bigger in screen pixels than its normal 35 pixel size. + */ + @computed get maxWidgetSize() { return Math.min(this._tagsBtnHeight * this.viewScaling, 0.25 * Math.min(NumCast(this.Document.width), NumCast(this.Document.height))); } // prettier-ignore + /** + * How much to reactively scale a UI element so that it is as big as it can be (up to its normal 35pixel size) without being too big for the Doc content + */ + @computed get uiBtnScaling() { return Math.max(this.maxWidgetSize / this._tagsBtnHeight, 1) * Math.min(1, this.viewScaling); } // prettier-ignore + + aiContentsWidth = () => (this.aiContentsHeight() * (this._props.NativeWidth?.() || 1)) / (this._props.NativeHeight?.() || 1); + aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - this._aiWinHeight * this.uiBtnScaling); @computed get viewBoxContents() { TraceMobx(); const isInk = this.layoutDoc._layout_isSvg && !this._props.LayoutTemplateString; const noBackground = this.Document.isGroup && !this._componentView?.isUnstyledView?.() && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); return ( - <div - className="documentView-contentsView" - style={{ - pointerEvents: (isInk || noBackground ? 'none' : this.contentPointerEvents()) ?? (this._mounted ? 'all' : 'none'), - height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined, - }}> - <DocumentContentsView - {...this._props} - layoutFieldKey={StrCast(this.Document.layout_fieldKey, 'layout')} - pointerEvents={this.contentPointerEvents} - setContentViewBox={this.setContentView} - childFilters={this.childFilters} - PanelHeight={this.panelHeight} - setHeight={this.setHeight} - isContentActive={this.isContentActive} - ScreenToLocalTransform={this.screenToLocalContent} - rootSelected={this.rootSelected} - onClickScript={this.onClickFunc} - setTitleFocus={this.setTitleFocus} - hideClickBehaviors={BoolCast(this.Document.hideClickBehaviors)} - /> - </div> + <> + <div + className="documentView-contentsView" + style={{ + pointerEvents: (isInk || noBackground ? 'none' : this.contentPointerEvents()) ?? (this._mounted ? 'all' : 'none'), + width: this._props.showAIEditor ? this.aiContentsWidth() : undefined, + height: this._props.showAIEditor ? this.aiContentsHeight() : this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined, + }}> + <DocumentContentsView + {...this._props} + layoutFieldKey={StrCast(this.Document.layout_fieldKey, 'layout')} + pointerEvents={this.contentPointerEvents} + setContentViewBox={this.setContentView} + childFilters={this.childFilters} + PanelWidth={this._props.showAIEditor ? this.aiContentsWidth : this._props.PanelWidth} + PanelHeight={this._props.showAIEditor ? this.aiContentsHeight : this.panelHeight} + setHeight={this.setHeight} + isContentActive={this.isContentActive} + ScreenToLocalTransform={this.screenToLocalContent} + rootSelected={this.rootSelected} + onClickScript={this.onClickFunc} + setTitleFocus={this.setTitleFocus} + hideClickBehaviors={BoolCast(this.Document.hideClickBehaviors)} + /> + </div> + {!this._props.showAIEditor ? ( + <div + className="documentView-noAiWidgets" + style={{ + width: `${100 / this.uiBtnScaling}%`, // + transform: `scale(${this.uiBtnScaling})`, + bottom: Number.isNaN(this.maxWidgetSize) ? undefined : this.maxWidgetSize, + }}> + {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? <TagsView Views={[this._props.DocumentView?.()]} /> : null} + </div> + ) : ( + <> + <div + className="documentView-editorView-history" + ref={r => this.historyRef(this._oldAiWheel, (this._oldAiWheel = r))} + style={{ + transform: `scale(${this.uiBtnScaling})`, + height: this.aiContentsHeight() / this.uiBtnScaling, + width: ((this._props.PanelWidth() - this.aiContentsWidth()) * 0.95) / this.uiBtnScaling, + }}> + {this._componentView?.componentAIViewHistory?.() ?? null} + </div> + <div + className="documentView-editorView" + style={{ + background: SnappingManager.userVariantColor, + width: `${100 / this.uiBtnScaling}%`, // + transform: `scale(${this.uiBtnScaling})`, + }} + ref={r => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}> + <div className="documentView-editorView-resizer" /> + {this._componentView?.componentAIView?.() ?? null} + {this._props.DocumentView?.() ? <TagsView Views={[this._props.DocumentView?.()]} /> : null} + </div> + </> + )} + {this.widgetDecorations ?? null} + </> ); } + _oldHistoryWheel: HTMLDivElement | null = null; + _oldAiWheel: HTMLDivElement | null = null; + onPassiveWheel = (e: WheelEvent) => { + e.stopPropagation(); + }; + + protected historyRef = (lastEle: HTMLDivElement | null, ele: HTMLDivElement | null) => { + lastEle?.removeEventListener('wheel', this.onPassiveWheel); + ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false }); + }; captionStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string) => this._props?.styleProvider?.(doc, props, property + ':caption'); fieldsDropdown = (placeholder: string) => ( @@ -895,7 +978,6 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document {this.captionView} </div> )} - {this.widgetDecorations ?? null} </div> )); }; @@ -910,15 +992,11 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document highlightStroke: undefined, }; const { clipPath, jsx } = (borderPath as { clipPath: string; jsx: JSX.Element }) ?? { clipPath: undefined, jsx: undefined }; - const boxShadow = !highlighting - ? this.boxShadow - : 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 boxShadow = this.boxShadow; const renderDoc = this.renderDoc({ borderRadius: this.borderRounding, - outline: highlighting && !this.borderRounding && !highlightStroke ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px', - border: highlighting && this.borderRounding && highlightStyle === 'dashed' ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined, + outline: highlighting && !highlightStroke ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : 'solid 0px', + border: this._componentView?.isUnstyledView?.() ? undefined : this.border, boxShadow, clipPath, }); @@ -934,7 +1012,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document onPointerOver={() => (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} style={{ - borderRadius: this.borderRounding, + borderRadius: this._componentView?.isUnstyledView?.() ? undefined : 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 ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} @@ -964,13 +1042,13 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document >, root: Doc ) { - const dir = ((presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) || PresEffectDirection.Center) as PresEffectDirection; + const effectDirection = (presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) as PresEffectDirection; const duration = Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)); const effectProps = { - left: dir === PresEffectDirection.Left, - right: dir === PresEffectDirection.Right, - top: dir === PresEffectDirection.Top, - bottom: dir === PresEffectDirection.Bottom, + left: effectDirection === PresEffectDirection.Left, + right: effectDirection === PresEffectDirection.Right, + top: effectDirection === PresEffectDirection.Top, + bottom: effectDirection === PresEffectDirection.Bottom, opposite: true, delay: 0, duration, @@ -984,7 +1062,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document const presEffect = StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect)); switch (presEffect) { case PresEffect.Expand: case PresEffect.Flip: case PresEffect.Rotate: case PresEffect.Bounce: - case PresEffect.Roll: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={presEffect} springSettings={timingConfig}>{renderDoc}</SpringAnimation> + case PresEffect.Roll: return <SpringAnimation doc={root} startOpacity={0} dir={effectDirection || PresEffectDirection.Left} presEffect={presEffect} springSettings={timingConfig}>{renderDoc}</SpringAnimation> // case PresEffect.Fade: return <SlideEffect doc={root} dir={dir} presEffect={PresEffect.Fade} tension={timingConfig.stiffness} friction={timingConfig.damping} mass={timingConfig.mass}>{renderDoc}</SlideEffect> case PresEffect.Fade: return <Fade {...effectProps}>{renderDoc}</Fade> // keep as preset, doesn't really make sense with spring config @@ -1032,6 +1110,12 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { public static DeselectAll: (except?: Doc) => void | undefined; public static DeselectView: (dv: DocumentView | undefined) => void | undefined; public static SelectView: (dv: DocumentView | undefined, extendSelection: boolean) => void | undefined; + + public static SelectOnLoad: Doc | undefined; + public static SetSelectOnLoad(doc?: Doc) { + DocumentView.SelectOnLoad = doc; + doc && DocumentView.addViewRenderedCb(doc, dv => dv.select(false)); + } /** * returns a list of all currently selected DocumentViews */ @@ -1071,15 +1155,11 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { * @param doc Doc to snapshot * @returns promise of icon ImageField */ - public static GetDocImage(doc: Doc) { + public static GetDocImage(doc?: Doc) { return DocumentView.getDocumentView(doc) ?.ComponentView?.updateIcon?.() - .then(() => ImageCast(DocCast(doc).icon)); + .then(() => ImageCast(doc!.icon, ImageCast(doc![Doc.LayoutFieldKey(doc!)]))); } - /** - * The DocumentView below the cursor at the start of a gesture (that receives the pointerDown event). Used by GestureOverlay to determine the doc a gesture should apply to. - */ - public static DownDocView: DocumentView | undefined; // the first DocView that receives a pointerdown event. used by GestureOverlay to determine the doc a gesture should apply to. public get displayName() { return 'DocumentView(' + (this.Document?.title??"") + ')'; } // prettier-ignore private _htmlOverlayEffect: Opt<Doc>; @@ -1131,10 +1211,13 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { @computed private get nativeScaling() { if (this.shouldNotScale) return 1; const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0; - if (this.layout_fitWidth || this._props.PanelHeight() / (this.effectiveNativeHeight || 1) > this._props.PanelWidth() / (this.effectiveNativeWidth || 1)) { - return Math.max(minTextScale, this._props.PanelWidth() / (this.effectiveNativeWidth || 1)); // width-limited or layout_fitWidth + const ai = this._showAIEditor && this.nativeWidth === this.layoutDoc.width ? 95 : 0; + const effNW = Math.max(this.effectiveNativeWidth - ai, 1); + const effNH = Math.max(this.effectiveNativeHeight - ai, 1); + if (this.layout_fitWidth || (this._props.PanelHeight() - ai) / effNH > (this._props.PanelWidth() - ai) / effNW) { + return Math.max(minTextScale, (this._props.PanelWidth() - ai) / effNW); // width-limited or layout_fitWidth } - return Math.max(minTextScale, this._props.PanelHeight() / (this.effectiveNativeHeight || 1)); // height-limited or unscaled + return Math.max(minTextScale, (this._props.PanelHeight() - ai) / effNH); // height-limited or unscaled } @computed private get panelWidth() { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this._props.PanelWidth(); @@ -1290,6 +1373,13 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { } }; + @observable public _showAIEditor: boolean = false; + + @action + public toggleAIEditor = () => { + this._showAIEditor = !this._showAIEditor; + }; + public setTextHtmlOverlay = action((text: string | undefined, effect?: Doc) => { this._htmlOverlayText = text; this._htmlOverlayEffect = effect; @@ -1305,8 +1395,8 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { this.Document[Animation] = presEffect; this._animEffectTimer = setTimeout(() => { this.Document[Animation] = undefined; }, timeInMs); // prettier-ignore }; - public setViewTransition = (transProp: string, timeInMs: number, afterTrans?: () => void, dataTrans = false) => { - this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, afterTrans, dataTrans); + public setViewTransition = (transProp: string, timeInMs: number, dataTrans = false) => { + this._viewTimer = DocumentView.SetViewTransition([this.layoutDoc], transProp, timeInMs, this._viewTimer, dataTrans); }; public setCustomView = undoable((custom: boolean, layout: string): void => { @@ -1385,7 +1475,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { public docViewPath = () => (this.containerViewPath ? [...this.containerViewPath(), this] : [this]); layout_fitWidthFunc = (/* doc: Doc */) => BoolCast(this.layout_fitWidth); - screenToLocalScale = () => this._props.ScreenToLocalTransform().Scale; + screenToLocalScale = () => this.screenToViewTransform().Scale; isSelected = () => this.IsSelected; select = (extendSelection: boolean, focusSelection?: boolean) => { if (!this._props.dontSelect?.()) DocumentView.SelectView(this, extendSelection); @@ -1402,8 +1492,10 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { ShouldNotScale = () => this.shouldNotScale; NativeWidth = () => this.effectiveNativeWidth; NativeHeight = () => this.effectiveNativeHeight; - PanelWidth = () => this.panelWidth; + PanelWidth = () => this.panelWidth - 2 * NumCast(this.Document.borderWidth); PanelHeight = () => this.panelHeight; + ReducedPanelWidth = () => this.panelWidth / 2; + ReducedPanelHeight = () => this.panelWidth / 2; NativeDimScaling = () => this.nativeScaling; hideLinkCount = () => !!this.hideLinkButton; isHovering = () => this._isHovering; @@ -1472,6 +1564,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { }}> <DocumentViewInternal {...this._props} + showAIEditor={this._showAIEditor} reactParent={undefined} isHovering={this.isHovering} fieldKey={this.LayoutFieldKey} @@ -1502,21 +1595,15 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { ); } - public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, afterTrans?: () => void, dataTrans = false) { - docs.forEach(doc => { - doc._viewTransition = `${transProp} ${timeInMs}ms`; - dataTrans && (doc.dataTransition = `${transProp} ${timeInMs}ms`); - }); + public static SetViewTransition(docs: Doc[], transProp: string, timeInMs: number, timer?: NodeJS.Timeout | undefined, dataTrans = false) { + const setTrans = (transition?: string) => + docs.forEach(doc => { + doc._viewTransition = transition; + dataTrans && (doc.dataTransition = transition); + }); + setTrans(`${transProp} ${timeInMs}ms`); timer && clearTimeout(timer); - return setTimeout( - () => - docs.forEach(doc => { - doc._viewTransition = undefined; - dataTrans && (doc.dataTransition = 'inherit'); - afterTrans?.(); - }), - timeInMs + 10 - ); + return setTimeout(setTrans, timeInMs + 10); } // shows a stacking view collection (by default, but the user can change) of all documents linked to the source @@ -1560,55 +1647,45 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { } else func(); } } - -export function ActiveFillColor(): string { - const dv = DocumentView.Selected().lastElement() ?.Document._layout_isSvg ? DocumentView.Selected().lastElement() : undefined; - return StrCast(dv?.Document.fillColor, StrCast(ActiveInkPen()?.activeFillColor, "")); -} // prettier-ignore -export function ActiveInkPen(): Doc { return Doc.UserDoc(); } // prettier-ignore -export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, 'black'); } // prettier-ignore -export function ActiveIsInkMask(): boolean { return BoolCast(ActiveInkPen()?.activeIsInkMask, false); } // prettier-ignore -export function ActiveInkHideTextLabels(): boolean { return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); } // prettier-ignore -export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ''); } // prettier-ignore -export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ''); } // prettier-ignore -export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } // prettier-ignore -export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, '0'); } // prettier-ignore -export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } // prettier-ignore -export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } // prettier-ignore -export function ActiveEraserWidth(): number { return Number(ActiveInkPen()?.eraserWidth ?? 25); } // prettier-ignore - +export function ActiveHideTextLabels(): boolean { return BoolCast(Doc.UserDoc().activeHideTextLabels, false); } // prettier-ignore +export function ActiveIsInkMask(): boolean { return BoolCast(Doc.UserDoc()?.activeIsInkMask, false); } // prettier-ignore +export function ActiveEraserWidth(): number { return Number(Doc.UserDoc()?.activeEraserWidth ?? 25); } // prettier-ignore + +export function ActiveInkFillColor(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}Fill`]); } // prettier-ignore +export function ActiveInkColor(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}Color`], 'black'); } // prettier-ignore +export function ActiveInkArrowStart(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}ArrowStart`], ''); } // prettier-ignore +export function ActiveInkArrowEnd(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}ArrowEnd`], ''); } // prettier-ignore +export function ActiveInkArrowScale(): number { return NumCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}ArrowScale`], 1); } // prettier-ignore +export function ActiveInkDash(): string { return StrCast(Doc.UserDoc()?.[`active${Doc.ActiveInk}Dash`], '0'); } // prettier-ignore +export function ActiveInkWidth(): number { return Number(Doc.UserDoc()?.[`active${Doc.ActiveInk}Width`]); } // prettier-ignore +export function ActiveInkBezierApprox(): string { return StrCast(Doc.UserDoc()[`active${Doc.ActiveInk}Bezier`]); } // prettier-ignore + +export function SetActiveIsInkMask(value: boolean) { Doc.UserDoc() && (Doc.UserDoc().activeIsInkMask = value); } // prettier-ignore +export function SetactiveHideTextLabels(value: boolean) { Doc.UserDoc() && (Doc.UserDoc().activeHideTextLabels = value); } // prettier-ignore +export function SetEraserWidth(width: number): void { Doc.UserDoc() && (Doc.UserDoc().activeEraserWidth = width); } // prettier-ignore export function SetActiveInkWidth(width: string): void { - !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width); + !isNaN(parseInt(width)) && Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Width`] = width); } -export function SetActiveBezierApprox(bezier: string): void { - ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier); +export function SetActiveInkBezierApprox(bezier: string): void { + Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Bezier`] = isNaN(parseInt(bezier)) ? '' : bezier); } export function SetActiveInkColor(value: string) { - ActiveInkPen() && (ActiveInkPen().activeInkColor = value); -} -export function SetActiveIsInkMask(value: boolean) { - ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value); -} -export function SetActiveInkHideTextLabels(value: boolean) { - ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value); -} -export function SetActiveFillColor(value: string) { - ActiveInkPen() && (ActiveInkPen().activeFillColor = value); + Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Color`] = value); } -export function SetActiveArrowStart(value: string) { - ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); +export function SetActiveInkFillColor(value: string) { + Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}Fill`] = value); } -export function SetActiveArrowEnd(value: string) { - ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); +export function SetActiveInkArrowStart(value: string) { + Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}ArrowStart`] = value); } -export function SetActiveArrowScale(value: number) { - ActiveInkPen() && (ActiveInkPen().activeArrowScale = value); +export function SetActiveInkArrowEnd(value: string) { + Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}ArrowEnd`] = value); } -export function SetActiveDash(dash: string): void { - !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); +export function SetActiveInkArrowScale(value: number) { + Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}ArrowScale`] = value); } -export function SetEraserWidth(width: number): void { - ActiveInkPen() && (ActiveInkPen().eraserWidth = width); +export function SetActiveInkDash(dash: string): void { + !isNaN(parseInt(dash)) && Doc.UserDoc() && (Doc.UserDoc()[`active${Doc.ActiveInk}`] = dash); } // eslint-disable-next-line prefer-arrow-callback |