aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoanne <zehan_ding@brown.edu>2025-06-24 10:15:04 -0400
committerJoanne <zehan_ding@brown.edu>2025-06-24 10:15:04 -0400
commitad1f2ffb01fef49449c2dd5875659e1c904558fd (patch)
tree3c586cc104b18b9bc183ebf875c970292aae06ca
parent17ec2a19b2d2dc5ba3f99c43d86c27946de2ac71 (diff)
parent1396850b90ed2dcca3776057ec4a7f2fc7ff297a (diff)
Merge branch 'master' of https://github.com/brown-dash/Dash-Web into joanne-tutorialagent
-rw-r--r--src/Utils.ts3
-rw-r--r--src/client/apis/gpt/GPT.ts50
-rw-r--r--src/client/util/CurrentUserUtils.ts4
-rw-r--r--src/client/views/DocumentDecorations.scss4
-rw-r--r--src/client/views/DocumentDecorations.tsx8
-rw-r--r--src/client/views/EditableView.tsx5
-rw-r--r--src/client/views/GestureOverlay.tsx4
-rw-r--r--src/client/views/InkTranscription.tsx182
-rw-r--r--src/client/views/InkingStroke.tsx2
-rw-r--r--src/client/views/LightboxView.tsx3
-rw-r--r--src/client/views/MainView.tsx36
-rw-r--r--src/client/views/UndoStack.tsx3
-rw-r--r--src/client/views/animationtimeline/Timeline.tsx3
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx3
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx10
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx12
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx3
-rw-r--r--src/client/views/collections/TreeView.tsx3
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx53
-rw-r--r--src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx3
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx39
-rw-r--r--src/client/views/collections/collectionLinear/CollectionLinearView.tsx5
-rw-r--r--src/client/views/collections/collectionSchema/CollectionSchemaView.tsx24
-rw-r--r--src/client/views/collections/collectionSchema/SchemaCellField.tsx4
-rw-r--r--src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx9
-rw-r--r--src/client/views/collections/collectionSchema/SchemaTableCell.tsx3
-rw-r--r--src/client/views/global/globalScripts.ts2
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx7
-rw-r--r--src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx3
-rw-r--r--src/client/views/nodes/DataVizBox/components/Histogram.tsx11
-rw-r--r--src/client/views/nodes/DataVizBox/components/LineChart.tsx11
-rw-r--r--src/client/views/nodes/DataVizBox/components/PieChart.tsx15
-rw-r--r--src/client/views/nodes/DiagramBox.tsx6
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx22
-rw-r--r--src/client/views/nodes/EquationBox.tsx3
-rw-r--r--src/client/views/nodes/FunctionPlotBox.tsx3
-rw-r--r--src/client/views/nodes/LabelBox.tsx38
-rw-r--r--src/client/views/nodes/LinkBox.tsx23
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx9
-rw-r--r--src/client/views/nodes/ScreenshotBox.tsx18
-rw-r--r--src/client/views/nodes/calendarBox/CalendarBox.tsx35
-rw-r--r--src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx8
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx8
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx51
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx30
-rw-r--r--src/fields/InkField.ts1
47 files changed, 402 insertions, 384 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index 724725c23..e96b8e231 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -202,6 +202,9 @@ export function aggregateBounds(boundsList: { x: number; y: number; width?: numb
export function intersectRect(r1: { left: number; top: number; width: number; height: number }, r2: { left: number; top: number; width: number; height: number }) {
return !(r2.left > r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top);
}
+export function rectContains(r1: { left: number; top: number; width: number; height: number }, r2: { left: number; top: number; width: number; height: number }) {
+ if (r1.left < r2.left && r1.left + r1.width > r2.left + r2.width && r1.top < r2.top && r1.top + r1.height > r2.top + r2.height) return true;
+}
export function stringHash(s?: string) {
return !s ? undefined : Math.abs(s.split('').reduce((a, b) => (n => n & n)((a << 5) - a + b.charCodeAt(0)), 0));
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 7878e9bfe..6258a82dc 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -11,10 +11,12 @@ export enum GPTDocCommand {
export const DescriptionSeperator = '======';
export const DocSeperator = '------';
+export const DataSeperator = '>>>>>>';
export enum TextClassifications {
- Title = 'word', //a few words
+ Title = 'word', //a few words
Caption = 'sentence', //few sentences
- LengthyDescription = 'paragraphs' }
+ LengthyDescription = 'paragraphs',
+}
enum GPTCallType {
SUMMARY = 'summary',
@@ -38,11 +40,12 @@ enum GPTCallType {
MAKERUBRIC = 'make_rubric', // create a definition rubric for a document to be used when quizzing the user
COMMANDTYPE = 'command_type', // Determine the type of command being made (GPTQueryType - eg., AssignTags, Sort, Filter, DocInfo, GenInfo) and possibly some parameters (eg, Tag type for Tags)
SUBSETDOCS = 'subset_docs', // select a subset of documents based on their descriptions
+ TAGDOCS = 'tag_docs', // choose a tags for each Doc
DOCINFO = 'doc_info', // provide information about a document
SORTDOCS = 'sort_docs',
CLASSIFYTEXTMINIMAL = 'classify_text_minimal', // classify text into one of the three categories: title, caption, lengthy description
CLASSIFYTEXTFULL = 'classify_text_full', //tags pdf content
- GENERATESCRAPBOOK = 'generate_scrapbook'
+ GENERATESCRAPBOOK = 'generate_scrapbook',
}
type GPTCallOpts = {
@@ -55,14 +58,12 @@ type GPTCallOpts = {
const callTypeMap: { [type in GPTCallType]: GPTCallOpts } = {
// newest model: gpt-4
summary: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: 'Summarize the text given in simpler terms.' },
-
-
+
sort_docs: {
model: 'gpt-4o',
maxTokens: 2048,
temp: 0.25,
- prompt:
- `The user is going to give you a list of descriptions.
+ prompt: `The user is going to give you a list of descriptions.
Each one is separated by '${DescriptionSeperator}' on either side.
Descriptions will vary in length, so make sure to only separate when you see '${DescriptionSeperator}'.
Sort them by the user's specifications.
@@ -71,7 +72,6 @@ const callTypeMap: { [type in GPTCallType]: GPTCallOpts } = {
It is VERY important that you format it exactly as described, ensuring the proper number of '${DescriptionSeperator[0]}' and '${DocSeperator[0]}' (${DescriptionSeperator.length} of each) and NO commas`,
},
-
edit: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: 'Reword the text.' },
stack: {
model: 'gpt-4o',
@@ -100,7 +100,7 @@ const callTypeMap: { [type in GPTCallType]: GPTCallOpts } = {
temp: 0.25,
prompt: `Based on the content of the the text, classify it into the
most appropriate category: '${TextClassifications.Title}' if it is a few words, '${TextClassifications.Caption}' if it is a couple sentences or less, or '${TextClassifications.LengthyDescription}' if it is a lengthy description. Output exclusively the classification in your response.
- `
+ `,
},
classify_text_full: {
model: 'gpt-4o',
@@ -109,7 +109,7 @@ const callTypeMap: { [type in GPTCallType]: GPTCallOpts } = {
prompt: `Based on the content of the the text, classify it into the
most appropriate category: '${TextClassifications.Title}', '${TextClassifications.Caption}', or '${TextClassifications.LengthyDescription}'.
Then provide five more descriptive tags (single words) separated by spaces.
- Finally, include a more detailed summary phrase tag using underscores, for a total of seven tags.`
+ Finally, include a more detailed summary phrase tag using underscores, for a total of seven tags.`,
},
describe: { model: 'gpt-4-vision-preview', maxTokens: 2048, temp: 0, prompt: 'Describe these images in 3-5 words' },
flashcard: {
@@ -174,7 +174,7 @@ const callTypeMap: { [type in GPTCallType]: GPTCallOpts } = {
model: 'gpt-4o',
maxTokens: 2048,
temp: 0.5,
- prompt: `Generate an aesthetically pleasing scrapbook layout preset based on these items.
+ prompt: `Generate an aesthetically pleasing scrapbook layout preset based on these items.
Return your response as JSON in the format:
[{
"type": rich text or image or pdf or video or collection
@@ -191,22 +191,32 @@ const callTypeMap: { [type in GPTCallType]: GPTCallOpts } = {
tag:
x: , y: , width: , height:
}
- ] `
-
- },
+ ] `,
+ },
command_type: {
model: 'gpt-4-turbo',
maxTokens: 1024,
temp: 0,
- prompt: `I'm going to provide you with a question.
- Based on the question, is the user asking you to
- ${GPTDocCommand.AssignTags}. Assigns docs with tags(like star / heart etc)/labels.
+ prompt: `Is the provided command/question asking you to:
+ ${GPTDocCommand.AssignTags}. Choose a descriptive tag/label.
${GPTDocCommand.GetInfo}. Provide information about a specific doc.
${GPTDocCommand.Filter}. Filter docs based on a question/information.
${GPTDocCommand.Sort}. Put docs in a specific order.
- Answer with only the number for ${GPTDocCommand.GetInfo}-${GPTDocCommand.Sort}.
- For number one, provide the number (${GPTDocCommand.AssignTags}) and the appropriate tag`,
+ Answer with only the number, do not add any other punctuation or formatting of any kind`,
+ },
+ tag_docs: {
+ model: 'gpt-4-turbo',
+ maxTokens: 1024,
+ temp: 0,
+ prompt: `I'm going to give you a list of descriptions.
+ Each one is separated by '${DescriptionSeperator}' on either side.
+ Descriptions will vary in length, so make sure to only separate when you see '${DescriptionSeperator}'.
+ Based on the question/command the user asks, provide a tag label of the given descriptions that best matches the user's specifications.
+ Format your response precisely as a single string that prints each description without including any '${DescriptionSeperator}', followed by '${DataSeperator}', followed by the tag label, followed by '${DescriptionSeperator}'.
+ Do not use any additional formatting marks or punctuation'.
+ Immediately afterward, surrounded by '${DocSeperator}' on BOTH SIDES, provide some insight into your reasoning for the way you sorted (and mention nothing about the formatting details given in this description).
+ `,
},
subset_docs: {
model: 'gpt-4-turbo',
@@ -284,7 +294,7 @@ const gptImageCall = async (prompt: string, n?: number) => {
n: n ?? 1,
size: '1024x1024',
});
- return response.data.map((data: Image) => data.url);
+ return (response.data ?? []).map((data: Image) => data.url);
// return response.data.data[0].url;
} catch (err) {
console.error(err);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 130a4d013..cf1c98b88 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -798,6 +798,7 @@ pie title Minerals in my tap water
{ title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen-nib", toolType: InkInkTool.Pen, ignoreClick: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' }},
{ title: "Highlight",toolTip: "Highlight (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", toolType: InkInkTool.Highlight, ignoreClick: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' }},
{ title: "Write", toolTip: "Write (Ctrl+Shift+P)", btnType: ButtonType.ToggleButton, icon: "pen", toolType: InkInkTool.Write, ignoreClick: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }},
+ { title: "Math", toolTip: "Math", btnType: ButtonType.ToggleButton, icon: "calculator", toolType: InkInkTool.Math, ignoreClick: true, scripts: {onClick:'{ return setActiveTool(this.toolType, true, _readOnly_);}' }, funcs: {hidden:"IsNoviceMode()" }},
]},
{ title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberSliderButton, toolType: InkProperty.StrokeWidth,ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"!activeInkTool()"}, numBtnMin: 1, linearView_btnWidth:40},
{ title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", toolType: InkProperty.StrokeColor,ignoreClick: true, scripts: {script: '{ return setInkProperty(this.toolType, value, _readOnly_);}'}, funcs: {hidden:"!activeInkTool()"}},
@@ -1034,6 +1035,9 @@ pie title Minerals in my tap water
doc[`active${InkInkTool.Write}Color`] ?? (doc[`active${InkInkTool.Write}Color`] = "rgb(255, 0, 0)");
doc[`active${InkInkTool.Write}Width`] ?? (doc[`active${InkInkTool.Write}Width`] = 1);
doc[`active${InkInkTool.Write}Bezier`] ?? (doc[`active${InkInkTool.Write}Bezier`] = "0");
+ doc[`active${InkInkTool.Math}Color`] ?? (doc[`active${InkInkTool.Math}Color`] = "rgb(0, 0, 255)");
+ doc[`active${InkInkTool.Math}Width`] ?? (doc[`active${InkInkTool.Math}Width`] = 1);
+ doc[`active${InkInkTool.Math}Bezier`] ?? (doc[`active${InkInkTool.Math}Bezier`] = "0");
doc[`active${InkInkTool.Highlight}Color`] ?? (doc[`active${InkInkTool.Highlight}Color`] = 'transparent');
doc[`active${InkInkTool.Highlight}Width`] ?? (doc[`active${InkInkTool.Highlight}Width`] = 20);
doc[`active${InkInkTool.Highlight}Bezier`] ?? (doc[`active${InkInkTool.Highlight}Bezier`] = "0");
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 25a806abd..d79826b3c 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -13,8 +13,8 @@ $resizeHandler: 8px;
border-radius: 100%;
height: 30px;
width: 30px;
- right: -40;
- bottom: -20;
+ right: -40px;
+ bottom: -20px;
//top: calc(50% - 15px);
position: absolute;
pointer-events: all;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 7a9f6c514..2b7050cf0 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -906,11 +906,9 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
<div
style={{
position: 'absolute',
- transform: `rotate(${rotation}deg)`,
- width: this.Bounds.r - this.Bounds.x + 'px',
- height: this.Bounds.b - this.Bounds.y + 'px',
- left: this.Bounds.r,
- top: this.Bounds.b,
+ transform: `translate(${bounds.x - this._resizeBorderWidth}px, ${bounds.y - this._resizeBorderWidth}px) rotate(${rotation}deg)`,
+ width: bounds.r - bounds.x + 2 * this._resizeBorderWidth + 'px',
+ height: bounds.b - bounds.y + 2 * this._resizeBorderWidth + 'px',
pointerEvents: 'none',
}}>
{this._isRotating ? null : (
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index d9447b7ec..deeabaa28 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -236,6 +236,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
return this._editing;
};
+ setInputRef = (r: HTMLInputElement | HTMLTextAreaElement | null) => (this._inputref = r);
renderEditor() {
return this._props.autosuggestProps ? (
<Autosuggest
@@ -255,7 +256,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
) : this._props.oneLine !== false && this._props.GetValue()?.toString().indexOf('\n') === -1 ? (
<input
className="editableView-input"
- ref={r => { this._inputref = r; }} // prettier-ignore
+ ref={this.setInputRef}
style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minWidth: 20, background: this._props.background }}
placeholder={this._props.placeholder}
onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
@@ -270,7 +271,7 @@ export class EditableView extends ObservableReactComponent<EditableProps> {
) : (
<textarea
className="editableView-input"
- ref={r => { this._inputref = r; }} // prettier-ignore
+ ref={this.setInputRef}
style={{ display: this._props.display, overflow: 'auto', fontSize: this._props.fontSize, minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20, background: this._props.background }}
placeholder={this._props.placeholder}
onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 777a34ebc..8488c5293 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -3,7 +3,7 @@ import { action, computed, makeObservable, observable, runInAction } from 'mobx'
import { observer } from 'mobx-react';
import * as React from 'react';
import { setupMoveUpEvents } from '../../ClientUtils';
-import { emptyFunction, intersectRect } from '../../Utils';
+import { emptyFunction, intersectRect, rectContains } from '../../Utils';
import { Doc } from '../../fields/Doc';
import { InkData, InkField, InkTool } from '../../fields/InkField';
import { NumCast } from '../../fields/Types';
@@ -166,7 +166,7 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
*/
docsInBoundingBox = (boundingBox: { topLeft: number[]; bottomRight: number[] }, childDocs: Doc[]): Doc[] => {
const rect = { left: boundingBox.topLeft[0], top: boundingBox.topLeft[1], width: boundingBox.bottomRight[0] - boundingBox.topLeft[0], height: boundingBox.bottomRight[1] - boundingBox.topLeft[1] };
- return childDocs.filter(doc => intersectRect(rect, { left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }));
+ return childDocs.filter(doc => rectContains(rect, { left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }));
};
/**
* Determines if what the array of cusp/intersection data corresponds to a scribble.
diff --git a/src/client/views/InkTranscription.tsx b/src/client/views/InkTranscription.tsx
index 6220033d4..32ca5f56b 100644
--- a/src/client/views/InkTranscription.tsx
+++ b/src/client/views/InkTranscription.tsx
@@ -32,7 +32,7 @@ export class InkTranscription extends React.Component {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@observable _iinkEditor: any = undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- private lastJiix: any;
+ @observable _iinkMathEditor: any = undefined;
private currGroup?: Doc;
private collectionFreeForm?: CollectionFreeFormView;
@@ -44,7 +44,7 @@ export class InkTranscription extends React.Component {
@action
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setMathRef = async (r: any) => {
- if (!this._textRegister && r) {
+ if (!this._mathRegister && r) {
const options = {
configuration: {
server: {
@@ -55,19 +55,17 @@ export class InkTranscription extends React.Component {
protocol: 'WEBSOCKET',
},
recognition: {
- type: 'TEXT',
- lang: 'en_US',
- text: {
- mimeTypes: ['application/vnd.myscript.jiix'] as 'application/vnd.myscript.jiix'[],
+ type: 'MATH',
+ math: {
+ mimeTypes: ['application/x-latex'] as unknown as 'application/vnd.myscript.jiix'[],
},
},
},
};
- await iink.Editor.load(r, 'INKV2', options);
-
- this._textRegister = r;
+ this._iinkMathEditor = await iink.Editor.load(r, 'INKV2', options);
+ this._mathRegister = r;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- r?.addEventListener('exported', (e: any) => this.exportInk(e, this._textRef));
+ r?.addEventListener('exported', (e: any) => this.exportInk(e));
return (this._textRef = r);
}
@@ -97,12 +95,14 @@ export class InkTranscription extends React.Component {
this._iinkEditor = await iink.Editor.load(r, 'INKV2', options);
this._textRegister = r;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- r?.addEventListener('exported', (e: any) => this.exportInk(e, this._textRef));
+ r?.addEventListener('exported', (e: any) => this.exportInk(e));
return (this._textRef = r);
}
};
+ _ffview: CollectionFreeFormView | undefined;
+
/**
* Handles processing Dash Doc data for ink transcription.
*
@@ -110,7 +110,7 @@ export class InkTranscription extends React.Component {
* @param inkDocs the ink docs contained within the selected group
* @param math boolean whether to do math transcription or not
*/
- transcribeInk = (groupDoc: Doc | undefined, inkDocs: Doc[], math: boolean) => {
+ transcribeInk = (ffview: CollectionFreeFormView, groupDoc: Doc | undefined, inkDocs: Doc[], math: boolean) => {
if (!groupDoc) return;
const validInks = inkDocs.filter(s => s.type === DocumentType.INK);
@@ -126,13 +126,10 @@ export class InkTranscription extends React.Component {
strokes.push(d.inkData.map(pd => inkStroke.ptToScreen({ X: pd.X, Y: pd.Y })));
times.push(authorTime);
});
+ this._ffview = ffview;
this.currGroup = groupDoc;
const pointerData = strokes.map((stroke, i) => this.inkJSON(stroke, times[i]));
- if (math) {
- this._iinkEditor.importPointEvents(pointerData);
- } else {
- this._iinkEditor.importPointEvents(pointerData);
- }
+ (math ? this._iinkMathEditor : this._iinkEditor).importPointEvents(pointerData);
};
convertPointsToString(points: InkData[]): string {
return points[0].map(point => `new Point(${point.X}, ${point.Y})`).join(',');
@@ -204,83 +201,92 @@ export class InkTranscription extends React.Component {
* @param ref the ref to the editor
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- exportInk = async (e: any, ref: any) => {
- const exports = e.detail['application/vnd.myscript.jiix'];
- if (exports) {
- if (exports['type'] == 'Math') {
- const latex = exports['application/x-latex'];
- if (this.currGroup) {
- this.currGroup.text = latex;
- this.currGroup.title = latex;
- }
+ exportInk = (e: { detail: { [key: string]: string } }) => {
+ const exports = e.detail;
+ if (exports['application/x-latex']) {
+ const latex = exports['application/x-latex'];
+ if (this.currGroup) {
+ this.currGroup.text = latex;
+ this.currGroup.title = latex;
+ }
- ref.editor.clear();
- } else if (exports['type'] == 'Text') {
- if (exports['application/vnd.myscript.jiix']) {
- this.lastJiix = JSON.parse(exports['application/vnd.myscript.jiix']);
- // map timestamp to strokes
- const timestampWord = new Map<number, string>();
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- this.lastJiix.words.map((word: any) => {
- if (word.items) {
- word.items.forEach((i: { id: string; timestamp: string; X: Array<number>; Y: Array<number>; F: Array<number> }) => {
- const ms = Date.parse(i.timestamp);
- timestampWord.set(ms, word.label);
- });
- }
+ this._ffview?.addDocument(
+ Docs.Create.EquationDocument(latex, {
+ title: '',
+ x: this.currGroup?.x as number,
+ y: (this.currGroup?.y as number) + (this.currGroup?.height as number),
+ nativeHeight: 40,
+ _height: 50,
+ nativeWidth: 40,
+ _width: 50,
+ })
+ );
+ // this.showRecogBox(latex as string);
+ this._iinkMathEditor.clear();
+ } else if (exports['application/vnd.myscript.jiix']) {
+ const lastJiix = exports['application/vnd.myscript.jiix'] as unknown as { words: string[]; label: string };
+ // map timestamp to strokes
+ const timestampWord = new Map<number, string>();
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ lastJiix.words.map((word: any) => {
+ if (word.items) {
+ word.items.forEach((i: { id: string; timestamp: string; X: Array<number>; Y: Array<number>; F: Array<number> }) => {
+ const ms = Date.parse(i.timestamp);
+ timestampWord.set(ms, word.label);
});
-
- const wordInkDocMap = new Map<string, Doc[]>();
- if (this.currGroup) {
- const docList = DocListCast(this.currGroup.data);
- docList.forEach((inkDoc: Doc) => {
- // just having the times match up and be a unique value (actual timestamp doesn't matter)
- const ms = (DateCast(inkDoc.author_date)?.getDate().getTime() ?? 0) + 14400000;
- const word = timestampWord.get(ms);
- if (!word) {
- return;
- }
- const entry = wordInkDocMap.get(word);
- if (entry) {
- entry.push(inkDoc);
- wordInkDocMap.set(word, entry);
- } else {
- const newEntry = [inkDoc];
- wordInkDocMap.set(word, newEntry);
- }
- });
- if (this.lastJiix.words.length > 1) this.subgroupsTranscriptions(wordInkDocMap);
- }
}
- const text = exports['label'];
+ });
- if (this.currGroup && text) {
- DocumentView.getDocumentView(this.currGroup)?.ComponentView?.updateIcon?.();
- const image = await this.getIcon();
- const { href } = (image as URLField).url;
- const hrefParts = href.split('.');
- const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`;
- let response;
- try {
- const hrefBase64 = await imageUrlToBase64(hrefComplete);
- response = await gptHandwriting(hrefBase64);
- } catch {
- console.error('Error getting image');
- }
- const textBoxText = 'iink: ' + text + '\n' + '\n' + 'ChatGPT: ' + response;
- this.currGroup.transcription = response;
- this.currGroup.title = response;
- if (!this.currGroup.hasTextBox) {
- const newDoc = Docs.Create.TextDocument(textBoxText, { title: '', x: this.currGroup.x as number, y: (this.currGroup.y as number) + (this.currGroup.height as number) });
- newDoc.height = 200;
- this.collectionFreeForm?.addDocument(newDoc);
- this.currGroup.hasTextBox = true;
+ const wordInkDocMap = new Map<string, Doc[]>();
+ if (this.currGroup) {
+ DocListCast(this.currGroup.data).forEach((inkDoc: Doc) => {
+ // just having the times match up and be a unique value (actual timestamp doesn't matter)
+ const ms = (DateCast(inkDoc.author_date)?.getDate().getTime() ?? 0) + 14400000;
+ const word = timestampWord.get(ms);
+ if (word) {
+ const entry = wordInkDocMap.get(word);
+ if (entry) {
+ entry.push(inkDoc);
+ wordInkDocMap.set(word, entry);
+ } else {
+ const newEntry = [inkDoc];
+ wordInkDocMap.set(word, newEntry);
+ }
}
- ref.editor.clear();
- }
+ });
+ if (lastJiix.words.length > 1) this.subgroupsTranscriptions(wordInkDocMap);
}
+ this.showRecogBox(lastJiix.label);
+ this._iinkEditor.clear();
}
};
+ private showRecogBox(text: string) {
+ if (this.currGroup) {
+ let response;
+ // DocumentView.getDocumentView(this.currGroup)?.ComponentView?.updateIcon?.();
+ // const image = await this.getIcon();
+ // const { href } = (image as URLField).url;
+ // const hrefParts = href.split('.');
+ // const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`;
+ // try {
+ // const hrefBase64 = await imageUrlToBase64(hrefComplete);
+ // response = await gptHandwriting(hrefBase64);
+ // } catch {
+ // console.error('Error getting image');
+ // }
+ const textBoxText = 'iink: ' + text + '\n' + '\n' + 'ChatGPT: ' + response;
+
+ this.currGroup.transcription = response;
+ this.currGroup.title = response;
+ if (!this.currGroup.hasTextBox) {
+ const newDoc = Docs.Create.TextDocument(textBoxText, { title: '', x: this.currGroup.x as number, y: (this.currGroup.y as number) + (this.currGroup.height as number) });
+ newDoc.height = 200;
+ this.collectionFreeForm?.addDocument(newDoc);
+ this.currGroup.hasTextBox = true;
+ }
+ }
+ }
+
/**
* gets the icon of the collection that was just made
* @returns the image of the collection
@@ -299,7 +305,7 @@ export class InkTranscription extends React.Component {
*/
createInkGroup() {
// TODO nda - if document being added to is a inkGrouping then we can just add to that group
- if (Doc.ActiveTool === InkTool.Ink && Doc.ActiveInk === InkInkTool.Write) {
+ if (Doc.ActiveTool === InkTool.Ink && [InkInkTool.Write, InkInkTool.Math].includes(Doc.ActiveInk)) {
CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => {
// TODO: nda - will probably want to go through ffView unprocessed docs and then see if any of the inksToGroup docs are in it and only use those
const selected = ffView.unprocessedDocs;
@@ -309,7 +315,7 @@ export class InkTranscription extends React.Component {
);
ffView.unprocessedDocs = [];
- InkTranscription.Instance.transcribeInk(newCollection, selected, false);
+ InkTranscription.Instance.transcribeInk(ffView, newCollection, selected, Doc.ActiveInk === InkInkTool.Math);
});
}
CollectionFreeFormView.collectionsWithUnprocessedInk.clear();
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 253db08de..4b651af7d 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -124,7 +124,7 @@ export class InkingStroke extends ViewBoxAnnotatableComponent<FieldViewProps>()
);
ffView.unprocessedDocs = [];
- InkTranscription.Instance.transcribeInk(newCollection, selected, false);
+ InkTranscription.Instance.transcribeInk(ffView, newCollection, selected, false);
}
};
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 0eb21b943..62b1180ec 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -244,6 +244,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
</div>
</div>
);
+ setStickerRef = (r: StickerPalette | null) => (this._annoPaletteView = r);
render() {
let downx = 0;
let downy = 0;
@@ -317,7 +318,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
</GestureOverlay>
</div>
- {this._showPalette && <StickerPalette ref={r => (this._annoPaletteView = r)} Doc={DocCast(Doc.UserDoc().myLightboxDrawings)} />}
+ {this._showPalette && DocCast(Doc.UserDoc().myLightboxDrawings) && <StickerPalette ref={this.setStickerRef} Doc={DocCast(Doc.UserDoc().myLightboxDrawings)!} />}
{this.renderNavBtn(0, undefined, this._props.PanelHeight / 2 - 12.5, 'chevron-left', this._doc && this._history.length ? true : false, this.previous)}
{this.renderNavBtn(
this._props.PanelWidth - Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]),
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 13b14617c..867a5a304 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -921,19 +921,19 @@ export class MainView extends ObservableReactComponent<object> {
);
}
+ setMainDashRef = (r: HTMLDivElement | null) =>
+ r &&
+ new ResizeObserver(
+ action(() => {
+ this._dashUIWidth = r.getBoundingClientRect().width;
+ this._dashUIHeight = r.getBoundingClientRect().height;
+ })
+ ).observe(r);
@computed get mainDashboardArea() {
return !this.userDoc ? null : (
<div
className="mainView-dashboardArea"
- ref={r => {
- r &&
- new ResizeObserver(
- action(() => {
- this._dashUIWidth = r.getBoundingClientRect().width;
- this._dashUIHeight = r.getBoundingClientRect().height;
- })
- ).observe(r);
- }}
+ ref={this.setMainDashRef}
style={{
color: 'black',
height: `calc(100% - ${this.topOfDashUI + this.topMenuHeight()}px)`,
@@ -1072,6 +1072,14 @@ export class MainView extends ObservableReactComponent<object> {
};
lightboxMaxBorder = [200, 50];
+ setMainViewRef = (r: HTMLDivElement | null) =>
+ r &&
+ new ResizeObserver(
+ action(() => {
+ this._windowWidth = r.getBoundingClientRect().width;
+ this._windowHeight = r.getBoundingClientRect().height;
+ })
+ ).observe(r);
render() {
return (
<div
@@ -1085,15 +1093,7 @@ export class MainView extends ObservableReactComponent<object> {
ele.scrollTop = ele.scrollLeft = 0;
})(document.getElementById('root')!)
}
- ref={r => {
- r &&
- new ResizeObserver(
- action(() => {
- this._windowWidth = r.getBoundingClientRect().width;
- this._windowHeight = r.getBoundingClientRect().height;
- })
- ).observe(r);
- }}>
+ ref={this.setMainViewRef}>
{this.inkResources}
<DictationOverlay />
<SharingManager />
diff --git a/src/client/views/UndoStack.tsx b/src/client/views/UndoStack.tsx
index 067020a62..3755b1ec1 100644
--- a/src/client/views/UndoStack.tsx
+++ b/src/client/views/UndoStack.tsx
@@ -9,6 +9,7 @@ import './UndoStack.scss';
@observer
export class UndoStack extends React.Component<object> {
+ setRef = (r: HTMLDivElement | null) => r?.scroll({ behavior: 'auto', top: (r?.scrollHeight ?? 0) + 20 });
render() {
const background = UndoManager.batchCounter.get() ? 'yellow' : SettingsManager.userVariantColor;
const color = UndoManager.batchCounter.get() ? 'black' : SettingsManager.userColor;
@@ -25,7 +26,7 @@ export class UndoStack extends React.Component<object> {
popup={
<div
className="undoStack-commandsContainer"
- ref={r => r?.scroll({ behavior: 'auto', top: (r?.scrollHeight ?? 0) + 20 })}
+ ref={this.setRef}
style={{
background,
color,
diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx
index 814e9a7a0..c2bd01334 100644
--- a/src/client/views/animationtimeline/Timeline.tsx
+++ b/src/client/views/animationtimeline/Timeline.tsx
@@ -533,6 +533,7 @@ export class Timeline extends ObservableReactComponent<FieldViewProps & { Doc: D
this._totalLength = RegionHelpers.convertPixelTime(this._time, 'mili', 'pixel', this._tickSpacing, this._tickIncrement);
};
+ setTrackRef = (r: Track) => this.mapOfTracks.push(r);
/**
* if you have any question here, just shoot me an email or text.
* basically the only thing you need to edit besides render methods in track (individual track lines) and keyframe (green region)
@@ -554,7 +555,7 @@ export class Timeline extends ObservableReactComponent<FieldViewProps & { Doc: D
{[...this.children, this._props.Doc].map(doc => (
<Track
key={doc[Id]}
- ref={ref => this.mapOfTracks.push(ref)}
+ ref={this.setTrackRef}
timeline={this}
animatedDoc={doc}
currentBarX={this._currentBarX}
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 7f639a11e..7a4408931 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -256,9 +256,10 @@ export class CollectionNoteTakingView extends CollectionSubView() {
const height = () => this.getDocHeight(doc);
let dref: Opt<DocumentView>;
const noteTakingDocTransform = () => this.getDocTransform(doc, dref);
+ const setRef = (r: DocumentView | null) => (dref = r || undefined);
return (
<DocumentView
- ref={r => (dref = r || undefined)}
+ ref={setRef}
Document={doc}
TemplateDataDocument={doc.isTemplateDoc || doc.isTemplateForField ? this._props.TemplateDataDocument : undefined}
pointerEvents={this.blockPointerEventsWhenDragging}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index bdeb7d944..fbdd23315 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import * as CSS from 'csstype';
-import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ClientUtils, DivHeight, returnNone, returnZero, setupMoveUpEvents, smoothScroll } from '../../../ClientUtils';
@@ -391,10 +391,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
});
// This following three functions must be from the view Mehek showed
- columnDividerDown = (e: React.PointerEvent) => {
- runInAction(() => {
- this._cursor = 'grabbing';
- });
+ columnDividerDown = action((e: React.PointerEvent) => {
+ this._cursor = 'grabbing';
const batch = UndoManager.StartBatch('stacking width');
setupMoveUpEvents(
this,
@@ -406,7 +404,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
}),
emptyFunction
);
- };
+ });
@action
onDividerMove = (e: PointerEvent) => {
this.Document._layout_columnWidth = Math.max(10, (this._props.DocumentView?.().screenToViewTransform().transformPoint(e.clientX, 0)[0] ?? 0) - this.xMargin);
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 8c535534a..b5efa7a72 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -304,6 +304,12 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
ContextMenu.Instance.displayMenu(pt[0], pt[1], undefined, true);
};
+ setRef = (r: HTMLDivElement | null) => {
+ if (this._headerRef && this._props.colHeaderRefs.includes(this._headerRef)) this._props.colHeaderRefs.splice(this._props.colStackRefs.indexOf(this._headerRef), 1);
+ r && this._props.colHeaderRefs.push(r);
+ this._headerRef = r;
+ };
+
@computed get innards() {
TraceMobx();
const key = this._props.pivotField;
@@ -315,11 +321,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
<div
key={heading}
className="collectionStackingView-sectionHeader"
- ref={r => {
- if (this._headerRef && this._props.colHeaderRefs.includes(this._headerRef)) this._props.colHeaderRefs.splice(this._props.colStackRefs.indexOf(this._headerRef), 1);
- r && this._props.colHeaderRefs.push(r);
- this._headerRef = r;
- }}
+ ref={this.setRef}
style={{
marginTop: 0,
marginBottom: this._props.gridGap,
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index bee5d016d..4625965b4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -407,6 +407,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
remAnnotationDocument = (doc: Doc | Doc[]) => this.removeDocument(doc, `${this._props.fieldKey}_annotations`) || false;
moveAnnotationDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[], annotationKey?: string) => boolean) => this.moveDocument(doc, targetCollection, addDocument) || false;
+ setRef = (r: HTMLDivElement | null) => !this.Document.treeView_HasOverlay && r && this.createTreeDropTarget(r);
@observable _headerHeight = 0;
@computed get content() {
const background = () => this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string;
@@ -428,7 +429,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
<div
className="collectionTreeView-contents"
key="tree"
- ref={r => !this.Document.treeView_HasOverlay && r && this.createTreeDropTarget(r)}
+ ref={this.setRef}
style={{
...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
color: color(),
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 5b2f1ff81..f84c7d3c0 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1294,6 +1294,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
return null;
}
+ const setRef = (r: TreeView | null) => treeViewRefs.set(child, r || undefined);
const dentDoc = (editTitle: boolean, newParent: Doc, addAfter: Doc | undefined, parent: TreeView | CollectionTreeView | undefined) => {
if (parent instanceof TreeView && parent._props.treeView.fileSysMode && !newParent.isFolder) return;
const fieldKey = Doc.LayoutDataKey(newParent);
@@ -1317,7 +1318,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
return (
<TreeView
key={child[Id]}
- ref={r => treeViewRefs.set(child, r || undefined)}
+ ref={setRef}
Document={pair.layout}
dataDoc={pair.data}
treeViewParent={treeViewParent}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8f9b132e8..a447a6ae4 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -564,7 +564,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const B = this.screenToFreeformContentsXf.transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
const inkDoc = this.createInkDoc(points, B);
if (Doc.ActiveInk === InkInkTool.Highlight) inkDoc.$backgroundColor = 'transparent';
- if (Doc.ActiveInk === InkInkTool.Write) {
+ if ([InkInkTool.Write, InkInkTool.Math].includes(Doc.ActiveInk)) {
this.unprocessedDocs.push(inkDoc);
CollectionFreeFormView.collectionsWithUnprocessedInk.add(this);
}
@@ -2260,18 +2260,41 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
);
};
+ @computed get inkEraser() {
+ return (
+ Doc.ActiveTool === InkTool.Eraser &&
+ Doc.ActiveEraser === InkEraserTool.Radius &&
+ this._showEraserCircle && (
+ <div
+ onPointerMove={this.onCursorMove}
+ style={{
+ position: 'fixed',
+ left: this._eraserX,
+ top: this._eraserY,
+ width: (ActiveEraserWidth() + 5) * 2,
+ height: (ActiveEraserWidth() + 5) * 2,
+ borderRadius: '50%',
+ border: '1px solid gray',
+ transform: 'translate(-50%, -50%)',
+ }}
+ />
+ )
+ );
+ }
+
+ setRef = (r: HTMLDivElement | null) => {
+ this.createDashEventsTarget(r);
+ this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel);
+ r?.addEventListener('mouseleave', this.onMouseLeave);
+ r?.addEventListener('mouseenter', this.onMouseEnter);
+ };
render() {
TraceMobx();
return (
<div
className="collectionfreeformview-container"
id={this._paintedId}
- ref={r => {
- this.createDashEventsTarget(r);
- this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel);
- r?.addEventListener('mouseleave', this.onMouseLeave);
- r?.addEventListener('mouseenter', this.onMouseEnter);
- }}
+ ref={this.setRef}
onWheel={this.onPointerWheel}
onClick={this.onClick}
onPointerDown={this.onPointerDown}
@@ -2286,21 +2309,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
width: `${100 / this.nativeDimScaling}%`,
height: this._props.getScrollHeight?.() ?? `${100 / this.nativeDimScaling}%`,
}}>
- {Doc.ActiveTool === InkTool.Eraser && Doc.ActiveEraser === InkEraserTool.Radius && this._showEraserCircle && (
- <div
- onPointerMove={this.onCursorMove}
- style={{
- position: 'fixed',
- left: this._eraserX,
- top: this._eraserY,
- width: (ActiveEraserWidth() + 5) * 2,
- height: (ActiveEraserWidth() + 5) * 2,
- borderRadius: '50%',
- border: '1px solid gray',
- transform: 'translate(-50%, -50%)',
- }}
- />
- )}
+ {this.inkEraser}
{this.paintFunc ? (
<FormattedTextBox {...this.props} /> // need this so that any live dashfieldviews will update the underlying text that the code eval reads
) : this._lightboxDoc ? (
diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index 142085e14..c31558dff 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -150,6 +150,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this.Document);
}, 'remove doc from face');
+ setRef = (r: HTMLDivElement | null) => this.fixWheelEvents(r, this._props.isContentActive);
render() {
return (
<div className="face-document-item" ref={ele => this.createDropTarget(ele!)}>
@@ -176,7 +177,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
style={{
pointerEvents: this._props.isContentActive() ? undefined : 'none',
}}
- ref={r => this.fixWheelEvents(r, this._props.isContentActive)}>
+ ref={this.setRef}>
{FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => {
const [name, type] = ImageCastToNameType(doc?.[Doc.LayoutDataKey(doc)]) ?? ['-missing-', '.png'];
return (
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ff78b332a..4191aaca8 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -762,29 +762,26 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
}
e.stopPropagation();
};
+ setRef = (r: HTMLDivElement | null) => {
+ r?.addEventListener('dashDragMovePause', this.onDragMovePause as EventListenerOrEventListenerObject);
+ this.MarqueeRef = r;
+ };
render() {
return (
- <>
- <div
- className="marqueeView"
- ref={r => {
- r?.addEventListener('dashDragMovePause', this.onDragMovePause as EventListenerOrEventListenerObject);
- this.MarqueeRef = r;
- }}
- style={{
- overflow: StrCast(this._props.Document._overflow),
- cursor: Doc.ActiveTool === InkTool.Ink || this._visible ? 'crosshair' : 'pointer',
- }}
- onDragOver={e => e.preventDefault()}
- onScroll={e => {
- e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0;
- }}
- onClick={this.onClick}
- onPointerDown={this.onPointerDown}>
- {this._visible ? this.marqueeDiv : null}
- {this.props.children}
- </div>
- </>
+ <div
+ className="marqueeView"
+ ref={this.setRef}
+ style={{
+ overflow: StrCast(this._props.Document._overflow),
+ cursor: Doc.ActiveTool === InkTool.Ink || this._visible ? 'crosshair' : 'pointer',
+ }}
+ onDragOver={e => e.preventDefault()}
+ onScroll={e => (e.currentTarget.scrollTop = (e.currentTarget.scrollLeft = 0))} // prettier-ignore
+ onClick={this.onClick}
+ onPointerDown={this.onPointerDown}>
+ {this._visible ? this.marqueeDiv : null}
+ {this.props.children}
+ </div>
);
}
}
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index d0a1e6f0d..435f618d9 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -158,14 +158,13 @@ export class CollectionLinearView extends CollectionSubView() {
let dref: Opt<HTMLDivElement>;
const docXf = () => this.getTransform(dref);
+ const setRef = (r: HTMLDivElement | null) => (dref = r || undefined);
// const scalable = pair.layout.onClick || pair.layout.onDragStart;
return hidden ? null : (
<div
className={preview ? 'preview' : `collectionLinearView-docBtn`}
key={doc[Id]}
- ref={r => {
- dref = r || undefined;
- }}
+ ref={setRef}
style={{
pointerEvents: 'all',
width: NumCast(doc._width),
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 6442385c0..2576bdf9b 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -1043,17 +1043,16 @@ export class CollectionSchemaView extends CollectionSubView() {
if (!this._oldKeysWheel?.scrollTop && e.deltaY <= 0) e.preventDefault();
e.stopPropagation();
};
+ setRef = (r: HTMLDivElement | null) => {
+ this._oldKeysWheel?.removeEventListener('wheel', this.onKeysPassiveWheel);
+ this._oldKeysWheel = r;
+ r?.addEventListener('wheel', this.onKeysPassiveWheel, { passive: false });
+ };
_oldKeysWheel: HTMLDivElement | null = null;
@computed get keysDropdown() {
return (
<div className="schema-key-search">
- <div
- className="schema-key-list"
- ref={r => {
- this._oldKeysWheel?.removeEventListener('wheel', this.onKeysPassiveWheel);
- this._oldKeysWheel = r;
- r?.addEventListener('wheel', this.onKeysPassiveWheel, { passive: false });
- }}>
+ <div className="schema-key-list" ref={this.setRef}>
{this._menuKeys.map(key => (
<div
key={key}
@@ -1294,6 +1293,9 @@ export class CollectionSchemaView extends CollectionSubView() {
screenToLocal = () => this.ScreenToLocalBoxXf().translate(-this.tableWidth, 0);
previewWidthFunc = () => this.previewWidth;
displayedDocsFunc = () => this.docsWithDrag.docs;
+ setColHdrRef = (r: SchemaColumnHeader | null) => r && this._headerRefs.push(r);
+ setPreviewRef = (r: HTMLDivElement | null) => (this._previewRef = r);
+
render() {
return (
<div
@@ -1331,7 +1333,7 @@ export class CollectionSchemaView extends CollectionSubView() {
{this.columnKeys.map((key, index) => (
<SchemaColumnHeader
//cleanupField={this.cleanupComputedField}
- ref={r => r && this._headerRefs.push(r)}
+ ref={this.setColHdrRef}
keysDropdown={this.keysDropdown}
schemaView={this}
columnWidth={() => CollectionSchemaView._minColWidth} //TODO: update
@@ -1379,11 +1381,7 @@ export class CollectionSchemaView extends CollectionSubView() {
</div>
{this.previewWidth > 0 && <div className="schema-preview-divider" style={{ width: CollectionSchemaView._previewDividerWidth }} onPointerDown={this.onDividerDown} />}
{this.previewWidth > 0 && (
- <div
- style={{ width: `${this.previewWidth}px` }}
- ref={ref => {
- this._previewRef = ref;
- }}>
+ <div style={{ width: `${this.previewWidth}px` }} ref={this.setPreviewRef}>
{Array.from(this._selectedDocs).lastElement() && (
<DocumentView
Document={Array.from(this._selectedDocs).lastElement()}
diff --git a/src/client/views/collections/collectionSchema/SchemaCellField.tsx b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
index 9ad94cb31..412daa105 100644
--- a/src/client/views/collections/collectionSchema/SchemaCellField.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaCellField.tsx
@@ -341,12 +341,14 @@ export class SchemaCellField extends ObservableReactComponent<SchemaCellFieldPro
return <span className="editableView-static">{this._props.fieldContents ? <FieldView {...this._props.fieldContents} /> : ''}</span>;
};
+ setRef = (r: HTMLDivElement | null) => (this._inputref = r);
+
renderEditor = () => {
return (
<div
contentEditable
className="schemaField-editing"
- ref={r => (this._inputref = r)}
+ ref={this.setRef}
style={{ minHeight: `min(100%, ${(this._props.GetValue()?.split('\n').length || 1) * 15})`, minWidth: 20 }}
onBlur={() => (this._props.refSelectModeInfo.enabled ? setTimeout(() => this.setIsFocused(true), 1000) : this.finalizeEdit(false, true, false))}
onInput={this.onChange}
diff --git a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
index 134f2ed31..64bfab856 100644
--- a/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaColumnHeader.tsx
@@ -118,6 +118,10 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
return { color, fieldProps, cursor };
};
+ setRef = (r: EditableView | null) => {
+ this._inputRef = r;
+ this._props.autoFocus && r?.setIsFocused(true);
+ };
@computed get editableView() {
const { color, fieldProps } = this.renderProps(this._props);
@@ -133,10 +137,7 @@ export class SchemaColumnHeader extends ObservableReactComponent<SchemaColumnHea
width: '100%',
}}>
<EditableView
- ref={r => {
- this._inputRef = r;
- this._props.autoFocus && r?.setIsFocused(true);
- }}
+ ref={this.setRef}
oneLine={true}
allowCRs={false}
contents={''}
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 8b34b4139..02e0d8100 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -185,6 +185,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
return eqSymbol + modField;
};
+ setRef = (r: SchemaCellField | null) => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true);
@computed get defaultCellContent() {
const { color, textDecoration, fieldProps, pointerEvents } = SchemaTableCell.renderProps(this._props);
@@ -204,7 +205,7 @@ export class SchemaTableCell extends ObservableReactComponent<SchemaTableCellPro
Doc={this._props.Doc}
highlightCells={(text: string) => this._props.highlightCells(this.adjustSelfReference(text))}
getCells={(text: string) => this._props.eqHighlightFunc(this.adjustSelfReference(text))}
- ref={r => selectedCell(this._props) && this._props.autoFocus && r?.setIsFocused(true)}
+ ref={this.setRef}
oneLine={this._props.oneLine}
contents={undefined}
fieldContents={fieldProps}
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index cb3adae10..e098d50d8 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -408,7 +408,7 @@ function setActiveTool(tool: InkTool | InkEraserTool | InkInkTool | Gestures, ke
}
runInAction(() => {
const eraserTool = tool === InkTool.Eraser ? Doc.ActiveEraser : [InkEraserTool.Stroke, InkEraserTool.Radius, InkEraserTool.Segment].includes(tool as InkEraserTool) ? (tool as InkEraserTool) : undefined;
- const inkTool = tool === InkTool.Ink ? Doc.ActiveInk : [InkInkTool.Pen, InkInkTool.Write, InkInkTool.Highlight].includes(tool as InkInkTool) ? (tool as InkInkTool) : undefined;
+ const inkTool = tool === InkTool.Ink ? Doc.ActiveInk : [InkInkTool.Pen, InkInkTool.Write, InkInkTool.Math, InkInkTool.Highlight].includes(tool as InkInkTool) ? (tool as InkInkTool) : undefined;
if (GestureOverlay.Instance) {
SnappingManager.SetKeepGestureMode(keepPrim);
}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 9369ff98a..0b7033e57 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -420,6 +420,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
};
+ setRef = (r: LineChart | Histogram | PieChart | null) => (this._vizRenderer = r ?? undefined);
// toggles for user to decide which chart type to view the data in
@computed get renderVizView() {
const scale = this._props.NativeDimScaling?.() || 1;
@@ -437,9 +438,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
if (!this.records.length) return 'no data/visualization';
switch (this.dataVizView) {
case DataVizView.TABLE: return <TableBox {...sharedProps} Doc={this.Document} specHighlightedRow={this._specialHighlightedRow} docView={this.DocumentView} selectAxes={this.selectAxes} selectTitleCol={this.selectTitleCol}/>;
- case DataVizView.LINECHART: return <LineChart {...sharedProps} Doc={this.Document} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => {this._vizRenderer = r ?? undefined;}} vizBox={this} />;
- case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} Doc={this.Document} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => {this._vizRenderer = r ?? undefined;}} />;
- case DataVizView.PIECHART: return <PieChart {...sharedProps} Doc={this.Document} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => {this._vizRenderer = r ?? undefined;}}
+ case DataVizView.LINECHART: return <LineChart {...sharedProps} Doc={this.Document} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={this.setRef} vizBox={this} />;
+ case DataVizView.HISTOGRAM: return <Histogram {...sharedProps} Doc={this.Document} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={this.setRef} />;
+ case DataVizView.PIECHART: return <PieChart {...sharedProps} Doc={this.Document} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={this.setRef}
margin={{ top: 10, right: 15, bottom: 15, left: 15 }} />;
default:
} // prettier-ignore
diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
index fb083ea75..8f6ecab57 100644
--- a/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
+++ b/src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx
@@ -540,6 +540,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
]; //prettier-ignore
}
+ setRef = (r: HTMLDivElement) => (this._ref = r);
render() {
const topButton = (icon: string, opt: string, func: () => void, tag: string) => (
<div className={`top-button-container ${tag} ${opt === this._menuContent ? 'selected' : ''}`}>
@@ -558,7 +559,7 @@ export class DocCreatorMenu extends ObservableReactComponent<DocCreateMenuProps>
{!this._shouldDisplay ? undefined : (
<div
className="docCreatorMenu-cont"
- ref={r => (this._ref = r)}
+ ref={this.setRef}
style={{
display: '',
left: this._pageX,
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index a7c4a00b0..f51683991 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -413,6 +413,10 @@ export class Histogram extends ObservableReactComponent<HistogramProps> {
});
};
+ setChartRef = (r: HTMLDivElement | null) => {
+ this._histogramRef = r;
+ r && this.drawChart(this._histogramData, this.width, this.height);
+ };
render() {
if (!this.selectedBins) this.layoutDoc.dataViz_histogram_selectedBins = new List<string>();
@@ -446,12 +450,7 @@ export class Histogram extends ObservableReactComponent<HistogramProps> {
size={Size.XSMALL}
/>
</div>
- <div
- ref={r => {
- this._histogramRef = r;
- r && this.drawChart(this._histogramData, this.width, this.height);
- }}
- />
+ <div ref={this.setChartRef} />
{selected !== 'none' ? (
<div className="selected-data">
Selected: {selected}
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 80fadf178..732681e05 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -347,6 +347,10 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
.style('pointer-events', 'none')
.style('transform', `translate(${xScale(d0.x) - this.width}px,${yScale(d0.y)}px)`);
}
+ setLineRef = (r: HTMLDivElement | null) => {
+ this._lineChartRef = r;
+ this.drawChart([this._lineChartData], this.rangeVals, this.width, this.height);
+ };
render() {
const selectedPt = this._currSelected ? `{ ${this._props.axes[0]}: ${this._currSelected.x} ${this._props.axes[1]}: ${this._currSelected.y} }` : 'none';
@@ -378,12 +382,7 @@ export class LineChart extends ObservableReactComponent<LineChartProps> {
fillWidth
/>
</div>
- <div
- ref={r => {
- this._lineChartRef = r;
- this.drawChart([this._lineChartData], this.rangeVals, this.width, this.height);
- }}
- />
+ <div ref={this.setLineRef} />
{selectedPt !== 'none' ? (
<div className="selected-data">
{`Selected: ${selectedPt}`}
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 0ae70786f..cf476b8d0 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -373,10 +373,10 @@ export class PieChart extends ObservableReactComponent<PieChartProps> {
const sliceName = StrCast(sliceTitle) ? StrCast(sliceTitle).replace(/\$/g, '').replace(/%/g, '').replace(/#/g, '').replace(/</g, '') : sliceTitle;
const sliceColors = Cast(this._props.layoutDoc.dataViz_pie_sliceColors, listSpec('string'), null);
- sliceColors.forEach(each => {
+ sliceColors?.forEach(each => {
if (each.split('::')[0] === sliceName) sliceColors.splice(sliceColors.indexOf(each), 1);
});
- sliceColors.push(StrCast(sliceName + '::' + color));
+ sliceColors?.push(StrCast(sliceName + '::' + color));
};
@action changeHistogramCheckBox = () => {
@@ -384,6 +384,10 @@ export class PieChart extends ObservableReactComponent<PieChartProps> {
this.drawChart(this._pieChartData, this.width, this.height);
};
+ setChartRef = (r: HTMLDivElement | null) => {
+ this._piechartRef = r;
+ this.drawChart(this._pieChartData, this.width, this.height);
+ };
render() {
let titleAccessor = 'dataViz_pie_title';
if (this._props.axes.length === 2) titleAccessor = titleAccessor + this._props.axes[0] + '-' + this._props.axes[1];
@@ -443,12 +447,7 @@ export class PieChart extends ObservableReactComponent<PieChartProps> {
Organize data as histogram
</div>
) : null}
- <div
- ref={r => {
- this._piechartRef = r;
- this.drawChart(this._pieChartData, this.width, this.height);
- }}
- />
+ <div ref={this.setChartRef} />
{selected !== 'none' ? (
<div className="selected-data">
Selected: {selected}
diff --git a/src/client/views/nodes/DiagramBox.tsx b/src/client/views/nodes/DiagramBox.tsx
index 7cfccf0dc..6a31f64ce 100644
--- a/src/client/views/nodes/DiagramBox.tsx
+++ b/src/client/views/nodes/DiagramBox.tsx
@@ -185,6 +185,8 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return '( )';
};
+ setRef = (r: HTMLDivElement | null) => this.fixWheelEvents(r, this._props.isContentActive);
+ setDiagramBoxRef = (r: HTMLDivElement | null) => r && this.renderMermaidAsync.call(this, this.removeWords(this.mermaidcode), r);
render() {
return (
<div
@@ -192,7 +194,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
style={{
pointerEvents: this._props.isContentActive() ? undefined : 'none',
}}
- ref={r => this.fixWheelEvents(r, this._props.isContentActive)}>
+ ref={this.setRef}>
<div className="DIYNodeBox-searchbar">
<input type="text" value={this._inputValue} onKeyDown={action(e => e.key === 'Enter' && this.generateMermaidCode())} onChange={action(e => (this._inputValue = e.target.value))} />
<button type="button" onClick={this.generateMermaidCode}>
@@ -208,7 +210,7 @@ export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
) : this._generating ? (
<div className="loading-circle" />
) : (
- <div className="diagramBox" ref={r => r && this.renderMermaidAsync.call(this, this.removeWords(this.mermaidcode), r)}>
+ <div className="diagramBox" ref={this.setDiagramBoxRef}>
{this._errorMessage || 'Type a prompt to generate a diagram'}
</div>
)}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 504c1491e..32741a0fe 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -261,9 +261,7 @@ export class DocumentContentsView extends ObservableReactComponent<DocumentConte
jsx={layoutFrame}
showWarnings
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- onError={(test: any) => {
- console.log('DocumentContentsView:' + test, bindings, layoutFrame);
- }}
+ onError={(test: any) => console.log('DocumentContentsView:' + test, bindings, layoutFrame)}
/>
);
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index fe95f15af..bd71115db 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -701,16 +701,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewProps & Field
aiContentsWidth = () => (this.aiContentsHeight() * (this._props.NativeWidth?.() || 1)) / (this._props.NativeHeight?.() || 1);
aiContentsHeight = () => Math.max(10, this._props.PanelHeight() - (this._aiWinHeight + (this.tagsOverlayFunc() ? 22 : 0)) * this.uiBtnScaling);
+ setAiRef = action((r: HTMLDivElement | null) => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r)));
+
@computed get aiEditor() {
return (
<div
className="documentView-editorView"
+ ref={this.setAiRef}
style={{
background: SnappingManager.userVariantColor,
width: `${100 / this.uiBtnScaling}%`, //
transform: `scale(${this.uiBtnScaling})`,
- }}
- ref={r => this.historyRef(this._oldHistoryWheel, (this._oldHistoryWheel = r))}>
+ }}>
<div className="documentView-editorView-resizer" />
{this._componentView?.componentAIView?.() ?? null}
{this._props.DocumentView?.() ? <TagsView background={this.backgroundBoxColor} Views={[this._props.DocumentView?.()]} /> : null}
@@ -1507,18 +1509,16 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
.translate(-(this._docViewInternal?.aiShift() ?? 0), 0)
.scale((this._docViewInternal?.aiScale() ?? 1) / this.nativeScaling);
+ setHtmlOverlayRef = (r: HTMLDivElement | null) => {
+ const val = r?.style.display !== 'none'; // if the outer overlay has been displayed, trigger the innner div to start it's opacity fade in transition
+ if (r && val !== this._enableHtmlOverlayTransitions) {
+ setTimeout(action(() => (this._enableHtmlOverlayTransitions = val)));
+ }
+ };
htmlOverlay = () => {
const effect = StrCast(this._htmlOverlayEffect?.presentation_effect, StrCast(this._htmlOverlayEffect?.followLinkAnimEffect));
return (
- <div
- className="documentView-htmlOverlay"
- ref={r => {
- const val = r?.style.display !== 'none'; // if the outer overlay has been displayed, trigger the innner div to start it's opacity fade in transition
- if (r && val !== this._enableHtmlOverlayTransitions) {
- setTimeout(action(() => (this._enableHtmlOverlayTransitions = val)));
- }
- }}
- style={{ display: !this._htmlOverlayText ? 'none' : undefined }}>
+ <div className="documentView-htmlOverlay" ref={this.setHtmlOverlayRef} style={{ display: !this._htmlOverlayText ? 'none' : undefined }}>
<div className="documentView-htmlOverlayInner" style={{ transition: `all 500ms`, opacity: this._enableHtmlOverlayTransitions ? 0.9 : 0 }}>
{DocumentViewInternal.AnimationEffect(
<div className="webBox-textHighlight">
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index e0ab04692..2ce24b688 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -116,12 +116,13 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.layoutDoc._nativeHeight = mathHeight;
}
};
+ setRef = (r: HTMLDivElement) => r && this._ref.current?.element.current && this.updateSize(this._ref.current?.element.current);
render() {
TraceMobx();
const scale = this._props.NativeDimScaling?.() || 1;
return (
<div
- ref={r => r && this._ref.current?.element.current && this.updateSize(this._ref.current?.element.current)}
+ ref={this.setRef}
className="equationBox-cont"
onKeyDown={e => e.stopPropagation()}
onPointerDown={e => !e.ctrlKey && e.stopPropagation()}
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index 8e4b64851..e4d37e006 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -121,11 +121,12 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
}
// if (this.layout_autoHeight) this.tryUpdateScrollHeight();
};
+ setRef = (r: HTMLDivElement | null) => r && this.createGraph(r);
@computed get theGraph() {
return (
<div
id={`${this._plotId}`}
- ref={r => r && this.createGraph(r)}
+ ref={this.setRef}
style={{ position: 'absolute', width: '100%', height: '100%' }}
onPointerDown={e => {
e.stopPropagation();
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index e1ecc2018..c5948cbbd 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -169,6 +169,25 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
+ setRef = (r: HTMLDivElement | null) => {
+ this._divRef?.removeEventListener('beforeinput', this.beforeInput);
+ this._divRef = r;
+ if (this._divRef) {
+ this._divRef.addEventListener('beforeinput', this.beforeInput);
+
+ if (DocumentView.SelectOnLoad === this.Document) {
+ DocumentView.SetSelectOnLoad(undefined);
+ this._liveTextUndo = FormattedTextBox.LiveTextUndo;
+ FormattedTextBox.LiveTextUndo = undefined;
+ this._divRef.focus();
+ }
+ this.fitTextToBox(this._divRef);
+ if (this.Title) {
+ this.resetCursor();
+ }
+ } else this._timeout && clearTimeout(this._timeout);
+ };
+
render() {
TraceMobx();
const boxParams = this.fitTextToBox(undefined); // this causes mobx to trigger re-render when data changes
@@ -228,24 +247,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
__html: `<span class="textFitted textFitAlignVert" style="display: inline-block; text-align: center; font-size: 100px; height: 0px;">${this.Title?.startsWith('#') ? '' : (this.Title ?? '')}</span>`,
}}
contentEditable={this._props.onClickScript?.() ? undefined : true}
- ref={r => {
- this._divRef?.removeEventListener('beforeinput', this.beforeInput);
- this._divRef = r;
- if (this._divRef) {
- this._divRef.addEventListener('beforeinput', this.beforeInput);
-
- if (DocumentView.SelectOnLoad === this.Document) {
- DocumentView.SetSelectOnLoad(undefined);
- this._liveTextUndo = FormattedTextBox.LiveTextUndo;
- FormattedTextBox.LiveTextUndo = undefined;
- this._divRef.focus();
- }
- this.fitTextToBox(this._divRef);
- if (this.Title) {
- this.resetCursor();
- }
- } else this._timeout && clearTimeout(this._timeout);
- }}
+ ref={this.setRef}
/>
</div>
</div>
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 78c8a686c..d31fadf77 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -99,6 +99,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
}
};
+ setRef = (r: HTMLDivElement | null) => (this._divRef = r);
render() {
TraceMobx();
@@ -149,28 +150,18 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
const aid = targetAhyperlinks?.find(alink => container?.contains(alink))?.id ?? targetAhyperlinks?.lastElement()?.id;
const bid = targetBhyperlinks?.find(blink => container?.contains(blink))?.id ?? targetBhyperlinks?.lastElement()?.id;
if (!aid || !bid) {
- setTimeout(
- action(() => {
- this._forceAnimate += 0.01;
- })
- );
+ setTimeout(action(() => (this._forceAnimate += 0.01)));
return null;
}
if (foundParent) {
setTimeout(
- action(() => {
- this._forceAnimate += 0.01;
- }),
+ action(() => (this._forceAnimate += 0.01)),
1
);
}
-
- if (at || bt)
- setTimeout(
- action(() => {
- this._forceAnimate += 0.01;
- })
- ); // this forces an update during a transition animation
+ if (at || bt) {
+ setTimeout(action(() => (this._forceAnimate += 0.01))); // this forces an update during a transition animation
+ }
const highlight = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Highlighting) as { highlightStyle: string; highlightColor: string; highlightIndex: number; highlightStroke: boolean };
const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : undefined;
const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string;
@@ -217,7 +208,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
id={this.DocumentView?.().DocUniqueId}
className="linkBox-label"
tabIndex={-1}
- ref={r => (this._divRef = r)}
+ ref={this.setRef}
onPointerDown={e => e.stopPropagation()}
onFocus={() => {
RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined, this.dataDoc);
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 5b07b303a..1d6f41c65 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -250,6 +250,10 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
);
}
+ setDocViewRef = (r: DocumentView | null) => {
+ const targetanchor = this._linkDoc && this._linkSrc && Doc.getOppositeAnchor(this._linkDoc, this._linkSrc);
+ targetanchor && this._targetDoc !== targetanchor && r?._props.focus?.(targetanchor, {});
+ };
@computed get docPreview() {
return (!this._linkDoc || !this._targetDoc || !this._linkSrc) && !this._toolTipText ? null : (
<div className="linkDocPreview-inner">
@@ -279,10 +283,7 @@ export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps
this._toolTipText
) : (
<DocumentView
- ref={r => {
- const targetanchor = this._linkDoc && this._linkSrc && Doc.getOppositeAnchor(this._linkDoc, this._linkSrc);
- targetanchor && this._targetDoc !== targetanchor && r?._props.focus?.(targetanchor, {});
- }}
+ ref={this.setDocViewRef}
Document={this._targetDoc!}
moveDocument={returnFalse}
styleProvider={this._props.styleProvider}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 603dcad5c..4677e0e61 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -171,19 +171,21 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
ContextMenu.Instance.addItem({ description: 'Options...', subitems, icon: 'video' });
};
+ setRef = (r: HTMLVideoElement | null) => {
+ this._videoRef = r;
+ setTimeout(() => {
+ if (this.layoutDoc.mediaState === mediaState.PendingRecording && this._videoRef) {
+ this.toggleRecording();
+ }
+ }, 100);
+ };
+
@computed get content() {
return (
<video
className="videoBox-content"
key="video"
- ref={r => {
- this._videoRef = r;
- setTimeout(() => {
- if (this.layoutDoc.mediaState === mediaState.PendingRecording && this._videoRef) {
- this.toggleRecording();
- }
- }, 100);
- }}
+ ref={this.setRef}
autoPlay={this._screenCapture}
style={{ width: this._screenCapture ? '100%' : undefined, height: this._screenCapture ? '100%' : undefined }}
onCanPlay={this.videoLoad}
diff --git a/src/client/views/nodes/calendarBox/CalendarBox.tsx b/src/client/views/nodes/calendarBox/CalendarBox.tsx
index a4183a11a..a2fa83b5a 100644
--- a/src/client/views/nodes/calendarBox/CalendarBox.tsx
+++ b/src/client/views/nodes/calendarBox/CalendarBox.tsx
@@ -298,10 +298,9 @@ export class CalendarBox extends CollectionSubView() {
ev.preventDefault();
});
}}
-
// for dragging and dropping (mirror)
- eventDragStart={(arg) => {
+ eventDragStart={arg => {
const mirror = arg.el.cloneNode(true) as HTMLElement;
const rect = arg.el.getBoundingClientRect();
@@ -312,25 +311,24 @@ export class CalendarBox extends CollectionSubView() {
mirror.classList.add('custom-drag-mirror');
mirror.style.width = `${rect.width}px`;
mirror.style.height = `${rect.height}px`;
-
+
document.body.appendChild(mirror);
-
+
const moveListener = (ev: MouseEvent) => {
- mirror.style.left = `${ev.clientX}px`;
- mirror.style.top = `${ev.clientY}px`;
+ mirror.style.left = `${ev.clientX}px`;
+ mirror.style.top = `${ev.clientY}px`;
};
-
+
window.addEventListener('mousemove', moveListener);
// hide the actual box
arg.el.style.visibility = 'hidden';
arg.el.style.opacity = '0';
-
+
(arg.el as any)._mirrorElement = mirror;
(arg.el as any)._moveListener = moveListener;
}}
-
- eventDragStop={(arg) => {
+ eventDragStop={arg => {
const el = arg.el as any;
const mirror = el._mirrorElement;
const moveListener = el._moveListener;
@@ -338,15 +336,18 @@ export class CalendarBox extends CollectionSubView() {
// show the actual box
el.style.visibility = 'visible';
el.style.opacity = '1';
-
+
if (mirror) document.body.removeChild(mirror);
if (moveListener) window.removeEventListener('mousemove', moveListener);
}}
-
/>
);
}
+ setRef = (r: HTMLDivElement | null) => {
+ this.createDashEventsTarget(r);
+ this.fixWheelEvents(r, this._props.isContentActive);
+ };
render() {
const scale = this._props.ScreenToLocalTransform().Scale;
const scaledWidth = this._props.PanelWidth();
@@ -361,11 +362,8 @@ export class CalendarBox extends CollectionSubView() {
height: scaledHeight,
overflow: 'hidden',
position: 'relative',
- }}
- ref={r => {
- this.createDashEventsTarget(r);
- this.fixWheelEvents(r, this._props.isContentActive);
}}
+ ref={this.setRef}
onPointerDown={e => {
setTimeout(
action(() => {
@@ -383,9 +381,8 @@ export class CalendarBox extends CollectionSubView() {
transformOrigin: 'top left',
width: scaledWidth / scale,
height: scaledHeight / scale,
- }}
- >
- {this.renderCalendar}
+ }}>
+ {this.renderCalendar}
</div>
</div>
);
diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
index 18d0266af..3f61d9ea6 100644
--- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
+++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx
@@ -1462,13 +1462,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</svg>
)}
</button>
- <DictationButton
- ref={r => {
- this._dictation = r;
- }}
- setInput={this.setChatInput}
- inputRef={this._textInputRef}
- />
+ <DictationButton ref={this.setDictationRef} setInput={this.setChatInput} inputRef={this._textInputRef} />
</form>
{/* Popup for citation */}
{this._citationPopup.visible && (
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 07cb795f1..255ee1afe 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2129,6 +2129,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
}
};
+ setRef = (r: HTMLDivElement | null) => this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel);
+ setScrollRef = (r: HTMLDivElement | null) => (this._scrollRef = r);
render() {
TraceMobx();
const scale = this.nativeScaling();
@@ -2143,7 +2145,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
) : styleFromLayout?.height === '0px' ? null : (
<div
className="formattedTextBox"
- ref={r => this.fixWheelEvents(r, this._props.isContentActive, this.onPassiveWheel)}
+ ref={this.setRef}
style={{
...(this._props.dontScale
? {}
@@ -2181,9 +2183,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
onDoubleClick={this.onDoubleClick}>
<div
className="formattedTextBox-outer"
- ref={r => {
- this._scrollRef = r;
- }}
+ ref={this.setScrollRef}
style={{
width: this.noSidebar ? '100%' : `calc(100% - ${this.sidebarWidthPercent})`,
overflow: this.layoutDoc._createDocOnCR || this.layoutDoc._layout_hideScroll ? 'hidden' : this.layout_autoHeight ? 'visible' : undefined,
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index cb2a1f13f..04b312ca5 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -1743,6 +1743,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
return <div />;
}
+ setAiEffectsRef = (r: HTMLTextAreaElement | null) =>
+ setTimeout(() => {
+ if (r && !r.textContent) {
+ r.style.height = '';
+ r.style.height = r.scrollHeight + 'px';
+ }
+ });
+
+ setAnimDictationRef = (r: DictationButton | null) => (this._animationDictation = r);
/**
* This chatbox is for getting slide effect transition suggestions from gpt and visualizing them
*/
@@ -1755,14 +1764,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<ReactTextareaAutosize
placeholder="Use AI to suggest effects. Leave blank for random results."
className="pres-chatbox"
- ref={r => {
- setTimeout(() => {
- if (r && !r.textContent) {
- r.style.height = '';
- r.style.height = r.scrollHeight + 'px';
- }
- });
- }}
+ ref={this.setAiEffectsRef}
value={this._animationChat}
onChange={e => {
e.currentTarget.style.height = '';
@@ -1784,12 +1786,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
color={SnappingManager.userVariantColor}
onClick={this.customizeAnimations}
/>
- <DictationButton
- ref={r => {
- this._animationDictation = r;
- }}
- setInput={this.setAnimationChat}
- />
+ <DictationButton ref={this.setAnimDictationRef} setInput={this.setAnimationChat} />
</div>
<div style={{ alignItems: 'center' }}>
Click a box to use the effect.
@@ -1821,6 +1818,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
);
}
+ setPropertiesRef = (r: HTMLTextAreaElement | null) =>
+ setTimeout(() => {
+ if (r && !r.textContent) {
+ r.style.height = '';
+ r.style.height = r.scrollHeight + 'px';
+ }
+ });
+
+ setSlideDictationRef = (r: DictationButton | null) => (this._slideDictation = r);
+
@computed get transitionDropdown() {
const { activeItem } = this;
// Retrieving spring timing properties
@@ -1855,14 +1862,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
<ReactTextareaAutosize
placeholder="Describe how to modify the slide properties."
className="pres-chatbox"
- ref={r => {
- setTimeout(() => {
- if (r && !r.textContent) {
- r.style.height = '';
- r.style.height = r.scrollHeight + 'px';
- }
- });
- }}
+ ref={this.setPropertiesRef}
value={this._chatInput}
onChange={e => {
e.currentTarget.style.height = '';
@@ -1874,12 +1874,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
e.stopPropagation();
}}
/>
- <DictationButton
- ref={r => {
- this._slideDictation = r;
- }}
- setInput={this.setChatInput}
- />
+ <DictationButton ref={this.setSlideDictationRef} setInput={this.setChatInput} />
</div>
<Button
style={{ alignSelf: 'flex-end' }}
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 568e48edf..9c37428ee 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -11,7 +11,7 @@ import { ClientUtils } from '../../../../ClientUtils';
import { Doc } from '../../../../fields/Doc';
import { NumCast, StrCast } from '../../../../fields/Types';
import { Networking } from '../../../Network';
-import { DescriptionSeperator, DocSeperator, GPTCallType, GPTDocCommand, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT';
+import { DataSeperator, DescriptionSeperator, DocSeperator, GPTCallType, GPTDocCommand, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT';
import { DocUtils } from '../../../documents/DocUtils';
import { Docs } from '../../../documents/Documents';
import { SettingsManager } from '../../../util/SettingsManager';
@@ -90,7 +90,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
if (hasChildDocs) {
this._textToDocMap.clear();
this.setCollectionContext(selDoc.Document);
- this.onGptResponse = (sortResult: string, questionType: GPTDocCommand, args?: string) => this.processGptResponse(selDoc, this._textToDocMap, sortResult, questionType, args);
+ this.onGptResponse = (sortResult: string, questionType: GPTDocCommand) => this.processGptResponse(selDoc, this._textToDocMap, sortResult, questionType);
this.onQuizRandom = () => this.randomlyChooseDoc(selDoc.Document, hasChildDocs());
this._documentDescriptions = Promise.all(hasChildDocs().map(doc =>
Doc.getDescription(doc).then(text => this._textToDocMap.set(text.replace(/\n/g, ' ').trim(), doc) && `${DescriptionSeperator}${text}${DescriptionSeperator}`)
@@ -134,7 +134,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
* @param questionType
* @param tag
*/
- processGptResponse = (docView: DocumentView, textToDocMap: Map<string, Doc>, gptOutput: string, questionType: GPTDocCommand, args?: string) =>
+ processGptResponse = (docView: DocumentView, textToDocMap: Map<string, Doc>, gptOutput: string, questionType: GPTDocCommand) =>
undoable(() => {
switch (questionType) { // reset collection based on question typefc
case GPTDocCommand.Sort:
@@ -145,20 +145,17 @@ export class GPTPopup extends ObservableReactComponent<object> {
break;
} // prettier-ignore
- gptOutput.split('======').filter(item => item.trim() !== '') // Split output into individual document contents
- .map(docContentRaw => textToDocMap.get(docContentRaw.replace(/\n/g, ' ').trim())) // the find the corresponding Doc using textToDoc map
- .filter(doc => doc).map(doc => doc!) // filter out undefined values
- .forEach((doc, index) => {
+ gptOutput.split(DescriptionSeperator).filter(item => item.trim() !== '') // Split output into individual document contents
+ .map(docContentRaw => docContentRaw.replace(/\n/g, ' ').trim())
+ .map(docContentRaw => ({doc: textToDocMap.get(docContentRaw.split(DataSeperator)[0]), data: docContentRaw.split(DataSeperator)[1] })) // the find the corresponding Doc using textToDoc map
+ .filter(({doc}) => doc).map(({doc, data}) => ({doc:doc!, data})) // filter out undefined values
+ .forEach(({doc, data}, index) => {
switch (questionType) {
case GPTDocCommand.Sort:
doc[ChatSortField] = index;
break;
case GPTDocCommand.AssignTags:
- if (args) {
- const hashTag = args.startsWith('#') ? args : '#' + args[0].toLowerCase() + args.slice(1);
- const filterTag = Doc.MyFilterHotKeys.map(key => StrCast(key.toolType)).find(key => key.includes(args)) ?? hashTag;
- TagItem.addTagToDoc(doc, filterTag);
- }
+ data && TagItem.addTagToDoc(doc, data.startsWith('#') ? data : '#'+data[0].toLowerCase()+data.slice(1) );
break;
case GPTDocCommand.Filter:
TagItem.addTagToDoc(doc, GPTPopup.ChatTag);
@@ -238,10 +235,10 @@ export class GPTPopup extends ObservableReactComponent<object> {
* @param userPrompt the user's input that chat will respond to
*/
generateUserPromptResponse = (userPrompt: string) =>
- gptAPICall(userPrompt, GPTCallType.COMMANDTYPE, undefined, true).then((commandType, args = commandType.split(' ').slice(1).join(' ')) =>
+ gptAPICall(userPrompt, GPTCallType.COMMANDTYPE, undefined, true).then(commandType =>
(async () => {
switch (this.NumberToCommandType(commandType)) {
- case GPTDocCommand.AssignTags:
+ case GPTDocCommand.AssignTags:return this._documentDescriptions?.then(descs => gptAPICall(userPrompt, GPTCallType.TAGDOCS, descs)) ?? "";
case GPTDocCommand.Filter: return this._documentDescriptions?.then(descs => gptAPICall(userPrompt, GPTCallType.SUBSETDOCS, descs)) ?? "";
case GPTDocCommand.Sort: return this._documentDescriptions?.then(descs => gptAPICall(userPrompt, GPTCallType.SORTDOCS, descs)) ?? "";
default: return Doc.getDescription(DocumentView.SelectedDocs().lastElement()).then(desc => gptAPICall(userPrompt, GPTCallType.DOCINFO, desc));
@@ -249,7 +246,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
})().then(
action(res => {
// Trigger the callback with the result
- this.onGptResponse?.(res || 'Something went wrong :(', this.NumberToCommandType(commandType), args);
+ this.onGptResponse?.(res || 'Something went wrong :(', this.NumberToCommandType(commandType));
this._conversationArray.push(
this.NumberToCommandType(commandType) === GPTDocCommand.GetInfo ? res:
// Extract explanation surrounded by the DocSeperator string (defined in GPT.ts) at the top or both at the top and bottom
@@ -515,6 +512,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
</div>
);
+ setDictationRef = (r: DictationButton | null) => (this._askDictation = r);
promptBox = (heading: string, value: string, onChange: (e: string) => string, placeholder: string) => (
<>
<div className="gptPopup-sortBox">
@@ -541,7 +539,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
background={SettingsManager.userVariantColor}
onClick={() => this.callGpt(this._mode)}
/>
- <DictationButton ref={r => (this._askDictation = r)} setInput={onChange} />
+ <DictationButton ref={this.setDictationRef} setInput={onChange} />
</div>
</>
);
diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts
index d1dda106a..f2c09b6b7 100644
--- a/src/fields/InkField.ts
+++ b/src/fields/InkField.ts
@@ -18,6 +18,7 @@ export enum InkInkTool {
Pen = 'Pen',
Highlight = 'Highlight',
Write = 'Write',
+ Math = 'Math',
}
export enum InkEraserTool {