diff options
Diffstat (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')
-rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 109 |
1 files changed, 65 insertions, 44 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 624f28413..8e7a6914f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,4 +1,4 @@ -import { action, computed, observable } from 'mobx'; +import { action, computed, observable, makeObservable, reaction, runInAction, override } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, DocListCast, Opt } from '../../../fields/Doc'; import { List } from '../../../fields/List'; @@ -6,7 +6,7 @@ import { listSpec } from '../../../fields/Schema'; import { ComputedField } from '../../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { numberRange, OmitKeys } from '../../../Utils'; +import { copyProps, numberRange, OmitKeys } from '../../../Utils'; import { DocumentManager } from '../../util/DocumentManager'; import { SelectionManager } from '../../util/SelectionManager'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; @@ -37,6 +37,13 @@ export interface CollectionFreeFormDocumentViewWrapperProps extends DocumentView } @observer export class CollectionFreeFormDocumentViewWrapper extends DocComponent<CollectionFreeFormDocumentViewWrapperProps & { fieldKey: string }>() implements CollectionFreeFormDocumentViewProps { + _prevProps: React.PropsWithChildren<CollectionFreeFormDocumentViewWrapperProps & { fieldKey: string }>; + @override _props: React.PropsWithChildren<CollectionFreeFormDocumentViewWrapperProps & { fieldKey: string }>; + constructor(props: React.PropsWithChildren<CollectionFreeFormDocumentViewWrapperProps & { fieldKey: string }>) { + super(props); + this._props = this._prevProps = props; + makeObservable(this); + } @observable X = this.props.x; @observable Y = this.props.y; @observable Z = this.props.z; @@ -64,11 +71,11 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti w_X = () => this.X; // prettier-ignore w_Y = () => this.Y; // prettier-ignore w_Z = () => this.Z; // prettier-ignore - w_ZIndex = () => this.ZIndex ?? NumCast(this.props.Document.zIndex); // prettier-ignore - w_Rotation = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore + w_ZIndex = () => this.ZIndex ?? NumCast(this.Document.zIndex); // prettier-ignore + w_Rotation = () => this.Rotation ?? NumCast(this.Document._rotation); // prettier-ignore w_Opacity = () => this.Opacity; // prettier-ignore - w_BackgroundColor = () => this.BackgroundColor ?? Cast(this.props.Document._backgroundColor, 'string', null); // prettier-ignore - w_Color = () => this.Color ?? Cast(this.props.Document._color, 'string', null); // prettier-ignore + w_BackgroundColor = () => this.BackgroundColor ?? Cast(this.Document._backgroundColor, 'string', null); // prettier-ignore + w_Color = () => this.Color ?? Cast(this.Document._color, 'string', null); // prettier-ignore w_Highlight = () => this.Highlight; // prettier-ignore w_Width = () => this.Width; // prettier-ignore w_Height = () => this.Height; // prettier-ignore @@ -76,17 +83,18 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti w_Transition = () => this.Transition; // prettier-ignore w_DataTransition = () => this.DataTransition; // prettier-ignore - PanelWidth = () => this.props.autoDim ? this.props.PanelWidth?.() : this.Width; // prettier-ignore - PanelHeight = () => this.props.autoDim ? this.props.PanelHeight?.() : this.Height; // prettier-ignore - @action + PanelWidth = () => this._props.autoDim ? this._props.PanelWidth?.() : this.Width; // prettier-ignore + PanelHeight = () => this._props.autoDim ? this._props.PanelHeight?.() : this.Height; // prettier-ignore + componentDidUpdate() { - this.WrapperKeys.forEach(keys => ((this as any)[keys.upper] = (this.props as any)[keys.lower])); + copyProps(this); + this.WrapperKeys.forEach(action(keys => ((this as any)[keys.upper] = (this.props as any)[keys.lower]))); } render() { const layoutProps = this.WrapperKeys.reduce((val, keys) => [(val['w_' + keys.upper] = (this as any)['w_' + keys.upper]), val][1], {} as { [key: string]: Function }); return ( <CollectionFreeFormDocumentView - {...OmitKeys(this.props, this.WrapperKeys.map(keys => keys.lower) ).omit} // prettier-ignore + {...OmitKeys(this._props, this.WrapperKeys.map(keys => keys.lower) ).omit} // prettier-ignore {...layoutProps} PanelWidth={this.PanelWidth} PanelHeight={this.PanelHeight} @@ -115,7 +123,7 @@ export interface CollectionFreeFormDocumentViewProps { } @observer -export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps & DocumentViewProps & { fieldKey: string }>() { +export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps & DocumentViewProps>() { get displayName() { // this makes mobx trace() statements more descriptive return 'CollectionFreeFormDocumentView(' + this.Document.title + ')'; } // prettier-ignore @@ -135,33 +143,46 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF public static animStringFields = ['backgroundColor', 'color', 'fillColor']; // fields that are configured to be animatable using animation frames public static animDataFields = (doc: Doc) => (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames + _props: React.PropsWithChildren<CollectionFreeFormDocumentViewProps & DocumentViewProps>; + constructor(props: React.PropsWithChildren<CollectionFreeFormDocumentViewProps & DocumentViewProps>) { + super(props); + this._props = Object.assign({}, props); + makeObservable(this); + } + get CollectionFreeFormView() { - return this.props.CollectionFreeFormView; + return this._props.CollectionFreeFormView; } styleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string) => { if (doc === this.layoutDoc) { switch (property) { - case StyleProp.Opacity: return this.props.w_Opacity(); // only change the opacity for this specific document, not its children - case StyleProp.BackgroundColor: return this.props.w_BackgroundColor(); - case StyleProp.Color: return this.props.w_Color(); + case StyleProp.Opacity: return this._props.w_Opacity(); // only change the opacity for this specific document, not its children + case StyleProp.BackgroundColor: return this._props.w_BackgroundColor(); + case StyleProp.Color: return this._props.w_Color(); } // prettier-ignore } - return this.props.styleProvider?.(doc, props, property); + return this._props.styleProvider?.(doc, props, property); }; public static getValues(doc: Doc, time: number, fillIn: boolean = true) { - return CollectionFreeFormDocumentView.animFields.reduce((p, val) => { - p[val.key] = Cast(doc[`${val.key}_indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); - return p; - }, {} as { [val: string]: Opt<number> }); + return CollectionFreeFormDocumentView.animFields.reduce( + (p, val) => { + p[val.key] = Cast(doc[`${val.key}_indexed`], listSpec('number'), fillIn ? [NumCast(doc[val.key], val.val)] : []).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as number); + return p; + }, + {} as { [val: string]: Opt<number> } + ); } public static getStringValues(doc: Doc, time: number) { - return CollectionFreeFormDocumentView.animStringFields.reduce((p, val) => { - p[val] = Cast(doc[`${val}_indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string); - return p; - }, {} as { [val: string]: Opt<string> }); + return CollectionFreeFormDocumentView.animStringFields.reduce( + (p, val) => { + p[val] = Cast(doc[`${val}_indexed`], listSpec('string'), [StrCast(doc[val])]).reduce((p, v, i) => ((i <= Math.round(time) && v !== undefined) || p === undefined ? v : p), undefined as any as string); + return p; + }, + {} as { [val: string]: Opt<string> } + ); } public static setStringValues(time: number, d: Doc, vals: { [val: string]: Opt<string> }) { @@ -213,7 +234,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF @action public float = () => { const topDoc = this.Document; - const containerDocView = this.props.docViewPath().lastElement(); + const containerDocView = this._props.docViewPath().lastElement(); const screenXf = containerDocView?.screenToLocalTransform(); if (screenXf) { SelectionManager.DeselectAll(); @@ -222,8 +243,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF topDoc.z = 0; topDoc.x = spt[0]; topDoc.y = spt[1]; - this.props.removeDocument?.(topDoc); - this.props.addDocTab(topDoc, OpenWhere.inParentFromScreen); + this._props.removeDocument?.(topDoc); + this._props.addDocTab(topDoc, OpenWhere.inParentFromScreen); } else { const spt = this.screenToLocalTransform().inverse().transformPoint(0, 0); const fpt = screenXf.transformPoint(spt[0], spt[1]); @@ -236,15 +257,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF }; nudge = (x: number, y: number) => { - const [locX, locY] = this.props.ScreenToLocalTransform().transformDirection(x, y); - this.props.Document.x = this.props.w_X() + locX; - this.props.Document.y = this.props.w_Y() + locY; + const [locX, locY] = this._props.ScreenToLocalTransform().transformDirection(x, y); + this._props.Document.x = this._props.w_X() + locX; + this._props.Document.y = this._props.w_Y() + locY; }; screenToLocalTransform = () => - this.props + this._props .ScreenToLocalTransform() - .translate(-this.props.w_X(), -this.props.w_Y()) - .rotateDeg(-(this.props.w_Rotation?.() || 0)); + .translate(-this._props.w_X(), -this._props.w_Y()) + .rotateDeg(-(this._props.w_Rotation?.() || 0)); returnThis = () => this; /// this indicates whether the doc view is activated because of its relationshop to a group @@ -255,25 +276,25 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF isGroupActive = () => { if (this.CollectionFreeFormView.isAnyChildContentActive()) return undefined; const isGroup = this.dataDoc.isGroup && (!this.layoutDoc.backgroundColor || this.layoutDoc.backgroundColor === 'transparent'); - return isGroup ? (this.props.isDocumentActive?.() ? 'group' : this.props.isGroupActive?.() ? 'child' : 'inactive') : this.props.isGroupActive?.() ? 'child' : undefined; + return isGroup ? (this._props.isDocumentActive?.() ? 'group' : this._props.isGroupActive?.() ? 'child' : 'inactive') : this._props.isGroupActive?.() ? 'child' : undefined; }; public static CollectionFreeFormDocViewClassName = 'collectionFreeFormDocumentView-container'; render() { TraceMobx(); - const passOnProps = OmitKeys(this.props, Object.keys(this.props).filter(key => key.startsWith('w_'))).omit; // prettier-ignore + const passOnProps = OmitKeys(this._props, Object.keys(this._props).filter(key => key.startsWith('w_'))).omit; // prettier-ignore return ( <div className={CollectionFreeFormDocumentView.CollectionFreeFormDocViewClassName} style={{ - width: this.props.PanelWidth(), - height: this.props.PanelHeight(), - transform: `translate(${this.props.w_X()}px, ${this.props.w_Y()}px) rotate(${NumCast(this.props.w_Rotation?.())}deg)`, - transition: this.props.w_Transition?.() ?? (this.props.w_DataTransition?.() || this.props.w_Transition?.()), - zIndex: this.props.w_ZIndex?.(), - display: this.props.w_Width?.() ? undefined : 'none', + width: this._props.PanelWidth(), + height: this._props.PanelHeight(), + transform: `translate(${this._props.w_X()}px, ${this._props.w_Y()}px) rotate(${NumCast(this._props.w_Rotation?.())}deg)`, + transition: this._props.w_Transition?.() ?? (this._props.w_DataTransition?.() || this._props.w_Transition?.()), + zIndex: this._props.w_ZIndex?.(), + display: this._props.w_Width?.() ? undefined : 'none', }}> - {this.props.RenderCutoffProvider(this.props.Document) ? ( - <div style={{ position: 'absolute', width: this.props.PanelWidth(), height: this.props.PanelHeight(), background: 'lightGreen' }} /> + {this._props.RenderCutoffProvider(this._props.Document) ? ( + <div style={{ position: 'absolute', width: this._props.PanelWidth(), height: this._props.PanelHeight(), background: 'lightGreen' }} /> ) : ( <DocumentView {...passOnProps} CollectionFreeFormDocumentView={this.returnThis} styleProvider={this.styleProvider} ScreenToLocalTransform={this.screenToLocalTransform} isGroupActive={this.isGroupActive} /> )} |