diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/ChatBox/MessageComponent.scss | 10 | ||||
| -rw-r--r-- | src/client/views/nodes/ChatBox/MessageComponent.tsx | 110 | ||||
| -rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 11 | ||||
| -rw-r--r-- | src/client/views/nodes/ComparisonBox.scss | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/ComparisonBox.tsx | 142 | ||||
| -rw-r--r-- | src/client/views/nodes/DataVizBox/components/TableBox.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 158 | ||||
| -rw-r--r-- | src/client/views/nodes/FontIconBox/FontIconBox.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/nodes/IconTagBox.scss | 30 | ||||
| -rw-r--r-- | src/client/views/nodes/IconTagBox.tsx | 168 | ||||
| -rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 5 | ||||
| -rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 8 | ||||
| -rw-r--r-- | src/client/views/nodes/WebBox.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 12 |
14 files changed, 429 insertions, 231 deletions
diff --git a/src/client/views/nodes/ChatBox/MessageComponent.scss b/src/client/views/nodes/ChatBox/MessageComponent.scss new file mode 100644 index 000000000..6fcc0e5e7 --- /dev/null +++ b/src/client/views/nodes/ChatBox/MessageComponent.scss @@ -0,0 +1,10 @@ +MessageComponent-citation { + color: lightblue; + vertical-align: super; + font-size: smaller; +} +MessageComponent-file_path { + color: lightblue; + vertical-align: baseline; + font-size: inherit; +} diff --git a/src/client/views/nodes/ChatBox/MessageComponent.tsx b/src/client/views/nodes/ChatBox/MessageComponent.tsx index fced0b4d5..f27a18891 100644 --- a/src/client/views/nodes/ChatBox/MessageComponent.tsx +++ b/src/client/views/nodes/ChatBox/MessageComponent.tsx @@ -1,11 +1,25 @@ +/* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable react/require-default-props */ -import React from 'react'; -import { observer } from 'mobx-react'; import { MathJax, MathJaxContext } from 'better-react-mathjax'; +import { observer } from 'mobx-react'; +import React from 'react'; +import * as Tb from 'react-icons/tb'; import ReactMarkdown from 'react-markdown'; -import { TbCircle0Filled, TbCircle1Filled, TbCircle2Filled, TbCircle3Filled, TbCircle4Filled, TbCircle5Filled, TbCircle6Filled, TbCircle7Filled, TbCircle8Filled, TbCircle9Filled } from 'react-icons/tb'; +import './MessageComponent.scss'; import { AssistantMessage } from './types'; +const TbCircles = [ + Tb.TbCircleNumber0Filled, + Tb.TbCircleNumber1Filled, + Tb.TbCircleNumber2Filled, + Tb.TbCircleNumber3Filled, + Tb.TbCircleNumber4Filled, + Tb.TbCircleNumber5Filled, + Tb.TbCircleNumber6Filled, + Tb.TbCircleNumber7Filled, + Tb.TbCircleNumber8Filled, + Tb.TbCircleNumber9Filled, +]; interface MessageComponentProps { message: AssistantMessage; toggleToolLogs: (index: number) => void; @@ -17,89 +31,41 @@ interface MessageComponentProps { isCurrent?: boolean; } -const MessageComponent: React.FC<MessageComponentProps> = function ({ message, toggleToolLogs, expandedLogIndex, goToLinkedDoc, index, showModal, setCurrentFile, isCurrent = false }) { - // const messageClass = `${message.role} ${isCurrent ? 'current-message' : ''}`; - - const LinkRenderer = ({ href, children }: { href: string; children: React.ReactNode }) => { - // console.log(href + " " + children) - const regex = /([a-zA-Z0-9_.!-]+)~~~(citation|file_path)/; - const matches = href.match(regex); - // console.log(href) - // console.log(matches) - const url = matches ? matches[1] : href; - const linkType = matches ? matches[2] : null; - if (linkType === 'citation') { - switch (children) { - case '0': - children = <TbCircle0Filled />; - break; - case '1': - children = <TbCircle1Filled />; - break; - case '2': - children = <TbCircle2Filled />; - break; - case '3': - children = <TbCircle3Filled />; - break; - case '4': - children = <TbCircle4Filled />; - break; - case '5': - children = <TbCircle5Filled />; - break; - case '6': - children = <TbCircle6Filled />; - break; - case '7': - children = <TbCircle7Filled />; - break; - case '8': - children = <TbCircle8Filled />; - break; - case '9': - children = <TbCircle9Filled />; - break; - default: - break; - } - } - // console.log(linkType) - const style = { - color: 'lightblue', - verticalAlign: linkType === 'citation' ? 'super' : 'baseline', - fontSize: linkType === 'citation' ? 'smaller' : 'inherit', - }; - - return ( - <a +const LinkRendererWrapper = (goToLinkedDoc: (url: string) => void, showModal: () => void, setCurrentFile: (file: { url: string }) => void) => + function LinkRenderer({ href, children }: { href?: string; children?: React.ReactNode }) { + const Children = TbCircles[Number(children)]; // pascal case variable needed to convert IconType to JSX.Element tag + const [, aurl, linkType] = href?.match(/([a-zA-Z0-9_.!-]+)~~~(citation|file_path)/) ?? [undefined, href, null]; + const renderType = (content: JSX.Element | null, click: (url: string) => void):JSX.Element => ( + // eslint-disable-next-line jsx-a11y/anchor-is-valid + <a className={`MessageComponent-${linkType}`} href="#" onClick={e => { e.preventDefault(); - if (linkType === 'citation') { - goToLinkedDoc(url); - } else if (linkType === 'file_path') { - showModal(); - setCurrentFile({ url }); - } - }} - style={style}> - {children} - </a> - ); + aurl && click(aurl); + }}> + {content} + </a> + ); // prettier-ignore + switch (linkType) { + case 'citation': return renderType(<Children />, (url: string) => goToLinkedDoc(url)); + case 'file_path': return renderType(null, (url: string) => { showModal(); setCurrentFile({ url }); }); + default: return null; + } // prettier-ignore }; +const MessageComponent: React.FC<MessageComponentProps> = function ({ message, toggleToolLogs, expandedLogIndex, goToLinkedDoc, index, showModal, setCurrentFile, isCurrent = false }) { + // const messageClass = `${message.role} ${isCurrent ? 'current-message' : ''}`; return ( <div className={`message ${message.role}`}> <MathJaxContext> <MathJax dynamic hideUntilTypeset="every"> - <ReactMarkdown components={{ a: LinkRenderer }}>{message.text ? message.text : ''}</ReactMarkdown> + <ReactMarkdown components={{ a: LinkRendererWrapper(goToLinkedDoc, showModal, setCurrentFile) }}>{message.text}</ReactMarkdown> </MathJax> </MathJaxContext> {message.image && <img src={message.image} alt="" />} <div className="message-footer"> {message.tool_logs && ( - <button className="toggle-logs-button" onClick={() => toggleToolLogs(index)}> + <button type="button" className="toggle-logs-button" onClick={() => toggleToolLogs(index)}> {expandedLogIndex === index ? 'Hide Code Interpreter Logs' : 'Show Code Interpreter Logs'} </button> )} diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 034a38e9c..ee67dd305 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -20,6 +20,11 @@ import { DocumentView, DocumentViewProps } from './DocumentView'; import { FieldViewProps } from './FieldView'; import { OpenWhere } from './OpenWhere'; +export enum GroupActive { // flags for whether a view is activate because of its relationship to a group + group = 'group', // this is a group that is activated because it's on an active canvas, but is not part of some other group + child = 'child', // this is a group child that is activated because its containing group is activated + inactive = 'inactive', // this is a group child but it is not active +} /// Ugh, typescript has no run-time way of iterating through the keys of an interface. so we need /// manaully keep this list of keys in synch wih the fields of the freeFormProps interface const freeFormPropsKeys = ['x', 'y', 'z', 'zIndex', 'rotation', 'opacity', 'backgroundColor', 'color', 'highlight', 'width', 'height', 'autoDim', 'transition']; @@ -274,7 +279,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF if (this._props.isAnyChildContentActive()) return undefined; const backColor = this.BackgroundColor; const isGroup = this.dataDoc.isGroup && (!backColor || backColor === 'transparent'); - return isGroup ? (this._props.isDocumentActive?.() ? 'group' : this._props.isGroupActive?.() ? 'child' : 'inactive') : this._props.isGroupActive?.() ? 'child' : undefined; + return isGroup ? (this._props.isDocumentActive?.() ? GroupActive.group : + this._props.isGroupActive?.() ? GroupActive.child : GroupActive.inactive) : + this._props.isGroupActive?.() ? GroupActive.child : undefined; // prettier-ignore }; localRotation = () => this._props.rotation; render() { @@ -313,6 +320,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF } } // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function gotoFrame(doc: any, newFrame: any) { +ScriptingGlobals.add(function gotoFrame(doc: Doc, newFrame: number) { CollectionFreeFormDocumentView.gotoKeyFrame(doc, newFrame); }); diff --git a/src/client/views/nodes/ComparisonBox.scss b/src/client/views/nodes/ComparisonBox.scss index 093b9c004..08d9e6010 100644 --- a/src/client/views/nodes/ComparisonBox.scss +++ b/src/client/views/nodes/ComparisonBox.scss @@ -49,7 +49,6 @@ left: 0; height: 100%; overflow: hidden; - transition: 200ms; .beforeBox-cont { height: 100%; @@ -63,7 +62,6 @@ width: 3px; display: inline-block; background: white; - transition: 200ms; .slide-handle { position: absolute; diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index adb380f12..efaf6807a 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -30,41 +30,23 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return FieldView.LayoutString(ComparisonBox, fieldKey); } private _disposers: (DragManager.DragDropDisposer | undefined)[] = [undefined, undefined]; + private _closeRef = React.createRef<HTMLDivElement>(); + @observable _inputValue = ''; + @observable _outputValue = ''; + @observable _loading = false; + @observable _errorMessage = ''; + @observable _outputMessage = ''; + @observable _animating = ''; + constructor(props: FieldViewProps) { super(props); makeObservable(this); } - @observable inputValue = ''; - @observable outputValue = ''; - @observable loading = false; - @observable errorMessage = ''; - @observable outputMessage = ''; - - @action handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { - this.inputValue = e.target.value; - console.log(this.inputValue); - }; - - @observable _animating = ''; - - @computed get clipWidth() { - return NumCast(this.layoutDoc[this.clipWidthKey], 50); - } - get clipWidthKey() { - return '_' + this._props.fieldKey + '_clipWidth'; - } - - @computed get clipHeight() { - return NumCast(this.layoutDoc[this.clipHeightKey], 200); - } - get clipHeightKey() { - return '_' + this._props.fieldKey + '_clipHeight'; - } - componentDidMount() { this._props.setContentViewBox?.(this); } + protected createDropTarget = (ele: HTMLDivElement | null, fieldKey: string, disposerId: number) => { this._disposers[disposerId]?.(); if (ele) { @@ -72,7 +54,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() } }; - private internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => { + @computed get revealOp() { return this.layoutDoc[`_${this.fieldKey}_revealOp`] as ('flip'|'hover'|undefined); } // prettier-ignore + @computed get clipWidth() { return NumCast(this.layoutDoc[`_${this.fieldKey}_clipWidth`], 50); } // prettier-ignore + set clipWidth(width: number) { this.layoutDoc[`_${this.fieldKey}_clipWidth`] = width; } // prettier-ignore + @computed get useAlternate() { return this.layoutDoc[`_${this.fieldKey}_usePath`] === 'alternate'; } // prettier-ignore + set useAlternate(alt: boolean) { this.layoutDoc[`_${this.fieldKey}_usePath`] = alt ? 'alternate' : undefined; } // prettier-ignore + + animateClipWidth = action((clipWidth: number, duration = 200 /* ms */) => { + this._animating = `all ${duration}ms`; // turn on clip animation transition, then turn it off at end of animation + setTimeout(action(() => { this._animating = ''; }), duration); // prettier-ignore + this.clipWidth = clipWidth; + }); + + internalDrop = undoable((e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => { if (dropEvent.complete.docDragData) { const { droppedDocuments } = dropEvent.complete.docDragData; const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocuments, this.Document, (doc: Doc | Doc[]) => this.addDoc(toList(doc).lastElement(), fieldKey)); @@ -84,45 +78,34 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return undefined; }, 'internal drop'); - private registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => { + registerSliding = (e: React.PointerEvent<HTMLDivElement>, targetWidth: number) => { if (e.button !== 2) { setupMoveUpEvents( this, e, this.onPointerMove, emptyFunction, - action((moveEv, doubleTap) => { + action((clickEv, doubleTap) => { if (doubleTap) { this._isAnyChildContentActive = true; if (!this.dataDoc[this.fieldKey + '_1'] && !this.dataDoc[this.fieldKey]) this.dataDoc[this.fieldKey + '_1'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); if (!this.dataDoc[this.fieldKey + '_2'] && !this.dataDoc[this.fieldKey + '_alternate']) this.dataDoc[this.fieldKey + '_2'] = DocUtils.copyDragFactory(Doc.UserDoc().emptyNote as Doc); + // DocumentView.addViewRenderedCb(DocCast(this.dataDoc[this.fieldKey + '_1']), dv => { + // dv?.select(false); + // }); } }), - false, + true, undefined, - action(() => { - if (this._isAnyChildContentActive) return; - this._animating = 'all 200ms'; - // on click, animate slider movement to the targetWidth - this.layoutDoc[this.clipWidthKey] = (targetWidth * 100) / this._props.PanelWidth(); - // this.layoutDoc[this.clipHeightKey] = (targetWidth * 100) / this._props.PanelHeight(); - - setTimeout( - action(() => { - this._animating = ''; - }), - 200 - ); - }) + () => !this._isAnyChildContentActive && this.animateClipWidth((targetWidth * 100) / this._props.PanelWidth()) ); } }; - @action - private onPointerMove = ({ movementX }: PointerEvent) => { + onPointerMove = ({ movementX }: PointerEvent) => { const width = movementX * this.ScreenToLocalBoxXf().Scale + (this.clipWidth / 100) * this._props.PanelWidth(); - if (width && width > 5 && width < this._props.PanelWidth()) { - this.layoutDoc[this.clipWidthKey] = (width * 100) / this._props.PanelWidth(); + if (width > 5 && width < this._props.PanelWidth()) { + this.clipWidth = (width * 100) / this._props.PanelWidth(); } return false; }; @@ -180,8 +163,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() ); }; docStyleProvider = (doc: Opt<Doc>, props: Opt<FieldViewProps>, property: string): any => { - if (property === StyleProp.PointerEvents) return 'none'; - return this._props.styleProvider?.(doc, props, property); + switch (property) { + case StyleProp.PointerEvents: return 'none'; + default: return this._props.styleProvider?.(doc, props, property); + } // prettier-ignore }; moveDoc1 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_1'), true); moveDoc2 = (docs: Doc | Doc[], targetCol: Doc | undefined, addDoc: any) => toList(docs).reduce((res, doc: Doc) => res && this.moveDoc(doc, addDoc, this.fieldKey + '_2'), true); @@ -220,36 +205,31 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() return layoutTemplateString; }; - _closeRef = React.createRef<HTMLDivElement>(); - /** * Flips a flashcard to the alternate side for the user to view. */ flipFlashcard = () => { - const usePath = this.layoutDoc[`_${this._props.fieldKey}_usePath`]; - this.layoutDoc[`_${this._props.fieldKey}_usePath`] = usePath === undefined ? 'alternate' : undefined; + this.useAlternate = !this.useAlternate; }; /** * Changes the view option to hover for a flashcard. */ - hoverFlip = (side: string | undefined) => { - if (this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'hover') this.layoutDoc[`_${this._props.fieldKey}_usePath`] = side; + hoverFlip = (alternate: boolean) => { + if (this.revealOp === 'hover') this.useAlternate = alternate; }; /** * Creates the button used to flip the flashcards. */ @computed get overlayAlternateIcon() { - const usepath = this.layoutDoc[`_${this._props.fieldKey}_usePath`]; return ( <Tooltip title={<div className="dash-tooltip">flip</div>}> <div className="formattedTextBox-alternateButton" onPointerDown={e => setupMoveUpEvents(e.target, e, returnFalse, emptyFunction, () => { - console.log(this.layoutDoc[`_${this._props.fieldKey}_revealOp`]); - if (!this.layoutDoc[`_${this._props.fieldKey}_revealOp`] || this.layoutDoc[`_${this._props.fieldKey}_revealOp`] === 'flip') { + if (!this.revealOp || this.revealOp === 'flip') { this.flipFlashcard(); console.log('Print Front of cards: ' + (RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text ?? '')); console.log('Print Back of cards: ' + (RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text ?? '')); @@ -257,8 +237,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() }) } style={{ - background: usepath === 'alternate' ? 'white' : 'black', - color: usepath === 'alternate' ? 'black' : 'white', + background: this.useAlternate ? 'white' : 'black', + color: this.useAlternate ? 'black' : 'white', }}> <FontAwesomeIcon icon="turn-up" size="sm" /> </div> @@ -268,14 +248,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() @action handleRenderGPTClick = () => { // Call the GPT model and get the output - this.layoutDoc[`_${this._props.fieldKey}_usePath`] = 'alternate'; - this.outputValue = ''; - if (this.inputValue) this.askGPT(); + this.useAlternate = true; + this._outputValue = ''; + if (this._inputValue) this.askGPT(); }; @action handleRenderClick = () => { // Call the GPT model and get the output - this.layoutDoc[`_${this._props.fieldKey}_usePath`] = undefined; + this.useAlternate = false; }; /** @@ -285,7 +265,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() askGPT = async (): Promise<string | undefined> => { const questionText = 'Question: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text); const rubricText = ' Rubric: ' + StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_0']).text)?.Text); - const queryText = questionText + ' UserAnswer: ' + this.inputValue + '. ' + rubricText; + const queryText = questionText + ' UserAnswer: ' + this._inputValue + '. ' + rubricText; try { const res = await gptAPICall(queryText, GPTCallType.QUIZ); @@ -293,8 +273,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() console.error('GPT call failed'); return; } - this.outputValue = res; - console.log(res); + this._outputValue = res; } catch (err) { console.error('GPT call failed'); } @@ -355,7 +334,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() ); if (this.Document._layout_isFlashcard) { - const side = this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 1 : 0; + const side = this.useAlternate ? 1 : 0; // add text box to each side when comparison box is first created if (!(this.dataDoc[this.fieldKey + '_0'] || this.dataDoc[this.fieldKey + '_0'] === 'empty')) { @@ -383,17 +362,19 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {/* {StrCast(RTFCast(DocCast(this.dataDoc[this.fieldKey + '_1']).text)?.Text)} */} <div className="input-box"> <textarea - value={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? this.outputValue : this.inputValue} - onChange={this.handleInputChange} - readOnly={this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate'} + value={this.useAlternate ? this._outputValue : this._inputValue} + onChange={action(e => { + this._inputValue = e.target.value; + })} + readOnly={this.useAlternate} /> </div> - <div className="submit-button" style={{ display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'none' : 'flex' }}> + <div className="submit-button" style={{ display: this.useAlternate ? 'none' : 'flex' }}> <button type="button" onClick={this.handleRenderGPTClick}> Submit </button> </div> - <div className="submit-button" style={{ display: this.layoutDoc[`_${this._props.fieldKey}_usePath`] === 'alternate' ? 'flex' : 'none' }}> + <div className="submit-button" style={{ display: this.useAlternate ? 'flex' : 'none' }}> <button type="button" onClick={this.handleRenderClick}> Edit Your Response </button> @@ -407,12 +388,8 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() <div className={`comparisonBox${this._props.isContentActive() ? '-interactive' : ''}`} /* change className to easily disable/enable pointer events in CSS */ style={{ display: 'flex', flexDirection: 'column' }} - onMouseEnter={() => { - this.hoverFlip('alternate'); - }} - onMouseLeave={() => { - this.hoverFlip(undefined); - }}> + onMouseEnter={() => this.hoverFlip(true)} + onMouseLeave={() => this.hoverFlip(false)}> {displayBox(`${this.fieldKey}_${side === 0 ? 1 : 0}`, side, this._props.PanelWidth() - 3)} {this.overlayAlternateIcon} </div> @@ -430,9 +407,10 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() className="slide-bar" style={{ left: `calc(${this.clipWidth + '%'} - 0.5px)`, + transition: this._animating, cursor: this.clipWidth < 5 ? 'e-resize' : this.clipWidth / 100 > (this._props.PanelWidth() - 5) / this._props.PanelWidth() ? 'w-resize' : undefined, }} - onPointerDown={e => !this._isAnyChildContentActive && this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ + onPointerDown={e => this.registerSliding(e, this._props.PanelWidth() / 2)} /* if clicked, return slide-bar to center */ > <div className="slide-handle" /> </div> diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx index a1deb1625..d2e82284e 100644 --- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx +++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx @@ -18,6 +18,7 @@ import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import './Chart.scss'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { DATA_VIZ_TABLE_ROW_HEIGHT } = require('../../../global/globalCssVariables.module.scss'); // prettier-ignore interface TableBoxProps { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 9ff96c692..f09e0c73d 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -43,6 +43,7 @@ import { ObserverJsxParser } from '../ObservableReactComponent'; import { PinProps } from '../PinFuncs'; import { StyleProp } from '../StyleProp'; import { ViewBoxInterface } from '../ViewBoxInterface'; +import { GroupActive } from './CollectionFreeFormDocumentView'; import { DocumentContentsView } from './DocumentContentsView'; import { DocumentLinksButton } from './DocumentLinksButton'; import './DocumentView.scss'; @@ -52,7 +53,7 @@ import { OpenWhere, OpenWhereMod } from './OpenWhere'; import { FormattedTextBox } from './formattedText/FormattedTextBox'; import { PresEffect, PresEffectDirection } from './trails/PresEnums'; import SpringAnimation from './trails/SlideEffect'; -import { SpringSettings, SpringType, springMappings } from './trails/SpringUtils'; +import { SpringType, springMappings } from './trails/SpringUtils'; interface Window { MediaRecorder: MediaRecorder; @@ -153,7 +154,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document @computed get disableClickScriptFunc() { const onScriptDisable = this._props.onClickScriptDisable ?? this._componentView?.onClickScriptDisable?.() ?? this.layoutDoc.onClickScriptDisable; - return (DocumentView.LongPress || + return (SnappingManager.LongPress || onScriptDisable === 'always' || (onScriptDisable !== 'never' && (this.rootSelected() || this._componentView?.isAnyChildContentActive?.()))); // prettier-ignore } @@ -297,17 +298,15 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document e.stopPropagation(); }; onClick = action((e: React.MouseEvent | React.PointerEvent) => { - if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; - const documentView = this._docView; - if (documentView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { + if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return; + if (this._docView && !this.Document.ignoreClick && this._props.renderDepth >= 0 && ClientUtils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) { let stopPropagate = true; let preventDefault = true; - !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document); const scriptProps = { this: this.Document, _readOnly_: false, scriptContext: this._props.scriptContext, - documentView, + documentView: this._docView, clientX: e.clientX, clientY: e.clientY, shiftKey: e.shiftKey, @@ -317,44 +316,39 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document }; if (this._doubleTap) { const defaultDblclick = this._props.defaultDoubleClick?.() || this.Document.defaultDoubleClick; - if (this.onDoubleClickHdlr?.script) { - UndoManager.RunInBatch(() => this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false), 'on double click: ' + this.Document.title); - } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') { - UndoManager.RunInBatch(() => this._props.addDocTab(this.Document, OpenWhere.lightboxAlways), 'double tap'); - DocumentView.DeselectAll(); - Doc.UnBrushDoc(this.Document); - } else { - this._singleClickFunc?.(); - } + undoable(() => { + if (this.onDoubleClickHdlr?.script) { + this.onDoubleClickHdlr.script.run(scriptProps, console.log).result?.select && this._props.select(false); + } else if (!Doc.IsSystem(this.Document) && defaultDblclick !== 'ignore') { + this._props.addDocTab(this.Document, OpenWhere.lightboxAlways); + DocumentView.DeselectAll(); + Doc.UnBrushDoc(this.Document); + } else this._singleClickFunc?.(); + }, 'on double click: ' + this.Document.title)(); this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout); this._doubleClickTimeout = undefined; this._singleClickFunc = undefined; } else { - let clickFunc: undefined | (() => any); - if (!this.disableClickScriptFunc && this.onClickHdlr?.script) { - clickFunc = undoable(() => { - this.onClickHdlr?.script.run(scriptProps, console.log).result?.select && this._props.select(false); - }, 'click ' + this.Document.title); - } else { - // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part - if (this.layoutDoc.onDragStart && !(e.ctrlKey || e.button > 0)) { - stopPropagate = false; - } - preventDefault = false; - } - const sendToBack = e.altKey ? () => documentView._props.bringToFront?.(this.Document, true) : undefined; + const sendToBack = e.altKey ? () => this._props.bringToFront?.(this.Document, true) : undefined; const selectFunc = () => { + !this.layoutDoc._keepZWhenDragged && this._props.bringToFront?.(this.Document); // selecting a view that is part of a template proxies the selection back to the root of the template const templateRoot = !(e.ctrlKey || e.button > 0) && this._props.docViewPath?.().reverse().find(dv => !dv._props.TemplateDataDocument); // prettier-ignore (templateRoot || this._docView)?.select(e.ctrlKey || e.shiftKey, e.metaKey); }; - this._singleClickFunc = clickFunc ?? sendToBack ?? selectFunc; - const waitFordblclick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; - if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') { + const clickFunc = this.onClickFunc?.()?.script ? () => (this.onClickFunc?.()?.script.run(scriptProps, console.log).result as Opt<{ select: boolean }>)?.select && this._props.select(false) : undefined; + if (!clickFunc) { + // onDragStart implies a button doc that we don't want to select when clicking. RootDocument & isTemplateForField implies we're clicking on part of a template instance and we want to select the whole template, not the part + if (this.layoutDoc.onDragStart && !(e.ctrlKey || e.button > 0)) stopPropagate = false; + preventDefault = false; + } + this._singleClickFunc = undoable(clickFunc ?? sendToBack ?? selectFunc, 'click: ' + this.Document.title); + const waitForDblClick = this._props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick; + if ((clickFunc && waitForDblClick !== 'never') || waitForDblClick === 'always') { this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout); this._doubleClickTimeout = setTimeout(this._singleClickFunc, 300); // eslint-disable-next-line no-use-before-define - } else if (!DocumentView.LongPress) { + } else if (!SnappingManager.LongPress) { this._singleClickFunc(); this._singleClickFunc = undefined; } @@ -365,9 +359,9 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document }); onPointerDown = (e: React.PointerEvent): void => { - if (this._props.isGroupActive?.() === 'child' && !this._props.isDocumentActive?.()) return; + if (this._props.isGroupActive?.() === GroupActive.child && !this._props.isDocumentActive?.()) return; // eslint-disable-next-line no-use-before-define - this._longPressSelector = setTimeout(() => DocumentView.LongPress && this._props.select(false), 1000); + this._longPressSelector = setTimeout(() => SnappingManager.LongPress && this._props.select(false), 1000); if (!DocumentView.DownDocView) DocumentView.DownDocView = this._docView; this._downX = e.clientX; @@ -418,7 +412,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document if (!this.isContentActive()) this._lastTap = Date.now(); // don't want to process the start of a double tap if the doucment is selected } // eslint-disable-next-line no-use-before-define - if (DocumentView.LongPress) e.preventDefault(); + if (SnappingManager.LongPress) e.preventDefault(); }; toggleFollowLink = undoable((): void => { @@ -975,8 +969,8 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document * @returns a function that will wrap a JSX animation element wrapping any JSX element */ public static AnimationEffect(renderDoc: JSX.Element, presEffectDoc: Opt<Doc>, root: Doc) { - let dir = (presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) as PresEffectDirection; - const transitionTime = presEffectDoc?.presentation_transition ? NumCast(presEffectDoc?.presentation_transition) : 500; + const dir = ((presEffectDoc?.presentation_effectDirection ?? presEffectDoc?.followLinkAnimDirection) || PresEffectDirection.Center) as PresEffectDirection; + const duration = Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)); const effectProps = { left: dir === PresEffectDirection.Left, right: dir === PresEffectDirection.Right, @@ -984,26 +978,14 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document bottom: dir === PresEffectDirection.Bottom, opposite: true, delay: 0, - duration: Cast(presEffectDoc?.presentation_transition, 'number', Cast(presEffectDoc?.followLinkTransitionTime, 'number', null)), + duration, }; const timing = StrCast(presEffectDoc?.presentation_effectTiming); - let timingConfig: SpringSettings | undefined; - if (timing) { - timingConfig = JSON.parse(timing); - } - - if (!timingConfig) { - timingConfig = { - type: SpringType.GENTLE, - ...springMappings.gentle, - }; - } - - if (!dir) { - dir = PresEffectDirection.Center; - } - + const timingConfig = (timing ? JSON.parse(timing) : undefined) ?? { + type: SpringType.GENTLE, + ...springMappings.gentle, + }; switch (StrCast(presEffectDoc?.presentation_effect, StrCast(presEffectDoc?.followLinkAnimEffect))) { case PresEffect.Expand: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Expand} springSettings={timingConfig}>{renderDoc}</SpringAnimation> case PresEffect.Flip: return <SpringAnimation doc={root} startOpacity={0} dir={dir} presEffect={PresEffect.Flip} springSettings={timingConfig}>{renderDoc}</SpringAnimation> @@ -1085,15 +1067,16 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done. ) => Promise<void>; public static linkCommonAncestor: (link: Doc) => DocumentView | undefined; - // pin func + /** + * Pins a Doc to the current presentation trail. (see TabDocView for implementation) + */ public static PinDoc: (docIn: Doc | Doc[], pinProps: PinProps) => void; - // gesture - public static DownDocView: DocumentView | undefined; // the first DocView that receives a pointerdown event. used by GestureOverlay to determine the doc a gesture should apply to. - // media playing - @observable public static CurrentlyPlaying: DocumentView[] = []; + /** + * The DocumentView below the cursor at the start of a gesture (that receives the pointerDown event). Used by GestureOverlay to determine the doc a gesture should apply to. + */ + public static DownDocView: DocumentView | undefined; public get displayName() { return 'DocumentView(' + (this.Document?.title??"") + ')'; } // prettier-ignore - public ContentRef = React.createRef<HTMLDivElement>(); private _htmlOverlayEffect: Opt<Doc>; private _disposers: { [name: string]: IReactionDisposer } = {}; private _viewTimer: NodeJS.Timeout | undefined; @@ -1124,7 +1107,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { @observable private _htmlOverlayText: Opt<string> = undefined; @observable private _isHovering = false; @observable private _selected = false; - @observable public static LongPress = false; + @observable public static CurrentlyPlaying: DocumentView[] = []; // audio or video media views that are currently playing @computed private get shouldNotScale() { return (this.layout_fitWidth && !this.nativeWidth) || this.ComponentView?.isUnstyledView?.(); @@ -1471,7 +1454,6 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { {!this.Document || !this._props.PanelWidth() ? null : ( <div className="contentFittingDocumentView-previewDoc" - ref={this.ContentRef} style={{ transform: `translate(${this.centeringX}px, ${this.centeringY}px)`, width: xshift ?? `${this._props.PanelWidth() - this.Xshift * 2}px`, @@ -1568,6 +1550,56 @@ export class DocumentView extends DocComponent<DocumentViewProps>() { } } +export function ActiveFillColor(): string { + const dv = DocumentView.Selected().lastElement() ?.Document._layout_isSvg ? DocumentView.Selected().lastElement() : undefined; + return StrCast(dv?.Document.fillColor, StrCast(ActiveInkPen()?.activeFillColor, "")); +} // prettier-ignore +export function ActiveInkPen(): Doc { return Doc.UserDoc(); } // prettier-ignore +export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, 'black'); } // prettier-ignore +export function ActiveIsInkMask(): boolean { return BoolCast(ActiveInkPen()?.activeIsInkMask, false); } // prettier-ignore +export function ActiveInkHideTextLabels(): boolean { return BoolCast(ActiveInkPen().activeInkHideTextLabels, false); } // prettier-ignore +export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, ''); } // prettier-ignore +export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, ''); } // prettier-ignore +export function ActiveArrowScale(): number { return NumCast(ActiveInkPen()?.activeArrowScale, 1); } // prettier-ignore +export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, '0'); } // prettier-ignore +export function ActiveInkWidth(): number { return Number(ActiveInkPen()?.activeInkWidth); } // prettier-ignore +export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); } // prettier-ignore +export function ActiveEraserWidth(): number { return Number(ActiveInkPen()?.eraserWidth); } // prettier-ignore + +export function SetActiveInkWidth(width: string): void { + !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width); +} +export function SetActiveBezierApprox(bezier: string): void { + ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? '' : bezier); +} +export function SetActiveInkColor(value: string) { + ActiveInkPen() && (ActiveInkPen().activeInkColor = value); +} +export function SetActiveIsInkMask(value: boolean) { + ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value); +} +export function SetActiveInkHideTextLabels(value: boolean) { + ActiveInkPen() && (ActiveInkPen().activeInkHideTextLabels = value); +} +export function SetActiveFillColor(value: string) { + ActiveInkPen() && (ActiveInkPen().activeFillColor = value); +} +export function SetActiveArrowStart(value: string) { + ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); +} +export function SetActiveArrowEnd(value: string) { + ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); +} +export function SetActiveArrowScale(value: number) { + ActiveInkPen() && (ActiveInkPen().activeArrowScale = value); +} +export function SetActiveDash(dash: string): void { + !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); +} +export function SetEraserWidth(width: number): void { + ActiveInkPen() && (ActiveInkPen().eraserWidth = width); +} + // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function DocFocusOrOpen(docIn: Doc, optionsIn?: FocusViewOptions, containingDoc?: Doc) { return DocumentView.FocusOrOpen(docIn, optionsIn, containingDoc); diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index ffb668b03..8317d62a6 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -192,7 +192,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { } else { text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result; // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); - getStyle = (val: string) => ({ fontFamily: val }); + // getStyle = (val: string) => ({ fontFamily: val }); } // Get items to place into the list diff --git a/src/client/views/nodes/IconTagBox.scss b/src/client/views/nodes/IconTagBox.scss new file mode 100644 index 000000000..8c0f92c90 --- /dev/null +++ b/src/client/views/nodes/IconTagBox.scss @@ -0,0 +1,30 @@ +@import '../global/globalCssVariables.module.scss'; + +.card-button-container { + display: flex; + padding: 3px; + position: absolute; + // width: 300px; + // height:100px; + pointer-events: none; /* This ensures the container does not capture hover events */ + + background-color: rgb(218, 218, 218); /* Background color of the container */ + border-radius: 50px; /* Rounds the corners of the container */ + transform: translateY(25px); + // box-shadow: 0 4px 8px rgba(0,0,0,0.1); /* Optional: Adds shadow for depth */ + align-items: center; /* Centers buttons vertically */ + justify-content: start; /* Centers buttons horizontally */ + + button { + pointer-events: auto; /* Re-enable pointer events for the buttons */ + transform: translateY(-7.5px); + + width: 30px; + height: 30px; + border-radius: 50%; + background-color: $dark-gray; + // border-color: $medium-blue; + margin: 5px; // transform: translateY(-50px); + background-color: transparent; + } +}
\ No newline at end of file diff --git a/src/client/views/nodes/IconTagBox.tsx b/src/client/views/nodes/IconTagBox.tsx new file mode 100644 index 000000000..9a2273c3a --- /dev/null +++ b/src/client/views/nodes/IconTagBox.tsx @@ -0,0 +1,168 @@ +import React from "react"; +import { observer } from "mobx-react"; +import { computed } from "mobx"; + +import { ObservableReactComponent } from "../ObservableReactComponent"; +import { NumCast } from "../../../fields/Types"; +import { makeObservable } from "mobx"; +import { Doc } from "../../../fields/Doc"; +import { Reaction } from "mobx"; +import { reaction } from "mobx"; +import { numberRange } from "../../../Utils"; +import { Tooltip } from "@mui/material"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { undoable } from "../../util/UndoManager"; +import { BoolCast } from "../../../fields/Types"; +import { DocCast } from "../../../fields/Types"; +import './IconTagBox.scss'; +import { AclAdmin, AclAugment, AclEdit, DocData } from '../../../fields/DocSymbols'; + + +export interface IconTagProps { + doc: Doc; + + +} + +@observer +export class IconTagBox extends ObservableReactComponent<IconTagProps> { + private ref: React.RefObject<HTMLDivElement>; + private height: number = 0; + + + @computed + get currentScale() { + return NumCast((this._props.doc.embedContainer as Doc)?._freeform_scale, 1); + } + + constructor(props: any) { + super(props); + makeObservable(this); + this.ref = React.createRef(); + } + + componentDidMount(): void { + this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; + this._props.doc._keywordHeight = this.height; + + reaction( + () => this.currentScale, + () => { + if (this.currentScale < 1) { + this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; + this._props.doc._keywordHeight = this.height; + } + } + ); + } + + componentDidUpdate(prevProps: Readonly<IconTagProps>): void { + this.height = this.ref.current?.getBoundingClientRect().height ? this.ref.current?.getBoundingClientRect().height : 0; + this._props.doc._keywordHeight = this.height; + } + + /** + * Renders the buttons to customize sorting depending on which group the card belongs to and the amount of total groups + * @param doc + * @param cardSort + * @returns + */ + renderButtons = (doc: Doc): JSX.Element | null => { + // if (cardSort !== cardSortings.Custom) return null; + + const amButtons = 4 + + // const amButtons = Math.max( + // 4, + // this.childDocs?.reduce((set, d) => { + // if (this.cardSort_customField) { + // set.add(NumCast(d[this.cardSort_customField])); + // } + // return set; + // }, new Set<number>()).size ?? 0 + // ); + + // const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc); + + const totalWidth = amButtons * 35 + amButtons * 2 * 5 + 6; + + const iconMap: { [key: number]: any } = { + 0: 'star', + 1: 'heart', + 2: 'cloud', + 3: 'bolt' + }; + + return ( + <div + className="card-button-container" + style={{ + transformOrigin: 'top left', + transform: `scale(${1 / this.currentScale}) translateY(${doc[DocData].showLabels ? doc._keywordHeight as number : 0}px)`, + width: `${totalWidth}px`, + fontSize: '50px' + }} + > + {numberRange(amButtons).map(i => ( + <Tooltip key={i} title={<div className="dash-tooltip">Click to add/remove this card from the {iconMap[i]} group</div>}> + <button key = {i} type="button" onClick={() => this.toggleButton(doc, iconMap[i] )}> + {this.getButtonIcon(doc, iconMap[i])} + </button> + </Tooltip> + ))} + </div> + ); + }; + + /** + * Toggles the buttons between on and off when creating custom sort groupings/changing those created by gpt + * @param childPairIndex + * @param buttonID + * @param doc + */ + toggleButton = undoable((doc: Doc, icon: string) => { + + + + // this.cardSort_customField && (doc[this.cardSort_customField] = buttonID); + + // doc.cardSort_activeIcons = new List<string>() + + + // const list = StrListCast(doc.cardSort_activeIcons); + // doc.cardSort_activeIcons = new List<string>(list.includes(icon) ? list.filter(d => d !== icon) : [...list, icon]); + + BoolCast(doc[icon]) ? doc[icon] = false : doc[icon] = true + + + + // StrListCast(doc.cardSort_activeIcons).push(iconMap[buttonID]) + }, 'toggle card tag'); + + + getButtonIcon = (doc: Doc, icon: any): JSX.Element => { + + // const isActive = StrListCast(doc.cardSort_activeIcons).includes(icon) + const isActive = doc[icon] + + // console.log(StrListCast(doc.cardSort_activeIcons)) + const color = isActive ? '#4476f7' : '#323232'; + + return <FontAwesomeIcon icon={icon} style={{ color , height: '30px', width: '30px'}} />; + }; + + render (){ + return ( + <> + {this.renderButtons(this._props.doc)} + + </> + ) + + } + + + +} + + diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 1c90fae9e..d940a96b9 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -454,6 +454,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }; focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); + renderedPixelDimensions = async () => { + const { nativeWidth: width, nativeHeight: height } = await Networking.PostToServer('/inspectImage', { source: this.paths[0] }); + return { width, height }; + }; + savedAnnotations = () => this._savedAnnotations; render() { TraceMobx(); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 7a89b143b..8db68ddfe 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -655,9 +655,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { ); else { if (!PDFBox.pdfpromise.get(href)) PDFBox.pdfpromise.set(href, Pdfjs.getDocument(href).promise); - PDFBox.pdfpromise.get(href)?.then((pdf: any) => { - PDFBox.pdfcache.set(href, (this._pdf = pdf)); - }); + PDFBox.pdfpromise.get(href)?.then( + action((pdf: any) => { + PDFBox.pdfcache.set(href, (this._pdf = pdf)); + }) + ); } } return pdfView ?? this.renderTitleBox; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 8835ea5e7..da947face 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -45,6 +45,7 @@ import { LinkInfo } from './LinkDocPreview'; import { OpenWhere } from './OpenWhere'; import './WebBox.scss'; +// eslint-disable-next-line @typescript-eslint/no-var-requires const { CreateImage } = require('./WebBoxRenderer'); @observer diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 9f2a9b8e1..5b435e44a 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -87,9 +87,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB public static LiveTextUndo: UndoManager.Batch | undefined; // undo batch when typing a new text note into a collection static _globalHighlightsCache: string = ''; static _globalHighlights = new ObservableSet<string>(['Audio Tags', 'Text from Others', 'Todo Items', 'Important Items', 'Disagree Items', 'Ignore Items']); - static _highlightStyleSheet: any = addStyleSheet(); - static _bulletStyleSheet: any = addStyleSheet(); - static _userStyleSheet: any = addStyleSheet(); + static _highlightStyleSheet = addStyleSheet(); + static _bulletStyleSheet = addStyleSheet(); + static _userStyleSheet = addStyleSheet(); static _hadSelection: boolean = false; private _selectionHTML: string | undefined; private _sidebarRef = React.createRef<SidebarAnnos>(); @@ -384,7 +384,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB } } } else { - const jsonstring = Cast(dataDoc[this.fieldKey], RichTextField)?.Data!; + const jsonstring = Cast(dataDoc[this.fieldKey], RichTextField)?.Data; if (jsonstring) { const json = JSON.parse(jsonstring); json.selection = state.toJSON().selection; @@ -1925,11 +1925,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB setHeight={this.setSidebarHeight} /> ) : ( - <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => DocumentView.SelectView(this.DocumentView?.()!, false), true)}> + <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => DocumentView.SelectView(this.DocumentView?.(), false), true)}> <ComponentTag // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} - ref={this._sidebarTagRef as any} + ref={this._sidebarTagRef} setContentView={emptyFunction} NativeWidth={returnZero} NativeHeight={returnZero} |
