diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 26 | ||||
| -rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 8 | ||||
| -rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 13 | ||||
| -rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 6 | ||||
| -rw-r--r-- | src/client/views/nodes/WebBox.tsx | 10 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 12 | ||||
| -rw-r--r-- | src/client/views/nodes/trails/PresBox.tsx | 24 |
7 files changed, 55 insertions, 44 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 48e32c071..fb20887cb 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -53,6 +53,7 @@ import { RadialMenu } from './RadialMenu'; import { ScriptingBox } from './ScriptingBox'; import { PinProps, PresBox } from './trails/PresBox'; import React = require('react'); +import { PresEffect, PresEffectDirection } from './trails'; const { Howl } = require('howler'); interface Window { @@ -95,10 +96,17 @@ export const ViewSpecPrefix = 'viewSpec'; // field prefix for anchor fields that export interface DocFocusOptions { originalTarget?: Doc; // set in JumpToDocument, used by TabDocView to determine whether to fit contents to tab willZoom?: boolean; // determines whether to zoom in on target document - scale?: number; // percent of containing frame to zoom into document + zoomScale?: number; // percent of containing frame to zoom into document + zoomTime?: number; afterFocus?: DocAfterFocusFunc; // function to call after focusing on a document docTransform?: Transform; // when a document can't be panned and zoomed within its own container (say a group), then we need to continue to move up the render hierarchy to find something that can pan and zoom. when this happens the docTransform must accumulate all the transforms of each level of the hierarchy instant?: boolean; // whether focus should happen instantly (as opposed to smooth zoom) + effect?: PresEffect; // animation effect for focus + effectDirection?: PresEffectDirection; + noSelect?: boolean; // whether target should be selected after focusing + playAudio?: boolean; // whether to play audio annotation on focus + toggleTarget?: boolean; // whether to toggle target on and off + originatingDoc?: Doc; // document that triggered the focus } export type DocAfterFocusFunc = (notFocused: boolean) => Promise<ViewAdjustment>; export type DocFocusFunc = (doc: Doc, options: DocFocusOptions) => void; @@ -106,7 +114,7 @@ export type StyleProviderFunc = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, p export interface DocComponentView { updateIcon?: () => void; // updates the icon representation of the document getAnchor?: () => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) - scrollFocus?: (doc: Doc, smooth: boolean) => Opt<number>; // returns the duration of the focus + scrollFocus?: (doc: Doc, options: DocFocusOptions) => Opt<number>; // returns the duration of the focus brushView?: (view: { width: number; height: number; panX: number; panY: number }) => void; setViewSpec?: (anchor: Doc, preview: boolean) => void; // sets viewing information for a componentview, typically when following a link. 'preview' tells the view to use the values without writing to the document reverseNativeScaling?: () => boolean; // DocumentView's setup screenToLocal based on the doc having a nativeWidth/Height. However, some content views (e.g., FreeFormView w/ fitContentsToBox set) may ignore the native dimensions so this flags the DocumentView to not do Nativre scaling. @@ -566,7 +574,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps .forEach(spec => (this.layoutDoc[spec.replace(ViewSpecPrefix, '')] = (field => (field instanceof ObjectField ? ObjectField.MakeCopy(field) : field))(anchor[spec]))); // after a render the general viewSpec should have created the right _componentView, so after a timeout, call the componentview to update its specific view specs setTimeout(() => this._componentView?.setViewSpec?.(anchor, LinkDocPreview.LinkInfo ? true : false)); - const focusSpeed = this._componentView?.scrollFocus?.(anchor, options?.instant !== true && !LinkDocPreview.LinkInfo); + const focusSpeed = this._componentView?.scrollFocus?.(anchor, { ...options, instant: options?.instant || LinkDocPreview.LinkInfo ? true : false }); const endFocus = focusSpeed === undefined ? options?.afterFocus : async (moved: boolean) => options?.afterFocus?.(true) ?? ViewAdjustment.doNothing; this.props.focus(options?.docTransform ? anchor : this.rootDoc, { ...options, @@ -741,8 +749,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps toggleFollowLink = (location: Opt<string>, zoom?: boolean, setPushpin?: boolean): void => { this.Document.ignoreClick = false; if (setPushpin) { - this.Document.isPushpin = !this.Document.isPushpin; - this.Document._isLinkButton = this.Document.isPushpin || this.Document._isLinkButton; + this.Document.followLinkToggle = !this.Document.followLinkToggle; + this.Document._isLinkButton = this.Document.followLinkToggle || this.Document._isLinkButton; } else { this.Document._isLinkButton = !this.Document._isLinkButton; } @@ -759,14 +767,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps toggleTargetOnClick = (): void => { this.Document.ignoreClick = false; this.Document._isLinkButton = true; - this.Document.isPushpin = true; + this.Document.followLinkToggle = true; }; @undoBatch @action followLinkOnClick = (location: Opt<string>, zoom: boolean): void => { this.Document.ignoreClick = false; this.Document._isLinkButton = true; - this.Document.isPushpin = false; + this.Document.followLinkToggle = false; this.Document.followLinkZoom = zoom; this.Document.followLinkLocation = location; }; @@ -775,7 +783,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps selectOnClick = (): void => { this.Document.ignoreClick = false; this.Document._isLinkButton = false; - this.Document.isPushpin = false; + this.Document.followLinkToggle = false; this.Document.onClick = this.layoutDoc.onClick = undefined; }; @undoBatch @@ -934,7 +942,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps onClicks.push({ description: this.Document.isLinkButton ? 'Remove Follow Behavior' : 'Follow Link in Place', event: () => this.toggleFollowLink('inPlace', false, false), icon: 'link' }); !this.Document.isLinkButton && onClicks.push({ description: 'Follow Link on Right', event: () => this.toggleFollowLink('add:right', false, false), icon: 'link' }); onClicks.push({ description: this.Document.isLinkButton || this.onClickHandler ? 'Remove Click Behavior' : 'Follow Link', event: () => this.toggleFollowLink(undefined, false, false), icon: 'link' }); - onClicks.push({ description: (this.Document.isPushpin ? 'Remove' : 'Make') + ' Pushpin', event: () => this.toggleFollowLink(undefined, false, true), icon: 'map-pin' }); + onClicks.push({ description: (this.Document.followLinkToggle ? 'Remove' : 'Make') + ' Pushpin', event: () => this.toggleFollowLink(undefined, false, true), icon: 'map-pin' }); onClicks.push({ description: 'Edit onClick Script', event: () => UndoManager.RunInBatch(() => DocUtils.makeCustomViewClicked(this.props.Document, undefined, 'onClick'), 'edit onClick'), icon: 'terminal' }); !existingOnClick && cm.addItem({ description: 'OnClick...', addDivider: true, noexpand: true, subitems: onClicks, icon: 'mouse-pointer' }); } else if (DocListCast(this.Document.links).length) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 1d79febdf..416107859 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -31,7 +31,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import './ImageBox.scss'; import React = require('react'); import { PresBox } from './trails'; -import { DocumentViewProps } from './DocumentView'; +import { DocFocusOptions, DocumentViewProps } from './DocumentView'; export const pageSchema = createSchema({ googlePhotosUrl: 'string', @@ -62,8 +62,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp }; @action - scrollFocus = (anchor: Doc, smooth: boolean) => { - const focusSpeed = !smooth ? 0 : NumCast(anchor.presTransition); + scrollFocus = (anchor: Doc, options: DocFocusOptions) => { + const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; return PresBox.restoreTargetDocView( this.rootDoc, // { pinDocLayout: BoolCast(anchor.presPinDocLayout) }, @@ -168,7 +168,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp const cropping = Doc.MakeCopy(region, true); Doc.GetProto(region).lockedPosition = true; Doc.GetProto(region).title = 'region:' + this.rootDoc.title; - Doc.GetProto(region).isPushpin = true; + Doc.GetProto(region).followLinkToggle = true; this.addDocument(region); const anchx = NumCast(cropping.x); const anchy = NumCast(cropping.y); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 39e323247..b19c4a9e2 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -28,6 +28,7 @@ import './PDFBox.scss'; import { VideoBox } from './VideoBox'; import React = require('react'); import { PresBox } from './trails'; +import { DocFocusOptions } from './DocumentView'; @observer export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps & FieldViewProps>() { @@ -94,7 +95,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps const cropping = Doc.MakeCopy(region, true); Doc.GetProto(region).lockedPosition = true; Doc.GetProto(region).title = 'region:' + this.rootDoc.title; - Doc.GetProto(region).isPushpin = true; + Doc.GetProto(region).followLinkToggle = true; this.addDocument(region); const docViewContent = this.props.docViewPath().lastElement().ContentDiv!; @@ -200,16 +201,16 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps brushView = (view: { width: number; height: number; panX: number; panY: number }) => { this._pdfViewer?.brushView(view); }; - scrollFocus = (doc: Doc, smooth: boolean) => { + scrollFocus = (doc: Doc, options: DocFocusOptions) => { let didToggle = false; if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { - this.toggleSidebar(!smooth); + this.toggleSidebar(!options.instant); didToggle = true; } if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1; this._initialScrollTarget = doc; - PresBox.restoreTargetDocView(this.rootDoc, {}, doc, NumCast(doc.presTransition, NumCast(doc.focusSpeed, 500)), { pannable: doc.presPinData ? true : false }); - return this._pdfViewer?.scrollFocus(doc, NumCast(doc.presPinViewScroll, NumCast(doc.y)), smooth) ?? (didToggle ? 1 : undefined); + PresBox.restoreTargetDocView(this.rootDoc, {}, doc, options.zoomTime ?? 500, { pannable: doc.presPinData ? true : false }); + return this._pdfViewer?.scrollFocus(doc, NumCast(doc.presPinViewScroll, NumCast(doc.y)), options) ?? (didToggle ? 1 : undefined); }; getAnchor = () => { const docAnchor = () => { @@ -277,7 +278,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps setPdfViewer = (pdfViewer: PDFViewer) => { this._pdfViewer = pdfViewer; if (this._initialScrollTarget) { - this.scrollFocus(this._initialScrollTarget, false); + this.scrollFocus(this._initialScrollTarget, { instant: true }); this._initialScrollTarget = undefined; } }; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 82d5b00f9..607cd6187 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -31,7 +31,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; import './VideoBox.scss'; import { ObjectField } from '../../../fields/ObjectField'; -import { OpenWhere } from './DocumentView'; +import { DocFocusOptions, OpenWhere } from './DocumentView'; const path = require('path'); /** @@ -950,7 +950,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp ); }; - scrollFocus = (doc: Doc, smooth: boolean) => { + scrollFocus = (doc: Doc, options: DocFocusOptions) => { if (doc !== this.rootDoc) { const showTime = Cast(doc._timecodeToShow, 'number', null); showTime !== undefined && setTimeout(() => this.Seek(showTime), 100); @@ -1006,7 +1006,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp Doc.GetProto(region).backgroundColor = 'transparent'; Doc.GetProto(region).lockedPosition = true; Doc.GetProto(region).title = 'region:' + this.rootDoc.title; - Doc.GetProto(region).isPushpin = true; + Doc.GetProto(region).followLinkToggle = true; region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001; this.addDocument(region); const anchx = NumCast(cropping.x); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 5ce6a0eb1..64b186489 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -29,7 +29,7 @@ import { AnchorMenu } from '../pdf/AnchorMenu'; import { Annotation } from '../pdf/Annotation'; import { SidebarAnnos } from '../SidebarAnnos'; import { StyleProp } from '../StyleProvider'; -import { DocumentViewProps } from './DocumentView'; +import { DocFocusOptions, DocumentViewProps } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { LinkDocPreview } from './LinkDocPreview'; import { VideoBox } from './VideoBox'; @@ -284,17 +284,17 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps setBrushViewer = (func?: (view: { width: number; height: number; panX: number; panY: number }) => void) => (this._setBrushViewer = func); brushView = (view: { width: number; height: number; panX: number; panY: number }) => this._setBrushViewer?.(view); - scrollFocus = (doc: Doc, smooth: boolean) => { - if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), !smooth); + scrollFocus = (doc: Doc, options: DocFocusOptions) => { + if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), options.instant); if (DocListCast(this.props.Document[this.fieldKey + '-sidebar']).includes(doc) && !this.SidebarShown) { - this.toggleSidebar(!smooth); + this.toggleSidebar(options.instant); } if (this._sidebarRef?.current?.makeDocUnfiltered(doc)) return 1; if (doc !== this.rootDoc && this._outerRef.current) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); const scrollTo = Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.layoutDoc._scrollTop), windowHeight, windowHeight * 0.1, Math.max(NumCast(doc.y) + doc[HeightSym](), this.getScrollHeight())); if (scrollTo !== undefined && this._initialScroll === undefined) { - const focusSpeed = smooth ? NumCast(doc.focusSpeed, 500) : 0; + const focusSpeed = options.instant ? 0 : options.zoomTime ?? 500; this.goTo(scrollTo, focusSpeed); return focusSpeed; } else if (!this._webPageHasBeenRendered || !this.getScrollHeight() || this._initialScroll !== undefined) { diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index ce4639b76..9e91f6c46 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -45,7 +45,7 @@ import { LightboxView } from '../../LightboxView'; import { AnchorMenu } from '../../pdf/AnchorMenu'; import { SidebarAnnos } from '../../SidebarAnnos'; import { StyleProp } from '../../StyleProvider'; -import { DocumentViewInternal, OpenWhere } from '../DocumentView'; +import { DocFocusOptions, DocumentViewInternal, OpenWhere } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { LinkDocPreview } from '../LinkDocPreview'; import { DashDocCommentView } from './DashDocCommentView'; @@ -689,9 +689,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps pinToPres = (anchor: Doc) => this.props.pinToPres(anchor, {}); @undoBatch - makePushpin = (anchor: Doc) => (anchor.isPushpin = !anchor.isPushpin); + makePushpin = (anchor: Doc) => (anchor.followLinkToggle = !anchor.followLinkToggle); - isPushpin = (anchor: Doc) => BoolCast(anchor.isPushpin); + isPushpin = (anchor: Doc) => BoolCast(anchor.followLinkToggle); specificContextMenu = (e: React.MouseEvent): void => { const cm = ContextMenu.Instance; @@ -922,10 +922,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps return anchorDoc ?? this.rootDoc; } - scrollFocus = (textAnchor: Doc, smooth: boolean) => { + scrollFocus = (textAnchor: Doc, options: DocFocusOptions) => { let didToggle = false; if (DocListCast(this.Document[this.fieldKey + '-sidebar']).includes(textAnchor) && !this.SidebarShown) { - this.toggleSidebar(!smooth); + this.toggleSidebar(options.instant); didToggle = true; } const textAnchorId = textAnchor[Id]; @@ -966,7 +966,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps const content = (ret.frag as any)?.content; if ((ret.frag.size > 2 || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) { - smooth && (this._focusSpeed = 500); + !options.instant && (this._focusSpeed = 500); let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start if (ret.frag.firstChild) { selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx index c04b79a1e..4073677f3 100644 --- a/src/client/views/nodes/trails/PresBox.tsx +++ b/src/client/views/nodes/trails/PresBox.tsx @@ -15,7 +15,7 @@ import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../../fields/Ty import { AudioField } from '../../../../fields/URLField'; import { emptyFunction, returnFalse, returnOne, setupMoveUpEvents, StopEvent } from '../../../../Utils'; import { DocServer } from '../../../DocServer'; -import { Docs } from '../../../documents/Documents'; +import { Docs, DocumentOptions } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocumentManager } from '../../../util/DocumentManager'; import { ScriptingGlobals } from '../../../util/ScriptingGlobals'; @@ -35,7 +35,7 @@ import { ScriptingBox } from '../ScriptingBox'; import './PresBox.scss'; import { PresEffect, PresEffectDirection, PresMovement, PresStatus } from './PresEnums'; import { map } from 'bluebird'; -import { OpenWhere, OpenWhereMod } from '../DocumentView'; +import { DocFocusOptions, OpenWhere, OpenWhereMod } from '../DocumentView'; const { Howl } = require('howler'); export interface PinProps { @@ -313,6 +313,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { this.rootDoc._itemIndex = index; const activeItem: Doc = this.activeItem; const targetDoc: Doc = this.targetDoc; + let focusSpeed = 500; if (activeItem.presActiveFrame !== undefined) { const transTime = NumCast(activeItem.presTransition, 500); const context = DocCast(DocCast(activeItem.presentationTargetDoc).context); @@ -334,11 +335,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { if (this.layoutDoc.presStatus !== PresStatus.Edit && (targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && activeItem.mediaStart === 'auto') { this.startTempMedia(targetDoc, activeItem); } - if (targetDoc) { - // Doc.linkFollowHighlight(targetDoc.annotationOn instanceof Doc ? [targetDoc, targetDoc.annotationOn] : targetDoc); - targetDoc && runInAction(() => (targetDoc.focusSpeed = activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500))); - setTimeout(() => (targetDoc.focusSpeed = undefined), NumCast(targetDoc.focusSpeed) + 10); - } if (targetDoc?.lastFrame !== undefined) { targetDoc._currentFrame = 0; } @@ -583,8 +579,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { LightboxView.SetLightboxDoc(targetDoc); // openInTab(targetDoc); } else if (targetDoc && activeItem.presMovement !== PresMovement.None) { LightboxView.SetLightboxDoc(undefined); - const zooming = activeItem.presMovement !== PresMovement.Pan; - DocumentManager.Instance.jumpToDocument(targetDoc, zooming, openInTab, srcContext ? [srcContext] : [], undefined, undefined, activeItem, finished, undefined, true, NumCast(activeItem.presZoom, 1)); + const options: DocFocusOptions = { + willZoom: activeItem.presMovement !== PresMovement.Pan, + zoomScale: NumCast(activeItem.presZoom, 1), + zoomTime: activeItem.presMovement === PresMovement.Jump ? 0 : NumCast(activeItem.presTransition, 500), + noSelect: true, + originatingDoc: activeItem, + }; + DocumentManager.Instance.jumpToDocument(targetDoc, options, openInTab, srcContext ? [srcContext] : [], finished); } else if (activeItem.presMovement === PresMovement.None && targetDoc.type === DocumentType.SCRIPTING) { (DocumentManager.Instance.getFirstDocumentView(targetDoc)?.ComponentView as ScriptingBox)?.onRun?.(); } @@ -1199,7 +1201,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { _batch: UndoManager.Batch | undefined = undefined; - public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?:number) => { + public static inputter = (min: string, step: string, max: string, value: number, active: boolean, change: (val: string) => void, hmargin?: number) => { let batch: any; return ( <input @@ -1208,7 +1210,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() { min={min} max={max} value={value} - style={{marginLeft: hmargin, marginRight:hmargin, width: `calc(100% - ${2*(hmargin??0)}px)`}} + style={{ marginLeft: hmargin, marginRight: hmargin, width: `calc(100% - ${2 * (hmargin ?? 0)}px)` }} className={`toolbar-slider ${active ? '' : 'none'}`} onPointerDown={e => { batch = UndoManager.StartBatch('pres slider'); |
