diff options
Diffstat (limited to 'src/client/views')
17 files changed, 211 insertions, 106 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index ae4b7cf3a..92c947fe6 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -34,7 +34,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } @computed get layoutDoc() { return Doc.Layout(this.props.Document); } - @computed get dataDoc() { return (this.props.DataDoc && this.props.Document.isTemplateField ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } + @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } @computed get extensionDoc() { return Doc.fieldExtensionDoc(this.dataDoc, this.props.fieldKey); } active = () => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected() || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools } diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index ba87ecfb4..1412316f9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -5,7 +5,7 @@ import { action, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../new_fields/Doc"; import { RichTextField } from '../../new_fields/RichTextField'; -import { NumCast } from "../../new_fields/Types"; +import { NumCast, StrCast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; @@ -135,13 +135,27 @@ export class DocumentButtonBar extends React.Component<{ views: DocumentView[], if (this._linkerButton.current !== null) { document.removeEventListener("pointermove", this.onLinkerButtonMoved); document.removeEventListener("pointerup", this.onLinkerButtonUp); - let selDoc = this.props.views[0]; - let container = selDoc.props.ContainingCollectionDoc ? selDoc.props.ContainingCollectionDoc.proto : undefined; - let dragData = new DragManager.LinkDragData(selDoc.props.Document, container ? [container] : []); - let _linkDrag = UndoManager.StartBatch("Drag Link"); + let docView = this.props.views[0]; + let container = docView.props.ContainingCollectionDoc ? docView.props.ContainingCollectionDoc.proto : undefined; + let dragData = new DragManager.LinkDragData(docView.props.Document, container ? [container] : []); + let linkDrag = UndoManager.StartBatch("Drag Link"); DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { handlers: { - dragComplete: () => _linkDrag && _linkDrag.end() + dragComplete: () => { + let tooltipmenu = FormattedTextBox.ToolTipTextMenu; + let linkDoc = dragData.linkDocument; + if (linkDoc && tooltipmenu) { + let proto = Doc.GetProto(linkDoc); + if (proto && docView) { + proto.sourceContext = docView.props.ContainingCollectionDoc; + } + let text = tooltipmenu.makeLink(linkDoc, StrCast(linkDoc.anchor2.title), e.ctrlKey ? "onRight" : "inTab"); + if (linkDoc instanceof Doc && linkDoc.anchor2 instanceof Doc) { + proto.title = text === "" ? proto.title : text + " to " + linkDoc.anchor2.title; // TODODO open to more descriptive descriptions of following in text link + } + } + linkDrag && linkDrag.end(); + } }, hideSource: false }); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 55c211d1d..890c32bcb 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -157,22 +157,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> this.onBackgroundUp(e); } - @observable _forceUpdate = 0; - _lastBox = { x: 0, y: 0, r: 0, b: 0 }; @computed get Bounds(): { x: number, y: number, b: number, r: number } { - let x = this._forceUpdate; - this._lastBox = SelectionManager.SelectedDocuments().reduce((bounds, documentView) => { + return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => { if (documentView.props.renderDepth === 0 || Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) { return bounds; } let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse(); - if (transform.TranslateX === 0 && transform.TranslateY === 0) { - setTimeout(action(() => this._forceUpdate++), 0); // bcz: fix CollectionStackingView's getTransform() somehow...without this, resizing things in the library view, for instance, show the wrong bounds - return this._lastBox; - } - var [sptX, sptY] = transform.transformPoint(0, 0); let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight()); if (documentView.props.Document.type === DocumentType.LINK) { @@ -187,7 +179,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) }; }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); - return this._lastBox; } onBackgroundDown = (e: React.PointerEvent): void => { @@ -557,8 +548,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } } public showTextBar = () => { - if (this.TextBar) { - TooltipTextMenu.Toolbar && Array.from(this.TextBar.childNodes).indexOf(TooltipTextMenu.Toolbar) === -1 && this.TextBar.appendChild(TooltipTextMenu.Toolbar); + if (this.TextBar && TooltipTextMenu.Toolbar && Array.from(this.TextBar.childNodes).indexOf(TooltipTextMenu.Toolbar) === -1) { + this.TextBar.appendChild(TooltipTextMenu.Toolbar); } } render() { diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 14e309f68..e66b42690 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -51,7 +51,10 @@ export class Track extends React.Component<IProps> { componentWillMount() { runInAction(() => { - if (!this.props.node.regions) this.props.node.regions = new List<Doc>(); + if (!this.props.node.regions) this.props.node.regions = new List<Doc>(); + console.log("hi"); + console.log("HELLO"); + console.log("hi"); }); } diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 203c68463..ebd47fd19 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -141,7 +141,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { <ContentFittingDocumentView Document={layoutDoc} DataDocument={this.previewDocument !== this.props.DataDoc ? this.props.DataDoc : undefined} - fieldKey={this.props.fieldKey} childDocs={this.childDocs} renderDepth={this.props.renderDepth} ruleProvider={this.props.Document.isRuleProvider && layoutDoc && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 15033e51a..be3bfca0a 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -168,7 +168,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return <ContentFittingDocumentView Document={doc} DataDocument={dataDoc} - fieldKey={this.props.fieldKey} showOverlays={this.overlays} renderDepth={this.props.renderDepth} ruleProvider={this.props.Document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.Document : this.props.ruleProvider} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 8726726bb..0e3f0d1a9 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -23,7 +23,6 @@ import { EditableView } from "../EditableView"; import { MainView } from '../MainView'; import { KeyValueBox } from '../nodes/KeyValueBox'; import { Templates } from '../Templates'; -import { CollectionViewType } from './CollectionView'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; import { CollectionSubView } from "./CollectionSubView"; import "./CollectionTreeView.scss"; @@ -177,8 +176,10 @@ class TreeView extends React.Component<TreeViewProps> { />) onWorkspaceContextMenu = (e: React.MouseEvent): void => { - if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking && this.props.document !== CurrentUserUtils.UserDocument.workspaces) { + if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view + if (this.props.document === CurrentUserUtils.UserDocument.recentlyClosed) { + ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List<Doc>(), icon: "plus" }); + } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) { ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" }); ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "inTab"), icon: "folder" }); ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight"), icon: "caret-square-right" }); @@ -317,7 +318,6 @@ class TreeView extends React.Component<TreeViewProps> { <ContentFittingDocumentView Document={layoutDoc} DataDocument={this.templateDataDoc} - fieldKey={this.fieldKey} renderDepth={this.props.renderDepth} showOverlays={this.noOverlays} ruleProvider={this.props.document.isRuleProvider && layoutDoc.type !== DocumentType.TEXT ? this.props.document : this.props.ruleProvider} @@ -538,6 +538,11 @@ export class CollectionTreeView extends CollectionSubView(Document) { e.stopPropagation(); e.preventDefault(); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); + } else if (!e.isPropagationStopped() && this.props.Document === CurrentUserUtils.UserDocument.recentlyClosed) { + ContextMenu.Instance.addItem({ description: "Clear All", event: () => CurrentUserUtils.UserDocument.recentlyClosed = new List<Doc>(), icon: "plus" }); + e.stopPropagation(); + e.preventDefault(); + ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); } else { let layoutItems: ContextMenuProps[] = []; layoutItems.push({ description: this.props.Document.preventTreeViewOpen ? "Persist Treeview State" : "Abandon Treeview State", event: () => this.props.Document.preventTreeViewOpen = !this.props.Document.preventTreeViewOpen, icon: "paint-brush" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2d7a557b5..f6240b6f8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -335,7 +335,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action onPointerWheel = (e: React.WheelEvent): void => { - if (this.props.Document.lockedPosition || this.props.Document.inOverlay) return; + if (this.props.Document.lockedTransform || this.props.Document.inOverlay) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -357,7 +357,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action setPan(panX: number, panY: number, panType: string = "None") { - if (!this.Document.lockedPosition || this.Document.inOverlay) { + if (!this.Document.lockedTransform || this.Document.inOverlay) { this.Document.panTransformType = panType; var scale = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index f41c4fc91..c8255b6fe 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -20,7 +20,6 @@ interface ContentFittingDocumentViewProps { childDocs?: Doc[]; renderDepth: number; fitToBox?: boolean; - fieldKey: string; PanelWidth: () => number; PanelHeight: () => number; ruleProvider: Doc | undefined; @@ -37,6 +36,7 @@ interface ContentFittingDocumentViewProps { whenActiveChanged: (isActive: boolean) => void; addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean; pinToPres: (document: Doc) => void; + dontRegisterView?: boolean; setPreviewScript: (script: string) => void; previewScript?: string; } @@ -108,6 +108,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo focus={this.props.focus || emptyFunction} backgroundColor={returnEmptyString} bringToFront={emptyFunction} + dontRegisterView={this.props.dontRegisterView} zoomToScale={emptyFunction} getScale={returnOne} /> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 93052ea73..7132f181e 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -74,6 +74,7 @@ export interface DocumentViewProps { getScale: () => number; animateBetweenIcon?: (maximize: boolean, target: number[]) => void; ChromeHeight?: () => number; + dontRegisterView?: boolean; layoutKey?: string; } @@ -98,7 +99,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu @action componentDidMount() { this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } })); - DocumentManager.Instance.DocumentViews.push(this); + + !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.push(this); } @action @@ -111,7 +113,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu componentWillUnmount() { this._dropDisposer && this._dropDisposer(); Doc.UnBrushDoc(this.props.Document); - DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); + !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1); } startDragging(x: number, y: number, dropAction: dropActionType, applyAsTemplate?: boolean) { @@ -136,7 +138,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { e.stopPropagation(); let preventDefault = true; - if (this._doubleTap && this.props.renderDepth && (!this.onClickHandler || !this.onClickHandler.script)) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click + if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click let fullScreenAlias = Doc.MakeAlias(this.props.Document); if (StrCast(fullScreenAlias.layoutKey) !== "layoutCustom" && fullScreenAlias.layoutCustom !== undefined) { fullScreenAlias.layoutKey = "layoutCustom"; @@ -350,9 +352,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu @undoBatch @action setCustomView = (custom: boolean): void => { - if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.DataDoc) { - Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.DataDoc); - } else { // bcz: not robust -- for now documents with string layout are native documents, and those with Doc layouts are customized + if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) { + Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document); + } else { custom ? DocumentView.makeCustomViewClicked(this.props.Document, this.props.DataDoc) : DocumentView.makeNativeViewClicked(this.props.Document); } } @@ -370,6 +372,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true; } + @undoBatch + @action + toggleLockTransform = (): void => { + this.Document.lockedTransform = this.Document.lockedTransform ? undefined : true; + } + listen = async () => { Doc.GetProto(this.props.Document).transcript = await DictationManager.Controls.listen({ continuous: { indefinite: true }, @@ -442,6 +450,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu layoutItems.push({ description: `${this.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc.autoHeight = !this.layoutDoc.autoHeight, icon: "plus" }); layoutItems.push({ description: this.Document.ignoreAspect || !this.Document.nativeWidth || !this.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" }); layoutItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); + layoutItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" }); layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" }); if (this.Document.type !== DocumentType.COL && this.Document.type !== DocumentType.TEMPLATE) { @@ -630,7 +639,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu {searchHighlight} </div> } - </> + </>; } render() { if (!this.props.Document) return (null); diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index ae9273639..83ecc4657 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -25,7 +25,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>( this._backgroundReaction = reaction(() => this.props.Document.backgroundColor, () => { if (this._ref && this._ref.current) { - let col = Utils.fromRGBAstr(getComputedStyle(this._ref.current).backgroundColor!); + let col = Utils.fromRGBAstr(getComputedStyle(this._ref.current).backgroundColor); let colsum = (col.r + col.g + col.b); if (colsum / col.a > 600 || col.a < 0.25) runInAction(() => this._foregroundColor = "black"); else if (colsum / col.a <= 600 || col.a >= .25) runInAction(() => this._foregroundColor = "white"); diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index a4acd3b82..b497b12b4 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -36,6 +36,18 @@ } } +.collectionfreeformview-container { + position: relative; +} +.formattedTextBox-outer { + position: relative; + overflow: auto; + display: inline-block; + padding: 10px 10px; + width: 100%; + height: 100%; +} + .formattedTextBox-inner-rounded { height: 70%; width: 85%; @@ -51,17 +63,17 @@ height: 100%; } -.menuicon { - display: inline-block; - border-right: 1px solid rgba(0, 0, 0, 0.2); - color: #888; - line-height: 1; - padding: 0 7px; - margin: 1px; - cursor: pointer; - text-align: center; - min-width: 1.4em; -} +// .menuicon { +// display: inline-block; +// border-right: 1px solid rgba(0, 0, 0, 0.2); +// color: #888; +// line-height: 1; +// padding: 0 7px; +// margin: 1px; +// cursor: pointer; +// text-align: center; +// min-width: 1.4em; +// } .strong, .heading { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 24d6f2509..35212b732 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -17,14 +17,13 @@ import { Copy, Id } from '../../../new_fields/FieldSymbols'; import { RichTextField } from "../../../new_fields/RichTextField"; import { RichTextUtils } from '../../../new_fields/RichTextUtils'; import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Cast, DateCast, NumCast, StrCast } from "../../../new_fields/Types"; -import { numberRange, Utils, addStyleSheet, addStyleSheetRule, clearStyleSheetRules } from '../../../Utils'; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { numberRange, Utils, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, returnOne } from '../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils'; import { DocServer } from "../../DocServer"; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { DictationManager } from '../../util/DictationManager'; -import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorExampleTransfer"; import { inpRules } from "../../util/RichTextRules"; @@ -33,7 +32,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; import { undoBatch, UndoManager } from "../../util/UndoManager"; -import { DocExtendableComponent } from "../DocComponent"; +import { DocAnnotatableComponent } from "../DocComponent"; import { DocumentButtonBar } from '../DocumentButtonBar'; import { DocumentDecorations } from '../DocumentDecorations'; import { InkingControl } from "../InkingControl"; @@ -46,6 +45,7 @@ import { ContextMenu } from '../ContextMenu'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { documentSchema } from '../../../new_fields/documentSchemas'; import { AudioBox } from './AudioBox'; +import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -70,11 +70,11 @@ const RichTextDocument = makeInterface(richTextSchema, documentSchema); type PullHandler = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => void; @observer -export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) { +export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(FormattedTextBox, fieldStr); } public static blankState = () => EditorState.create(FormattedTextBox.Instance.config); public static Instance: FormattedTextBox; - private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined; + public static ToolTipTextMenu: TooltipTextMenu | undefined = undefined; private _ref: React.RefObject<HTMLDivElement> = React.createRef(); private _proseRef?: HTMLDivElement; private _editorView: Opt<EditorView>; @@ -85,7 +85,6 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F private _searchReactionDisposer?: Lambda; private _scrollToRegionReactionDisposer: Opt<IReactionDisposer>; private _reactionDisposer: Opt<IReactionDisposer>; - private _textReactionDisposer: Opt<IReactionDisposer>; private _heightReactionDisposer: Opt<IReactionDisposer>; private _rulesReactionDisposer: Opt<IReactionDisposer>; private _proxyReactionDisposer: Opt<IReactionDisposer>; @@ -120,7 +119,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F } public static getToolTip(ev: EditorView) { - return this._toolTipTextMenu ? this._toolTipTextMenu : this._toolTipTextMenu = new TooltipTextMenu(ev); + return this.ToolTipTextMenu ? this.ToolTipTextMenu : this.ToolTipTextMenu = new TooltipTextMenu(ev); } @undoBatch @@ -191,9 +190,8 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F let tsel = this._editorView.state.selection.$from; tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 1000))); this._applyingChange = true; - this.extensionDoc && (this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n")); this.extensionDoc && (this.extensionDoc.lastModified = new DateField(new Date(Date.now()))); - this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON())); + this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), state.doc.textBetween(0, state.doc.content.size, "\n\n")); this._applyingChange = false; this.updateTitle(); this.tryUpdateHeight(); @@ -250,7 +248,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F // replace text contents whend dragging with Alt if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.mods === "AltKey") { if (draggedDoc.data instanceof RichTextField) { - Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data); + Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text); e.stopPropagation(); } // apply as template when dragging with Meta @@ -290,6 +288,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F if (context === node) return { from: offset, to: offset + node.nodeSize }; if (node.isBlock) { + // tslint:disable-next-line: prefer-for-of for (let i = 0; i < (context.content as any).content.length; i++) { let result = this.getNodeEndpoints((context.content as any).content[i], node); if (result) { @@ -360,6 +359,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F specificContextMenu = (e: React.MouseEvent): void => { let funcs: ContextMenuProps[] = []; + funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document.sidebarWidthPercent = StrCast(this.props.Document.sidebarWidthPercent, "0%") === "0%" ? "25%" : "0%"; }, icon: "expand-arrows-alt" }); funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" }); ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option => funcs.push({ @@ -510,17 +510,6 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F () => this.tryUpdateHeight() ); - this._textReactionDisposer = reaction( - () => this.extensionDoc, - () => { - if (this.extensionDoc && (this.dataDoc.text || this.dataDoc.lastModified)) { - this.extensionDoc.text = this.dataDoc.text; - this.extensionDoc.lastModified = DateCast(this.dataDoc.lastModified)[Copy](); - this.dataDoc.text = undefined; - this.dataDoc.lastModified = undefined; - } - }, { fireImmediately: true }); - this.setupEditor(this.config, this.dataDoc, this.props.fieldKey); @@ -787,7 +776,9 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F while (refNode && !("getBoundingClientRect" in refNode)) refNode = refNode.parentElement; let r1 = refNode && refNode.getBoundingClientRect(); let r3 = self._ref.current!.getBoundingClientRect(); - r1 && (self._ref.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale); + if (r1.top < r3.top || r1.top > r3.bottom) { + r1 && (self._ref.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale); + } return true; }, dispatchTransaction: this.dispatchTransaction, @@ -834,7 +825,6 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F this._rulesReactionDisposer && this._rulesReactionDisposer(); this._reactionDisposer && this._reactionDisposer(); this._proxyReactionDisposer && this._proxyReactionDisposer(); - this._textReactionDisposer && this._textReactionDisposer(); this._pushReactionDisposer && this._pushReactionDisposer(); this._pullReactionDisposer && this._pullReactionDisposer(); this._heightReactionDisposer && this._heightReactionDisposer(); @@ -857,7 +847,10 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F } onPointerUp = (e: React.PointerEvent): void => { - if (!(e.nativeEvent as any).formattedHandled) { FormattedTextBoxComment.textBox = this; } + if (!(e.nativeEvent as any).formattedHandled) { + FormattedTextBoxComment.textBox = this; + FormattedTextBoxComment.update(this._editorView!); + } (e.nativeEvent as any).formattedHandled = true; if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { @@ -968,7 +961,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F let self = FormattedTextBox; return new Plugin({ view(newView) { - return self._toolTipTextMenu = FormattedTextBox.getToolTip(newView); + return self.ToolTipTextMenu = FormattedTextBox.getToolTip(newView); } }); } @@ -1018,12 +1011,15 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F } } + @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidth, "0%"); } + @computed get sidebarWidth() { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); } + @computed get annotationsKey() { return "annotations"; } render() { trace(); let rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : ""; let interactive = InkingControl.Instance.selectedTool || this.layoutDoc.isBackground; if (this.props.isSelected()) { - FormattedTextBox._toolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props); + FormattedTextBox.ToolTipTextMenu!.updateFromDash(this._editorView!, undefined, this.props); } else if (FormattedTextBoxComment.textBox === this) { FormattedTextBoxComment.Hide(); } @@ -1050,8 +1046,32 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F onPointerEnter={action(() => this._entered = true)} onPointerLeave={action(() => this._entered = false)} > - <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} /> - + <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }}> + <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} /> + </div> + {this.sidebarWidthPercent === "0%" ? (null) : <div style={{ borderLeft: "solid 1px black", width: `${this.sidebarWidthPercent}`, height: "100%", display: "inline-block" }}> + <CollectionFreeFormView {...this.props} + PanelHeight={() => this.props.PanelHeight()} + PanelWidth={() => this.sidebarWidth} + annotationsKey={this.annotationsKey} + isAnnotationOverlay={true} + focus={this.props.focus} + isSelected={this.props.isSelected} + select={emptyFunction} + active={this.active} + ContentScaling={returnOne} + whenActiveChanged={this.whenActiveChanged} + removeDocument={this.removeDocument} + moveDocument={this.moveDocument} + addDocument={this.addDocument} + CollectionView={undefined} + ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)} + ruleProvider={undefined} + renderDepth={this.props.renderDepth + 1} + ContainingCollectionDoc={this.props.ContainingCollectionDoc} + chromeCollapsed={true}> + </CollectionFreeFormView> + </div>} <div className="formattedTextBox-dictation" onClick={e => { this._recording ? this.stopDictation(true) : this.recordDictation(); diff --git a/src/client/views/nodes/FormattedTextBoxComment.scss b/src/client/views/nodes/FormattedTextBoxComment.scss index 792cee182..2dd63ec21 100644 --- a/src/client/views/nodes/FormattedTextBoxComment.scss +++ b/src/client/views/nodes/FormattedTextBoxComment.scss @@ -5,7 +5,6 @@ background: white; border: 1px solid silver; border-radius: 2px; - padding: 2px 10px; margin-bottom: 7px; -webkit-transform: translateX(-50%); transform: translateX(-50%); diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx index f35ca502f..c076fd34a 100644 --- a/src/client/views/nodes/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/FormattedTextBoxComment.tsx @@ -1,17 +1,20 @@ -import { Plugin, EditorState } from "prosemirror-state"; -import './FormattedTextBoxComment.scss'; -import { ResolvedPos, Mark } from "prosemirror-model"; +import { Mark, ResolvedPos } from "prosemirror-model"; +import { EditorState, Plugin } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; +import * as ReactDOM from 'react-dom'; import { Doc } from "../../../new_fields/Doc"; -import { schema } from "../../util/RichTextSchema"; +import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { emptyFunction, returnEmptyString, returnFalse, Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; -import { Utils } from "../../../Utils"; -import { StrCast, Cast, FieldValue } from "../../../new_fields/Types"; -import { FormattedTextBox } from "./FormattedTextBox"; -import { DocUtils } from "../../documents/Documents"; -import { isBuffer } from "util"; import { DocumentManager } from "../../util/DocumentManager"; -import { DocumentType } from "../../documents/DocumentTypes"; +import { schema } from "../../util/RichTextSchema"; +import { Transform } from "../../util/Transform"; +import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; +import { FormattedTextBox } from "./FormattedTextBox"; +import './FormattedTextBoxComment.scss'; +import React = require("react"); +import { Docs } from "../../documents/Documents"; +import wiki from "wikijs"; export let formattedTextBoxCommentPlugin = new Plugin({ view(editorView) { return new FormattedTextBoxComment(editorView); } @@ -50,6 +53,7 @@ export function findEndOfMark(rpos: ResolvedPos, view: EditorView, finder: (mark export class FormattedTextBoxComment { static tooltip: HTMLElement; static tooltipText: HTMLElement; + static tooltipInput: HTMLInputElement; static start: number; static end: number; static mark: Mark; @@ -59,30 +63,40 @@ export class FormattedTextBoxComment { constructor(view: any) { if (!FormattedTextBoxComment.tooltip) { const root = document.getElementById("root"); - let input = document.createElement("input"); - input.type = "checkbox"; + FormattedTextBoxComment.tooltipInput = document.createElement("input"); + FormattedTextBoxComment.tooltipInput.type = "checkbox"; FormattedTextBoxComment.tooltip = document.createElement("div"); FormattedTextBoxComment.tooltipText = document.createElement("div"); + FormattedTextBoxComment.tooltipText.style.width = "100%"; + FormattedTextBoxComment.tooltipText.style.height = "100%"; + FormattedTextBoxComment.tooltipText.style.textOverflow = "ellipsis"; FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipText); FormattedTextBoxComment.tooltip.className = "FormattedTextBox-tooltip"; FormattedTextBoxComment.tooltip.style.pointerEvents = "all"; FormattedTextBoxComment.tooltip.style.maxWidth = "350px"; - FormattedTextBoxComment.tooltip.appendChild(input); + FormattedTextBoxComment.tooltip.style.maxHeight = "250px"; + FormattedTextBoxComment.tooltip.style.width = "100%"; + FormattedTextBoxComment.tooltip.style.height = "100%"; + FormattedTextBoxComment.tooltip.style.overflow = "hidden"; + FormattedTextBoxComment.tooltip.style.display = "none"; + FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipInput); FormattedTextBoxComment.tooltip.onpointerdown = (e: PointerEvent) => { let keep = e.target && (e.target as any).type === "checkbox" ? true : false; - if (FormattedTextBoxComment.linkDoc && !keep && FormattedTextBoxComment.textBox) { - DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, FormattedTextBoxComment.textBox.props.Document, - (doc: Doc, maxLocation: string) => FormattedTextBoxComment.textBox!.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight")); + const textBox = FormattedTextBoxComment.textBox; + if (FormattedTextBoxComment.linkDoc && !keep && textBox) { + DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, + (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight")); + } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) { + textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, width: 200, height: 400 }), undefined, "onRight"); } FormattedTextBoxComment.opened = keep || !FormattedTextBoxComment.opened; - FormattedTextBoxComment.textBox && FormattedTextBoxComment.start !== undefined && FormattedTextBoxComment.textBox.setAnnotation( + textBox && FormattedTextBoxComment.start !== undefined && textBox.setAnnotation( FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark, FormattedTextBoxComment.opened, keep); e.stopPropagation(); }; root && root.appendChild(FormattedTextBoxComment.tooltip); } - this.update(view, undefined); } public static Hide() { @@ -98,7 +112,7 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = ""); } - update(view: EditorView, lastState?: EditorState) { + static update(view: EditorView, lastState?: EditorState) { let state = view.state; // Don't do anything if the document/selection didn't change if (lastState && lastState.doc.eq(state.doc) && @@ -113,6 +127,12 @@ export class FormattedTextBoxComment { } let set = "none"; let nbef = 0; + FormattedTextBoxComment.tooltipInput.style.display = "none"; + FormattedTextBoxComment.tooltip.style.width = ""; + FormattedTextBoxComment.tooltip.style.height = ""; + (FormattedTextBoxComment.tooltipText as any).href = ""; + FormattedTextBoxComment.tooltipText.style.whiteSpace = ""; + FormattedTextBoxComment.tooltipText.style.overflow = ""; // this section checks to see if the insertion point is over text entered by a different user. If so, it sets ths comment text to indicate the user and the modification date if (state.selection.$from) { nbef = findStartOfMark(state.selection.$from, view, findOtherUserMark); @@ -127,6 +147,7 @@ export class FormattedTextBoxComment { if (mark && child && ((nbef && naft) || !noselection)) { FormattedTextBoxComment.tooltipText.textContent = mark.attrs.userid + " date=" + (new Date(mark.attrs.modified * 5000)).toDateString(); set = ""; + FormattedTextBoxComment.tooltipInput.style.display = ""; } } // this checks if the selection is a hyperlink. If so, it displays the target doc's text for internal links, and the url of the target for external links. @@ -138,15 +159,48 @@ export class FormattedTextBoxComment { let mark = child && findLinkMark(child.marks); if (mark && child && nbef && naft) { FormattedTextBoxComment.tooltipText.textContent = "external => " + mark.attrs.href; + if (mark.attrs.href.startsWith("https://en.wikipedia.org/wiki/")) { + wiki().page(mark.attrs.href.replace("https://en.wikipedia.org/wiki/", "")).then(page => page.summary().then(summary => FormattedTextBoxComment.tooltipText.textContent = summary.substring(0, 500))); + } else { + FormattedTextBoxComment.tooltipText.style.whiteSpace = "pre"; + FormattedTextBoxComment.tooltipText.style.overflow = "hidden"; + } + (FormattedTextBoxComment.tooltipText as any).href = mark.attrs.href; if (mark.attrs.href.indexOf(Utils.prepend("/doc/")) === 0) { let docTarget = mark.attrs.href.replace(Utils.prepend("/doc/"), "").split("?")[0]; docTarget && DocServer.GetRefField(docTarget).then(linkDoc => { if (linkDoc instanceof Doc) { FormattedTextBoxComment.linkDoc = linkDoc; - let target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc)); - let ext = (target && target.type !== DocumentType.PDFANNO && Doc.fieldExtensionDoc(target, "data")) || target; // try guessing that the target doc's data is in the 'data' field. probably need an 'overviewLayout' and then just display the target Document .... - let text = ext && StrCast(ext.text); - ext && (FormattedTextBoxComment.tooltipText.textContent = (target && target.type === DocumentType.PDFANNO ? "Quoted from " : "") + "=> " + (text || StrCast(ext.title))); + const target = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.props.Document) ? Cast(linkDoc.anchor2, Doc) : Cast(linkDoc.anchor1, Doc)); + try { + ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText); + } catch (e) { } + if (target) { + ReactDOM.render(<ContentFittingDocumentView + fitToBox={true} + Document={target} + moveDocument={returnFalse} + getTransform={Transform.Identity} + active={returnFalse} + setPreviewScript={returnEmptyString} + addDocument={returnFalse} + removeDocument={returnFalse} + ruleProvider={undefined} + addDocTab={returnFalse} + pinToPres={returnFalse} + dontRegisterView={true} + renderDepth={1} + PanelWidth={() => Math.min(350, NumCast(target.width, 350))} + PanelHeight={() => Math.min(250, NumCast(target.height, 250))} + focus={emptyFunction} + whenActiveChanged={returnFalse} + />, FormattedTextBoxComment.tooltipText); + FormattedTextBoxComment.tooltip.style.width = NumCast(target.width) ? `${NumCast(target.width)}` : "100%"; + FormattedTextBoxComment.tooltip.style.height = NumCast(target.height) ? `${NumCast(target.height)}` : "100%"; + } + // let ext = (target && target.type !== DocumentType.PDFANNO && Doc.fieldExtensionDoc(target, "data")) || target; // try guessing that the target doc's data is in the 'data' field. probably need an 'overviewLayout' and then just display the target Document .... + // let text = ext && StrCast(ext.text); + // ext && (FormattedTextBoxComment.tooltipText.textContent = (target && target.type === DocumentType.PDFANNO ? "Quoted from " : "") + "=> " + (text || StrCast(ext.title))); } }); } @@ -168,5 +222,5 @@ export class FormattedTextBoxComment { FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = set); } - destroy() { FormattedTextBoxComment.tooltip.style.display = "none"; } + destroy() { } } diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 17b2094ec..f50a3a0ef 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -172,7 +172,6 @@ export class PresElementBox extends DocComponent<FieldViewProps, PresDocument>(P <ContentFittingDocumentView fitToBox={StrCast(this.targetDoc.type).indexOf(DocumentType.COL) !== -1} Document={this.targetDoc} - fieldKey={this.props.fieldKey} addDocument={returnFalse} removeDocument={returnFalse} ruleProvider={undefined} diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index b841190d4..62f3aba4c 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -33,7 +33,7 @@ export enum Keys { export class FilterBox extends React.Component { static Instance: FilterBox; - public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB]; + public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB, DocumentType.TEMPLATE]; //if true, any keywords can be used. if false, all keywords are required. //this also serves as an indicator if the word status filter is applied @@ -82,7 +82,7 @@ export class FilterBox extends React.Component { var panel = this.nextElementSibling as HTMLElement; if (panel.style.maxHeight) { panel.style.overflow = "hidden"; - panel.style.maxHeight = null; + panel.style.maxHeight = ""; panel.style.opacity = "0"; } else { setTimeout(() => { @@ -114,7 +114,7 @@ export class FilterBox extends React.Component { acc[i].classList.toggle("active"); var panel = acc[i].nextElementSibling as HTMLElement; panel.style.overflow = "hidden"; - panel.style.maxHeight = null; + panel.style.maxHeight = ""; } } }); |
