diff options
| author | Eric <ericmabr@gmail.com> | 2023-08-13 16:08:28 -0400 |
|---|---|---|
| committer | Eric <ericmabr@gmail.com> | 2023-08-13 16:08:28 -0400 |
| commit | 0020ec69b847c8607affb57babddfddc812dc9b6 (patch) | |
| tree | e24255039015745d2073806bee97ce449ddb5260 /src/client/views/DocumentDecorations.tsx | |
| parent | 7b2553514bb000eb7f618eb0f0d653baee78742c (diff) | |
| parent | 3b45f1d30a947dc1702ec347b83e98374c5b603c (diff) | |
Merge branch 'master' into UI_Update_Eric_Ma
Diffstat (limited to 'src/client/views/DocumentDecorations.tsx')
| -rw-r--r-- | src/client/views/DocumentDecorations.tsx | 208 |
1 files changed, 130 insertions, 78 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 39073d763..f3daf3ffa 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -2,23 +2,26 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@material-ui/core'; import { IconButton } from 'browndash-components'; -import { action, computed, observable, reaction, runInAction } from 'mobx'; +import { action, computed, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { FaUndo } from 'react-icons/fa'; import { DateField } from '../../fields/DateField'; -import { AclAdmin, AclEdit, DataSym, Doc, DocListCast, Field, HeightSym, WidthSym } from '../../fields/Doc'; -import { Document } from '../../fields/documentSchemas'; +import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc'; +import { AclAdmin, AclAugment, AclEdit, DocData, Height, Width } from '../../fields/DocSymbols'; import { InkField } from '../../fields/InkField'; +import { RichTextField } from '../../fields/RichTextField'; import { ScriptField } from '../../fields/ScriptField'; -import { Cast, NumCast, StrCast } from '../../fields/Types'; +import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; import { GetEffectiveAcl } from '../../fields/util'; import { aggregateBounds, emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; +import { DocumentManager } from '../util/DocumentManager'; import { DragManager } from '../util/DragManager'; +import { LinkFollower } from '../util/LinkFollower'; import { SelectionManager } from '../util/SelectionManager'; import { SnappingManager } from '../util/SnappingManager'; -import { undoBatch, UndoManager } from '../util/UndoManager'; +import { UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { CollectionFreeFormView } from './collections/collectionFreeForm'; import { DocumentButtonBar } from './DocumentButtonBar'; @@ -27,15 +30,11 @@ import { Colors } from './global/globalEnums'; import { InkingStroke } from './InkingStroke'; import { InkStrokeProperties } from './InkStrokeProperties'; import { LightboxView } from './LightboxView'; -import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; +import { DocumentView, OpenWhereMod } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import React = require('react'); -import { RichTextField } from '../../fields/RichTextField'; -import { LinkFollower } from '../util/LinkFollower'; import _ = require('lodash'); -import { DocumentManager } from '../util/DocumentManager'; -import { isUndefined } from 'lodash'; @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { @@ -65,6 +64,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P @observable private _isRotating: boolean = false; @observable private _isRounding: boolean = false; @observable private _isResizing: boolean = false; + @observable private showLayoutAcl: boolean = false; constructor(props: any) { super(props); @@ -150,7 +150,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P Doc.SetInPlace(d.rootDoc, titleFieldKey, titleField, true); } }), - 'title blur' + 'edit title' ); } }; @@ -163,35 +163,50 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P }; @action onContainerDown = (e: React.PointerEvent): void => { - setupMoveUpEvents( - this, - e, - e => this.onBackgroundMove(true, e), - e => {}, - emptyFunction - ); + const first = SelectionManager.Views()[0]; + const effectiveLayoutAcl = GetEffectiveAcl(first.rootDoc); + if (effectiveLayoutAcl == AclAdmin || effectiveLayoutAcl == AclEdit || effectiveLayoutAcl == AclAugment) { + setupMoveUpEvents( + this, + e, + e => this.onBackgroundMove(true, e), + e => {}, + emptyFunction + ); + } }; @action onTitleDown = (e: React.PointerEvent): void => { - setupMoveUpEvents( - this, - e, - e => this.onBackgroundMove(true, e), - e => {}, - action(e => { - !this._editingTitle && (this._accumulatedTitle = this._titleControlString.startsWith('#') ? this.selectionTitle : this._titleControlString); - this._editingTitle = true; - this._keyinput.current && setTimeout(this._keyinput.current.focus); - }) - ); + const first = SelectionManager.Views()[0]; + const effectiveLayoutAcl = GetEffectiveAcl(first.rootDoc); + if (effectiveLayoutAcl == AclAdmin || effectiveLayoutAcl == AclEdit || effectiveLayoutAcl == AclAugment) { + setupMoveUpEvents( + this, + e, + e => this.onBackgroundMove(true, e), + e => {}, + action(e => { + !this._editingTitle && (this._accumulatedTitle = this._titleControlString.startsWith('#') ? this.selectionTitle : this._titleControlString); + this._editingTitle = true; + this._keyinput.current && setTimeout(this._keyinput.current.focus); + }) + ); + } }; onBackgroundDown = (e: React.PointerEvent) => setupMoveUpEvents(this, e, e => this.onBackgroundMove(false, e), emptyFunction, emptyFunction); @action onBackgroundMove = (dragTitle: boolean, e: PointerEvent): boolean => { + const first = SelectionManager.Views()[0]; + const effectiveLayoutAcl = GetEffectiveAcl(first.rootDoc); + if (effectiveLayoutAcl != AclAdmin && effectiveLayoutAcl != AclEdit && effectiveLayoutAcl != AclAugment) { + return false; + } const dragDocView = SelectionManager.Views()[0]; - if (DocListCast(Doc.MyOverlayDocs.data).includes(dragDocView.rootDoc)) return false; + const containers = new Set<Doc | undefined>(); + SelectionManager.Views().forEach(v => containers.add(DocCast(v.rootDoc.embedContainer))); + if (containers.size > 1) return false; const { left, top } = dragDocView.getBounds() || { left: 0, top: 0 }; const dragData = new DragManager.DocumentDragData( SelectionManager.Views().map(dv => dv.props.Document), @@ -227,11 +242,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P .filter(v => v && v.props.renderDepth > 0); if (forceDeleteOrIconify === false && this._iconifyBatch) return; this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false; - if (!this._iconifyBatch) { - this._iconifyBatch = UndoManager.StartBatch('iconifying'); - } else { - forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes - } var iconifyingCount = views.length; const finished = action((force?: boolean) => { if ((force || --iconifyingCount === 0) && this._iconifyBatch) { @@ -250,6 +260,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P this._iconifyBatch = undefined; } }); + if (!this._iconifyBatch) { + this._iconifyBatch = UndoManager.StartBatch(forceDeleteOrIconify ? 'delete selected docs' : 'iconifying'); + } else { + forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes + } + if (forceDeleteOrIconify) finished(forceDeleteOrIconify); else if (!this._deleteAfterIconify) views.forEach(dv => dv.iconify(finished)); }; @@ -273,19 +289,19 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (selectedDocs.length) { if (e.ctrlKey) { // open an embedding in a new tab with Ctrl Key - CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].props.Document), OpenWhereMod.right); + CollectionDockingView.AddSplit(Doc.BestEmbedding(selectedDocs[0].rootDoc), OpenWhereMod.right); } else if (e.shiftKey) { // open centered in a new workspace with Shift Key - const embedding = Doc.MakeEmbedding(selectedDocs[0].props.Document); + const embedding = Doc.MakeEmbedding(selectedDocs[0].rootDoc); embedding.embedContainer = undefined; - embedding.x = -embedding[WidthSym]() / 2; - embedding.y = -embedding[HeightSym]() / 2; + embedding.x = -embedding[Width]() / 2; + embedding.y = -embedding[Height]() / 2; CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([embedding], { title: 'Tab for ' + embedding.title }), OpenWhereMod.right); } else if (e.altKey) { // open same document in new tab - CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, OpenWhereMod.right); + CollectionDockingView.ToggleSplit(selectedDocs[0].rootDoc, OpenWhereMod.right); } else { - var openDoc = selectedDocs[0].props.Document; + var openDoc = selectedDocs[0].rootDoc; if (openDoc.layout_fieldKey === 'layout_icon') { openDoc = DocListCast(openDoc.proto_embeddings).find(embedding => !embedding.embedContainer) ?? Doc.MakeEmbedding(openDoc); Doc.deiconifyView(openDoc); @@ -293,7 +309,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P LightboxView.SetLightboxDoc( openDoc, undefined, - selectedDocs.slice(1).map(view => view.props.Document) + selectedDocs.slice(1).map(view => view.rootDoc) ); } } @@ -330,7 +346,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const docMax = Math.min(NumCast(doc.width) / 2, NumCast(doc.height) / 2); const ratio = dist / maxDist; const radius = Math.min(1, ratio) * docMax; - doc.borderRounding = `${radius}px`; + doc.layout_borderRounding = `${radius}px`; }); return false; }, // moveEvent @@ -397,7 +413,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P onRotateDown = (e: React.PointerEvent): void => { this._isRotating = true; const rcScreen = { X: this.rotCenter[0], Y: this.rotCenter[1] }; - const rotateUndo = UndoManager.StartBatch('rotatedown'); + const rotateUndo = UndoManager.StartBatch('drag rotation'); const selectedInk = SelectionManager.Views().filter(i => i.ComponentView instanceof InkingStroke); const centerPoint = this.rotCenter.slice(); const infos = new Map<Doc, { unrotatedDocPos: { x: number; y: number }; startRotCtr: { x: number; y: number }; accumRot: number }>(); @@ -465,7 +481,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const bounds = e.currentTarget.getBoundingClientRect(); this._offX = this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX; this._offY = this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY; - this._resizeUndo = UndoManager.StartBatch('DocDecs resize'); + this._resizeUndo = UndoManager.StartBatch('drag resizing'); this._snapX = e.pageX; this._snapY = e.pageY; const ffviewSet = new Set<CollectionFreeFormView>(); @@ -479,6 +495,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => { const first = SelectionManager.Views()[0]; + const effectiveAcl = GetEffectiveAcl(first.rootDoc); + if (!(effectiveAcl == AclAdmin || effectiveAcl == AclEdit || effectiveAcl == AclAugment)) return false; if (!first) return false; let thisPt = { x: e.clientX - this._offX, y: e.clientY - this._offY }; var fixedAspect = Doc.NativeAspect(first.layoutDoc); @@ -586,7 +604,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P let dW = docwidth * (dWin / refWidth); let dH = docheight * (dHin / refHeight); const scale = docView.props.ScreenToLocalTransform().Scale; - const modifyNativeDim = (e.ctrlKey || doc.layout_forceReflow) && doc.nativeDimModifiable && ((!dragBottom && !dragTop) || e.ctrlKey || doc.nativeHeightUnfrozen); + const modifyNativeDim = (e.ctrlKey && doc.nativeDimModifiable) || (doc.layout_forceReflow && !dragBottom && !dragTop) || (doc.nativeHeightUnfrozen && (dragBottom || dragTop || e.ctrlKey)); if (nwidth && nheight) { if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) { docheight = (nheight / nwidth) * docwidth; @@ -599,9 +617,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } let actualdW = Math.max(docwidth + dW * scale, 20); let actualdH = Math.max(docheight + dH * scale, 20); - let dX = !dWin ? 0 : scale * refCent[0] * (1 - (1 + dWin / refWidth)); - let dY = !dHin ? 0 : scale * refCent[1] * (1 - (1 + dHin / refHeight)); - const preserveNativeDim = doc._nativeHeightUnfrozen === false && doc._nativeDimModifiable === false; + let dX = !dWin ? 0 : (scale * refCent[0] * -dWin) / refWidth; + let dY = !dHin ? 0 : (scale * refCent[1] * -dHin) / refHeight; + const preserveNativeDim = !doc._nativeHeightUnfrozen && !doc._nativeDimModifiable; const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable); if (fixedAspect) { if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) { @@ -612,6 +630,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } else { if (!doc._layout_fitWidth || preserveNativeDim) { actualdH = (nheight / nwidth) * actualdW; + dYin && (dY = -dW * scale * (nheight / nwidth)); doc._height = actualdH; } else if (!modifyNativeDim || dragBotRight) { doc._height = actualdH; @@ -628,13 +647,14 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P } else { if (!doc._layout_fitWidth || preserveNativeDim) { actualdW = (nwidth / nheight) * actualdH; + dXin && (dX = -dH * scale * (nwidth / nheight)); doc._width = actualdW; } else if (!modifyNativeDim || dragBotRight) { doc._width = actualdW; } } if (!modifyNativeDim) { - actualdH = Math.min((nheight / nwidth) * docwidth, actualdH); + actualdH = (nheight / nwidth) * NumCast(doc._width); //, actualdH); } doc._height = actualdH; } @@ -744,17 +764,25 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P setTimeout(action(() => (this._showNothing = true))); return null; } + + // sharing + const acl = GetEffectiveAcl(!this.showLayoutAcl ? Doc.GetProto(seldocview.rootDoc) : seldocview.rootDoc); + const docShareMode = HierarchyMapping.get(acl)!.name; + const shareMode = StrCast(docShareMode); + var shareSymbolIcon = ReverseHierarchyMap.get(shareMode)?.image; + // hide the decorations if the parent chooses to hide it or if the document itself hides it const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations; - const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating; + const hideResizers = + ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating; const hideTitle = hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating; - const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.hideDocumentButtonBar || this._isRounding || this._isRotating; + const hideDocumentButtonBar = hideDecorations || seldocview.props.hideDocumentButtonBar || seldocview.rootDoc.layout_hideDocumentButtonBar || this._isRounding || this._isRotating; // if multiple documents have been opened at the same time, then don't show open button const hideOpenButton = hideDecorations || seldocview.props.hideOpenButton || - seldocview.rootDoc.hideOpenButton || - SelectionManager.Views().some(docView => docView.props.Document._stayInCollection || docView.props.Document.isGroup || docView.props.Document.hideOpenButton) || + seldocview.rootDoc.layout_hideOpenButton || + SelectionManager.Views().some(docView => docView.rootDoc._dragOnlyWithinContainer || docView.rootDoc.isGroup || docView.rootDoc.layout_hideOpenButton) || this._isRounding || this._isRotating; const hideDeleteButton = @@ -764,26 +792,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P seldocview.props.hideDeleteButton || seldocview.rootDoc.hideDeleteButton || SelectionManager.Views().some(docView => { - const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit; - return (docView.rootDoc.stayInCollection && !docView.rootDoc.timelineLabel) || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin); + const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DocData]) : AclEdit; + return collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin; }); - const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => ( <Tooltip key={key} title={<div className="dash-tooltip">{title}</div>} placement="top"> - <div - className={`documentDecorations-${key}Button`} - onContextMenu={e => e.preventDefault()} - onPointerDown={ - pointerDown ?? - (e => - setupMoveUpEvents( - this, - e, - returnFalse, - emptyFunction, - undoBatch(e => click!(e)) - )) - }> + <div className={`documentDecorations-${key}Button`} onContextMenu={e => e.preventDefault()} onPointerDown={pointerDown ?? (e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => click!(e)))}> <FontAwesomeIcon icon={icon as any} /> </div> </Tooltip> @@ -807,12 +821,33 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P // Radius constants const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView; - const borderRadius = numberValue(StrCast(seldocview.rootDoc.borderRounding)); + const borderRadius = numberValue(StrCast(seldocview.rootDoc.layout_borderRounding)); const docMax = Math.min(NumCast(seldocview.rootDoc.width) / 2, NumCast(seldocview.rootDoc.height) / 2); const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2); const radiusHandle = (borderRadius / docMax) * maxDist; const radiusHandleLocation = Math.min(radiusHandle, maxDist); + const sharingMenu = docShareMode ? ( + <div className="documentDecorations-share"> + <div className={`documentDecorations-share${shareMode}`}> + + {shareSymbolIcon + ' ' + shareMode} + + {/* {!Doc.noviceMode ? ( + <div className="checkbox"> + <div className="checkbox-box"> + <input type="checkbox" checked={this.showLayoutAcl} onChange={action(() => (this.showLayoutAcl = !this.showLayoutAcl))} /> + </div> + <div className="checkbox-text"> Layout </div> + </div> + ) : null} + */} + </div> + </div> + ) : ( + <div /> + ); + const titleArea = this._editingTitle ? ( <input ref={this._keyinput} @@ -827,8 +862,18 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P onPointerDown={e => e.stopPropagation()} /> ) : ( - <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown}> - <span className={`documentDecorations-titleSpan${colorScheme}`}>{`${hideTitle ? '' : this.selectionTitle}`}</span> + <div + className="documentDecorations-title" + key="title" + onPointerDown={e => { + e.stopPropagation; + }}> + {hideTitle ? null : ( + <span className={`documentDecorations-titleSpan${colorScheme}`} onPointerDown={this.onTitleDown}> + {this.selectionTitle} + </span> + )} + {sharingMenu} {!useLock ? null : ( <Tooltip key="lock" title={<div className="dash-tooltip">toggle ability to interact with document</div>} placement="top"> <div className="documentDecorations-lock" style={{ color: seldocview.rootDoc._lockedPosition ? 'red' : undefined }} onPointerDown={this.onLockDown} onContextMenu={e => e.preventDefault()}> @@ -838,6 +883,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P )} </div> ); + return ( <div className={`documentDecorations${colorScheme}`} style={{ opacity: this._showNothing ? 0.1 : undefined }}> <div @@ -867,11 +913,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P width: bounds.r - bounds.x + this._resizeBorderWidth + 'px', height: bounds.b - bounds.y + this._resizeBorderWidth + this._titleHeight + 'px', }}> - <div className="documentDecorations-topbar" style={{ display: hideDeleteButton && hideTitle && hideOpenButton ? 'none' : undefined }} onPointerDown={this.onContainerDown}> + <div + className="documentDecorations-topbar" + style={{ + color: 'black', + display: hideDeleteButton && hideTitle && hideOpenButton ? 'none' : undefined, + }} + onPointerDown={this.onContainerDown}> {hideDeleteButton ? null : topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} {hideResizers || hideDeleteButton ? null : topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} - {hideTitle ? null : titleArea} - {hideOpenButton ? null : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as new embedding, shift: in new collection)')} + {titleArea} + {hideOpenButton ? <div /> : topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')} </div> {hideResizers ? null : ( <> @@ -927,7 +979,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P }}> {this._isRotating ? null : ( <Tooltip enterDelay={750} title={<div className="dash-tooltip">tap to set rotate center, drag to rotate</div>}> - <div className="documentDecorations-rotation" style={{ pointerEvents: 'all' }} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}> + <div className="documentDecorations-rotation" style={{ pointerEvents: 'all', color: 'blue' }} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}> <IconButton icon={<FaUndo />} color={Colors.LIGHT_GRAY} /> </div> </Tooltip> |
