aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGeireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>2023-07-08 13:13:20 -0400
committerGeireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>2023-07-08 13:13:20 -0400
commitb67380fd889bef0a3e5ca2c3a90473db4d6b8c31 (patch)
treea5dc8c8aaab1f7420f6e8c3bef25599cbcdb173b /src
parente8a55c5400ac6ec4a14c8d3422edd1cc532dd2ac (diff)
parente4ad92e7300ee7844a514379c8a01d0f01cb3a59 (diff)
Merge branch 'master' into geireann_dash_components
Diffstat (limited to 'src')
-rw-r--r--src/Utils.ts8
-rw-r--r--src/client/documents/Documents.ts7
-rw-r--r--src/client/util/DocumentManager.ts35
-rw-r--r--src/client/views/DashboardView.tsx3
-rw-r--r--src/client/views/DocComponent.tsx2
-rw-r--r--src/client/views/DocumentButtonBar.tsx1
-rw-r--r--src/client/views/DocumentDecorations.tsx2
-rw-r--r--src/client/views/FilterPanel.tsx14
-rw-r--r--src/client/views/StyleProvider.tsx6
-rw-r--r--src/client/views/collections/CollectionDockingView.scss6
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx11
-rw-r--r--src/client/views/collections/CollectionNoteTakingView.tsx5
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx5
-rw-r--r--src/client/views/collections/CollectionSubView.tsx12
-rw-r--r--src/client/views/collections/TabDocView.tsx155
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx32
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss9
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx17
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss10
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx17
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx15
-rw-r--r--src/client/views/nodes/DocumentView.tsx10
-rw-r--r--src/client/views/nodes/ImageBox.tsx19
-rw-r--r--src/client/views/nodes/button/FontIconBox.scss4
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx19
-rw-r--r--src/client/views/pdf/PDFViewer.scss8
-rw-r--r--src/client/views/pdf/PDFViewer.tsx13
-rw-r--r--src/fields/Doc.ts6
-rw-r--r--src/fields/util.ts5
29 files changed, 264 insertions, 192 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index 8c56896c5..2e06b5631 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -141,7 +141,7 @@ export namespace Utils {
const isTransparentFunctionHack = 'isTransparent(__value__)';
export const noRecursionHack = '__noRecursion';
- export const noDragsDocFilter = 'noDragDocs:any:check';
+ export const noDragsDocFilter = 'noDragDocs::any::check';
export function IsRecursiveFilter(val: string) {
return !val.includes(noRecursionHack);
}
@@ -150,14 +150,14 @@ export namespace Utils {
}
export function IsTransparentFilter() {
// bcz: isTransparent(__value__) is a hack. it would be nice to have acual functions be parsed, but now Doc.matchFieldValue is hardwired to recognize just this one
- return `backgroundColor:${isTransparentFunctionHack},${noRecursionHack}:check`; // bcz: hack. noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field
+ return `backgroundColor::${isTransparentFunctionHack},${noRecursionHack}::check`; // bcz: hack. noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field
}
export function IsOpaqueFilter() {
// bcz: isTransparent(__value__) is a hack. it would be nice to have acual functions be parsed, but now Doc.matchFieldValue is hardwired to recognize just this one
- return `backgroundColor:${isTransparentFunctionHack},${noRecursionHack}:x`; // bcz: hack. noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field
+ return `backgroundColor::${isTransparentFunctionHack},${noRecursionHack}::x`; // bcz: hack. noRecursion should probably be either another ':' delimited field, or it should be a modifier to the comparision (eg., check, x, etc) field
}
export function IsPropUnsetFilter(prop: string) {
- return `${prop}:any,${noRecursionHack}:unset`;
+ return `${prop}::any,${noRecursionHack}::unset`;
}
export function toRGBAstr(col: { r: number; g: number; b: number; a?: number }) {
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index acd323eca..934803c16 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -172,6 +172,7 @@ export class DocumentOptions {
'acl-Public'?: string; // public permissions
'_acl-Public'?: string; // public permissions
type?: DTYPEt = new DTypeInfo('type of document', true);
+ type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
_type_collection?: COLLt = new CTypeInfo('how collection is rendered'); // sub type of a collection
title?: STRt = new StrInfo('title of document');
caption?: RichTextField;
@@ -1156,7 +1157,7 @@ export namespace Docs {
}
export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, _type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeViewFreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id);
}
export function DirectoryImportDocument(options: DocumentOptions = {}) {
@@ -1213,7 +1214,7 @@ export namespace DocUtils {
const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
childFilters.forEach(filter => {
- const fields = filter.split(':');
+ const fields = filter.split(Doc.FilterSep);
const key = fields[0];
const value = fields[1];
const modifiers = fields[2];
@@ -1231,7 +1232,7 @@ export namespace DocUtils {
return false;
}
- for (const facetKey of Object.keys(filterFacets).filter(fkey => fkey !== 'cookies' && fkey !== Utils.noDragsDocFilter.split(':')[0])) {
+ for (const facetKey of Object.keys(filterFacets).filter(fkey => fkey !== 'cookies' && fkey !== Utils.noDragsDocFilter.split(Doc.FilterSep)[0])) {
const facet = filterFacets[facetKey];
// facets that match some value in the field of the document (e.g. some text field)
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7e3302067..3f0848d00 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -25,7 +25,13 @@ export class DocumentManager {
@observable public RecordingEvent = 0;
@observable public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = [];
@computed public get DocumentViews() {
- return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox));
+ return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath)));
+ }
+ public AddDocumentView(dv: DocumentView) {
+ this._documentViews.add(dv);
+ }
+ public DeleteDocumentView(dv: DocumentView) {
+ this._documentViews.delete(dv);
}
private static _instance: DocumentManager;
@@ -83,7 +89,7 @@ export class DocumentManager {
// this.LinkedDocumentViews.forEach(view => console.log(" LV = " + view.a.props.Document.title + "/" + view.a.props.LayoutTemplateString + " --> " +
// view.b.props.Document.title + "/" + view.b.props.LayoutTemplateString));
} else {
- this._documentViews.add(view);
+ this.AddDocumentView(view);
}
this.callAddViewFuncs(view);
};
@@ -101,7 +107,7 @@ export class DocumentManager {
const index = this.LinkAnchorBoxViews.indexOf(view);
this.LinkAnchorBoxViews.splice(index, 1);
} else {
- this._documentViews.delete(view);
+ this.DeleteDocumentView(view);
}
SelectionManager.DeselectView(view);
});
@@ -228,7 +234,7 @@ export class DocumentManager {
public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => {
const docViewPath = targetDocView.docViewPath.slice();
let rootContextView = docViewPath.shift();
- await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined })));
+ await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false })));
if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden;
else if (options.openLocation?.startsWith(OpenWhere.toggle) && !options.didMove && rootContextView) DocumentViewInternal.addDocTabFunc(rootContextView.rootDoc, options.openLocation);
};
@@ -242,7 +248,7 @@ export class DocumentManager {
public showDocument = async (
targetDoc: Doc, // document to display
options: DocFocusOptions, // options for how to navigate to target
- finished?: () => void
+ finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
) => {
const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
@@ -269,22 +275,29 @@ export class DocumentManager {
docContextPath.shift();
const childViewIterator = async (docView: DocumentView) => {
const innerDoc = docContextPath.shift();
- return { viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined };
+ return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined };
};
+
if (rootContextView) {
const target = await this.focusViewsInPath(rootContextView, options, childViewIterator);
this.restoreDocView(target.viewSpec, target.docView, options, target.contextView ?? target.docView, targetDoc);
- }
- finished?.();
+ finished?.(target.focused);
+ } else finished?.(false);
};
- focusViewsInPath = async (docView: DocumentView, options: DocFocusOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView> }>) => {
+ focusViewsInPath = async (
+ docView: DocumentView, //
+ options: DocFocusOptions,
+ iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView>; focused: boolean }>
+ ) => {
let contextView: DocumentView | undefined; // view containing context that contains target
+ let focused = false;
while (true) {
docView.rootDoc.layout_fieldKey === 'layout_icon' ? await new Promise<void>(res => docView.iconify(res)) : undefined;
- docView.props.focus(docView.rootDoc, options); // focus the view within its container
+ const nextFocus = docView.props.focus(docView.rootDoc, options); // focus the view within its container
+ focused = focused || (nextFocus === undefined ? false : true); // keep track of whether focusing on a view needed to actually change anything
const { childDocView, viewSpec } = await iterator(docView);
- if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView };
+ if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView, focused };
contextView = docView;
docView = childDocView;
}
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index d91c17545..1a7a4d342 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -347,7 +347,8 @@ export class DashboardView extends React.Component {
},
],
};
- Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true);
+ if (dashboard.dockingConfig && dashboard.dockingConfig !== Doc.GetProto(dashboard).dockingConfig) dashboard.dockingConfig = JSON.stringify(reset);
+ else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true);
return reset;
};
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 3de40a640..70d208a0b 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -173,7 +173,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
}
const first = doc instanceof Doc ? doc : doc[0];
if (!first?._dragOnlyWithinContainer && addDocument !== returnFalse) {
- return this.removeDocument(doc, annotationKey, true) && addDocument(doc, annotationKey);
+ return this.removeDocument(doc, annotationKey, false) && addDocument(doc, annotationKey);
}
return false;
};
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 35b0b22a8..16f5ad168 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -464,6 +464,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
action(() => {
this._isRecording = false;
this._stopFunc();
+ b.end();
}),
emptyFunction
);
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 41ce08d3c..3f71111e3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -916,7 +916,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
}}>
{this._isRotating ? null : (
<Tooltip enterDelay={750} title={<div className="dash-tooltip">tap to set rotate center, drag to rotate</div>}>
- <div className="documentDecorations-rotation" style={{ pointerEvents: 'all' }} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}>
+ <div className="documentDecorations-rotation" style={{ pointerEvents: 'all', color: 'blue' }} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}>
<IconButton icon={<FaUndo />} color={Colors.LIGHT_GRAY} />
</div>
</Tooltip>
diff --git a/src/client/views/FilterPanel.tsx b/src/client/views/FilterPanel.tsx
index fe42628cd..a5c18cd8b 100644
--- a/src/client/views/FilterPanel.tsx
+++ b/src/client/views/FilterPanel.tsx
@@ -71,7 +71,7 @@ export class FilterPanel extends React.Component<filterProps> {
* @returns a string array of the current attributes
*/
@computed get currentFacets() {
- return this.activeFilters.map(filter => filter.split(':')[0]);
+ return this.activeFilters.map(filter => filter.split(Doc.FilterSep)[0]);
}
gatherFieldValues(childDocs: Doc[], facetKey: string) {
@@ -108,8 +108,8 @@ export class FilterPanel extends React.Component<filterProps> {
@observable _chosenFacets = new ObservableMap<string, 'text' | 'checkbox' | 'slider' | 'range'>();
@computed get activeFacets() {
const facets = new Map<string, 'text' | 'checkbox' | 'slider' | 'range'>(this._chosenFacets);
- StrListCast(this.targetDoc?._childFilters).map(filter => facets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'));
- setTimeout(() => StrListCast(this.targetDoc?._childFilters).map(action(filter => this._chosenFacets.set(filter.split(':')[0], filter.split(':')[2] === 'match' ? 'text' : 'checkbox'))));
+ StrListCast(this.targetDoc?._childFilters).map(filter => facets.set(filter.split(Doc.FilterSep)[0], filter.split(Doc.FilterSep)[2] === 'match' ? 'text' : 'checkbox'));
+ setTimeout(() => StrListCast(this.targetDoc?._childFilters).map(action(filter => this._chosenFacets.set(filter.split(Doc.FilterSep)[0], filter.split(Doc.FilterSep)[2] === 'match' ? 'text' : 'checkbox'))));
return facets;
}
/**
@@ -203,8 +203,8 @@ export class FilterPanel extends React.Component<filterProps> {
<input
placeholder={
StrListCast(this.targetDoc._childFilters)
- .find(filter => filter.split(':')[0] === facetHeader)
- ?.split(':')[1] ?? '-empty-'
+ .find(filter => filter.split(Doc.FilterSep)[0] === facetHeader)
+ ?.split(Doc.FilterSep)[1] ?? '-empty-'
}
onBlur={undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match'), 'set text filter')}
onKeyDown={e => e.key === 'Enter' && undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, e.currentTarget.value, !e.currentTarget.value ? 'remove' : 'match'), 'set text filter')(e)}
@@ -219,8 +219,8 @@ export class FilterPanel extends React.Component<filterProps> {
style={{ width: 20, marginLeft: 20 }}
checked={
StrListCast(this.targetDoc._childFilters)
- .find(filter => filter.split(':')[0] === facetHeader && filter.split(':')[1] == facetValue)
- ?.split(':')[2] === 'check'
+ .find(filter => filter.split(Doc.FilterSep)[0] === facetHeader && filter.split(Doc.FilterSep)[1] == facetValue)
+ ?.split(Doc.FilterSep)[2] === 'check'
}
type={type}
onChange={undoable(e => Doc.setDocFilter(this.targetDoc, facetHeader, fval, e.target.checked ? 'check' : 'remove'), 'set filter')}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 0af9bfed2..96502115d 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -134,7 +134,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
return undefined;
case StyleProp.DocContents:return undefined;
case StyleProp.WidgetColor:return isAnnotated ? Colors.LIGHT_BLUE : darkScheme() ? 'lightgrey' : 'dimgrey';
- case StyleProp.Opacity: return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null));
+ case StyleProp.Opacity: return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.textInlineAnnotations ? 0 : Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null));
case StyleProp.HideLinkBtn:return props?.hideLinkButton || (!selected && doc?.layout_hideLinkButton);
case StyleProp.FontSize: return StrCast(doc?.[fieldKey + 'fontSize'], StrCast(doc?._text_fontSize, StrCast(Doc.UserDoc().fontSize)));
case StyleProp.FontFamily: return StrCast(doc?.[fieldKey + 'fontFamily'], StrCast(doc?._text_fontFamily, StrCast(Doc.UserDoc().fontFamily)));
@@ -228,7 +228,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
? '#00000010' // faint interior for collections on PDFs, images, etc
: doc?._isGroup
? undefined
- : Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : 'linear-gradient(#065fff, #85c1f9)'));
+ : doc._type_collection === CollectionViewType.Stacking ?
+ (darkScheme() ? Colors.MEDIUM_GRAY : Colors.DARK_GRAY)
+ : Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : Colors.MEDIUM_GRAY));
break;
//if (doc._type_collection !== CollectionViewType.Freeform && doc._type_collection !== CollectionViewType.Time) return "rgb(62,62,62)";
default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE);
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 78e44dfa2..4c15d5eed 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -15,6 +15,12 @@
cursor: grab;
color: $black;
}
+.collectiondockingview-container .lm_splitter {
+ opacity: 0.2;
+ &:hover {
+ opacity: 1;
+ }
+}
.lm_title.focus-visible {
-webkit-appearance: none;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index a5d7e7864..2ed55b3ca 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -29,6 +29,7 @@ import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
import { TabDocView } from './TabDocView';
import React = require('react');
+import { DocumentManager } from '../../util/DocumentManager';
const _global = (window /* browser */ || global) /* node */ as any;
@observer
@@ -359,6 +360,7 @@ export class CollectionDockingView extends CollectionSubView() {
} catch (e) {}
this._goldenLayout?.destroy();
window.removeEventListener('resize', this.onResize);
+ window.removeEventListener('mouseup', this.onPointerUp);
this._reactionDisposer?.();
this._lightboxReactionDisposer?.();
@@ -409,7 +411,14 @@ export class CollectionDockingView extends CollectionSubView() {
if (!htmlTarget.closest('*.lm_content') && (htmlTarget.closest('*.lm_tab') || htmlTarget.closest('*.lm_stack'))) {
const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : '';
if (className.includes('lm_maximise')) this._flush = UndoManager.StartBatch('tab maximize');
- else if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE();
+ else {
+ const tabTarget = (e.target as HTMLElement)?.parentElement?.className.includes('lm_tab') ? (e.target as HTMLElement).parentElement : (e.target as HTMLElement);
+ const map = Array.from(this.tabMap).find(tab => tab.element[0] === tabTarget);
+ if (map?.DashDoc && DocumentManager.Instance.getFirstDocumentView(map.DashDoc)) {
+ SelectionManager.SelectView(DocumentManager.Instance.getFirstDocumentView(map.DashDoc), false);
+ }
+ if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE();
+ }
}
}
if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index f1c4c2cdf..53a42d2a6 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -47,7 +47,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
@observable _cursor: CursorProperty = 'grab';
@observable _scroll = 0;
@computed get chromeHidden() {
- return BoolCast(this.layoutDoc.chromeHidden);
+ return BoolCast(this.layoutDoc.chromeHidden) || this.props.onBrowseClick?.() ? true : false;
}
// columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns
@computed get colHeaderData() {
@@ -192,7 +192,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
if (found) {
const top = found.getBoundingClientRect().top;
const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
- if (Math.floor(localTop[1]) !== 0) {
+ if (Math.floor(localTop[1]) !== 0 && Math.ceil(this.props.PanelHeight()) < (this._mainCont?.scrollHeight || 0)) {
let focusSpeed = options.zoomTime ?? 500;
smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
return focusSpeed;
@@ -252,6 +252,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
layout_showTitle={this.props.childlayout_showTitle}
dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
+ onBrowseClick={this.props.onBrowseClick}
onDoubleClick={this.onChildDoubleClickHandler}
ScreenToLocalTransform={noteTakingDocTransform}
focus={this.focusDocument}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4756b4cd3..ec529afc3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -31,6 +31,7 @@ import { CollectionMasonryViewFieldRow } from './CollectionMasonryViewFieldRow';
import './CollectionStackingView.scss';
import { CollectionStackingViewFieldColumn } from './CollectionStackingViewFieldColumn';
import { CollectionSubView } from './CollectionSubView';
+import { Colors } from '../global/globalEnums';
const _global = (window /* browser */ || global) /* node */ as any;
export type collectionStackingViewProps = {
@@ -84,7 +85,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
return this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.HeaderMargin);
}
@computed get xMargin() {
- return NumCast(this.layoutDoc._xMargin, Math.min(3, 0.05 * this.props.PanelWidth()));
+ return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this.props.PanelWidth()));
}
@computed get yMargin() {
return this.props.yPadding || NumCast(this.layoutDoc._yMargin, Math.min(5, 0.05 * this.props.PanelWidth()));
@@ -137,7 +138,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
// assuming we need to get rowSpan because we might be dealing with many columns. Grid gap makes sense if multiple columns
const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
// just getting the style
- const style = this.isStackingView ? { width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
+ const style = this.isStackingView ? { background: Colors.MEDIUM_GRAY, width: width(), marginTop: i ? this.gridGap : 0, height: height() } : { gridRowEnd: `span ${rowSpan}` };
// So we're choosing whether we're going to render a column or a masonry doc
return (
<div className={`collectionStackingView-${this.isStackingView ? 'columnDoc' : 'masonryDoc'}`} key={d[Id]} style={style}>
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 39fb2db1e..c189ef126 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -205,7 +205,7 @@ export function CollectionSubView<X>(moreProps?: X) {
protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
const docDragData = de.complete.docDragData;
if (docDragData) {
- let added = false;
+ let added = undefined;
const dropAction = docDragData.dropAction || docDragData.userDropAction;
const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]);
const someMoved = !dropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag));
@@ -215,7 +215,8 @@ export function CollectionSubView<X>(moreProps?: X) {
const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
if (movedDocs.length) {
const canAdd = de.embedKey || dropAction || Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.rootDoc);
- added = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse);
+ const moved = docDragData.moveDocument(movedDocs, this.rootDoc, canAdd ? this.addDocument : returnFalse);
+ added = canAdd || moved ? moved : undefined;
} else {
ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
added = addedDocs.length ? this.addDocument(addedDocs) : true;
@@ -225,11 +226,10 @@ export function CollectionSubView<X>(moreProps?: X) {
added = this.addDocument(docDragData.droppedDocuments);
!added && alert('You cannot perform this move');
}
- !added && e.preventDefault();
- e.stopPropagation();
- return added;
+ added === false && !this.props.isAnnotationOverlay && e.preventDefault();
+ added === true && e.stopPropagation();
+ return added ? true : false;
} else if (de.complete.annoDragData) {
- e.stopPropagation();
const dropCreator = de.complete.annoDragData.dropDocCreator;
de.complete.annoDragData.dropDocCreator = () => {
const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 97d4d989b..4d780f46b 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -2,7 +2,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
import { clamp } from 'lodash';
-import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, observable, ObservableSet, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as ReactDOM from 'react-dom/client';
import { Doc, Opt } from '../../../fields/Doc';
@@ -43,12 +43,21 @@ interface TabDocViewProps {
}
@observer
export class TabDocView extends React.Component<TabDocViewProps> {
+ static _allTabs = new ObservableSet<TabDocView>();
_mainCont: HTMLDivElement | null = null;
_tabReaction: IReactionDisposer | undefined;
@observable _activated: boolean = false;
@observable _panelWidth = 0;
@observable _panelHeight = 0;
+ @observable _hovering = false;
@observable _isActive: boolean = false;
+ @observable _isAnyChildContentActive = false;
+ @computed get _isUserActivated() {
+ return SelectionManager.Views().some(view => view.rootDoc === this._document) || this._isAnyChildContentActive;
+ }
+ @computed get _isContentActive() {
+ return this._isUserActivated || this._hovering;
+ }
@observable _document: Doc | undefined;
@observable _view: DocumentView | undefined;
@@ -61,9 +70,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
return 'transparent';
}
@computed get tabColor() {
- let tabColor = StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor)));
- if (tabColor === 'transparent') return 'black';
- return tabColor;
+ return this._isUserActivated ? Colors.WHITE : this._hovering ? Colors.LIGHT_GRAY : Colors.MEDIUM_GRAY;
}
@computed get tabTextColor() {
return this._document?.type === DocumentType.PRES ? 'black' : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color)));
@@ -191,7 +198,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
});
tab._disposers.selectionDisposer = reaction(
- () => SelectionManager.Views().some(v => v.topMost && v.props.Document === doc),
+ () => SelectionManager.Views().some(view => view.rootDoc === this._document),
action(selected => {
if (selected) this._activated = true;
const toggle = tab.element[0].children[2].children[0] as HTMLInputElement;
@@ -305,6 +312,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
}
+ @action
componentDidMount() {
new _global.ResizeObserver(
action((entries: any) => {
@@ -319,14 +327,17 @@ export class TabDocView extends React.Component<TabDocViewProps> {
// this._tabReaction = reaction(() => ({ selected: this.active(), title: this.tab?.titleElement[0] }),
// ({ selected, title }) => title && (title.style.backgroundColor = selected ? "white" : ""),
// { fireImmediately: true });
+ TabDocView._allTabs.add(this);
}
componentDidUpdate() {
this._view && DocumentManager.Instance.AddView(this._view);
}
+ @action
componentWillUnmount() {
this._tabReaction?.();
this._view && DocumentManager.Instance.RemoveView(this._view);
+ TabDocView._allTabs.delete(this);
this.props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged);
}
@@ -335,6 +346,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
private onActiveContentItemChanged(contentItem: any) {
if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) {
this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab;
+ if (!this._view) setTimeout(() => SelectionManager.SelectView(this._view, false));
!this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
}
}
@@ -404,11 +416,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
};
PanelWidth = () => this._panelWidth;
PanelHeight = () => this._panelHeight;
- miniMapColor = () => this.tabColor;
+ miniMapColor = () => Colors.MEDIUM_GRAY;
tabView = () => this._view;
disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._type_collection !== CollectionViewType.Freeform;
- hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.layout_hideMinimap);
-
+ whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive);
+ isContentActive = () => this._isContentActive;
@computed get docView() {
return !this._activated || !this._document ? null : (
<>
@@ -426,7 +438,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
DataDoc={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
onBrowseClick={MainView.Instance.exploreMode}
waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
- isContentActive={returnTrue}
+ isContentActive={this.isContentActive}
isDocumentActive={returnFalse}
PanelWidth={this.PanelWidth}
PanelHeight={this.PanelHeight}
@@ -440,30 +452,15 @@ export class TabDocView extends React.Component<TabDocViewProps> {
ScreenToLocalTransform={this.ScreenToLocalTransform}
dontCenter={'y'}
rootSelected={returnTrue}
- whenChildContentsActiveChanged={emptyFunction}
+ whenChildContentsActiveChanged={this.whenChildContentActiveChanges}
focus={this.focusFunc}
docViewPath={returnEmptyDoclist}
bringToFront={emptyFunction}
pinToPres={TabDocView.PinDoc}
/>
- <TabMinimapView key="minimap" hideMinimap={this.hideMinimap} addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />
- <Tooltip key="ttip" title={<div className="dash-tooltip">{this._document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}>
- <div
- className="miniMap-hidden"
- style={{
- display: this.disableMinimap() || this._document._type_collection !== 'freeform' ? 'none' : undefined,
- color: this._document.layout_hideMinimap ? Colors.BLACK : Colors.WHITE,
- backgroundColor: this._document.layout_hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
- boxShadow: this._document.layout_hideMinimap ? Shadows.STANDARD_SHADOW : undefined,
- }}
- onPointerDown={e => e.stopPropagation()}
- onClick={action(e => {
- e.stopPropagation();
- this._document!.layout_hideMinimap = !this._document!.layout_hideMinimap;
- })}>
- <FontAwesomeIcon icon={'globe-asia'} size="lg" />
- </div>
- </Tooltip>
+ {this.disableMinimap() || this._document._type_collection !== CollectionViewType.Freeform ? null : (
+ <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />
+ )}
</>
);
}
@@ -475,6 +472,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
style={{
fontFamily: Doc.UserDoc().renderStyle === 'comic' ? 'Comic Sans MS' : undefined,
}}
+ onPointerEnter={action(() => (this._hovering = true))}
+ onPointerLeave={action(() => (this._hovering = false))}
+ onDragOver={action(() => (this._hovering = true))}
+ onDragLeave={action(() => (this._hovering = false))}
ref={ref => {
if ((this._mainCont = ref)) {
if (this._lastTab) {
@@ -494,7 +495,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
interface TabMinimapViewProps {
document: Doc;
- hideMinimap: () => boolean;
tabView: () => DocumentView | undefined;
addDocTab: (doc: Doc, where: OpenWhere) => boolean;
PanelWidth: () => number;
@@ -569,46 +569,67 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
if (!this.renderBounds) return null;
const miniWidth = (this.props.PanelWidth() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100;
const miniHeight = (this.props.PanelHeight() / NumCast(this.props.document._freeform_scale, 1) / this.renderBounds.dim) * 100;
- const miniLeft = 50 + ((NumCast(this.props.document._freeform_) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2;
+ const miniLeft = 50 + ((NumCast(this.props.document._freeform_panX) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2;
const miniTop = 50 + ((NumCast(this.props.document._freeform_panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2;
const miniSize = this.returnMiniSize();
- return this.props.hideMinimap() ? null : (
- <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
- <CollectionFreeFormView
- Document={this.props.document}
- docViewPath={returnEmptyDoclist}
- childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
- noOverlay={true} // don't render overlay Docs since they won't scale
- setHeight={returnFalse}
- isContentActive={emptyFunction}
- isAnyChildContentActive={returnFalse}
- select={emptyFunction}
- isSelected={returnFalse}
- dontRegisterView={true}
- fieldKey={Doc.LayoutFieldKey(this.props.document)}
- bringToFront={emptyFunction}
- rootSelected={returnTrue}
- addDocument={returnFalse}
- moveDocument={returnFalse}
- removeDocument={returnFalse}
- PanelWidth={this.returnMiniSize}
- PanelHeight={this.returnMiniSize}
- ScreenToLocalTransform={Transform.Identity}
- renderDepth={0}
- whenChildContentsActiveChanged={emptyFunction}
- focus={emptyFunction}
- styleProvider={TabMinimapView.miniStyleProvider}
- addDocTab={this.props.addDocTab}
- pinToPres={TabDocView.PinDoc}
- childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
- childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
- searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
- fitContentsToBox={returnTrue}
- />
- <div className="miniOverlay" onPointerDown={this.miniDown}>
- <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} />
- </div>
- </div>
+ return (
+ <>
+ {' '}
+ {this.props.document?.layout_hideMinimap ? null : (
+ <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
+ <CollectionFreeFormView
+ Document={this.props.document}
+ docViewPath={returnEmptyDoclist}
+ childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
+ noOverlay={true} // don't render overlay Docs since they won't scale
+ setHeight={returnFalse}
+ isContentActive={emptyFunction}
+ isAnyChildContentActive={returnFalse}
+ select={emptyFunction}
+ isSelected={returnFalse}
+ dontRegisterView={true}
+ fieldKey={Doc.LayoutFieldKey(this.props.document)}
+ bringToFront={emptyFunction}
+ rootSelected={returnTrue}
+ addDocument={returnFalse}
+ moveDocument={returnFalse}
+ removeDocument={returnFalse}
+ PanelWidth={this.returnMiniSize}
+ PanelHeight={this.returnMiniSize}
+ ScreenToLocalTransform={Transform.Identity}
+ renderDepth={0}
+ whenChildContentsActiveChanged={emptyFunction}
+ focus={emptyFunction}
+ styleProvider={TabMinimapView.miniStyleProvider}
+ addDocTab={this.props.addDocTab}
+ pinToPres={TabDocView.PinDoc}
+ childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+ childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+ searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
+ fitContentsToBox={returnTrue}
+ />
+ <div className="miniOverlay" onPointerDown={this.miniDown}>
+ <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} />
+ </div>
+ </div>
+ )}
+ <Tooltip key="ttip" title={<div className="dash-tooltip">{this.props.document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}>
+ <div
+ className="miniMap-hidden"
+ style={{
+ color: this.props.document.layout_hideMinimap ? Colors.BLACK : Colors.WHITE,
+ backgroundColor: this.props.document.layout_hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
+ boxShadow: this.props.document.layout_hideMinimap ? Shadows.STANDARD_SHADOW : undefined,
+ }}
+ onPointerDown={e => e.stopPropagation()}
+ onClick={action(e => {
+ e.stopPropagation();
+ this.props.document!.layout_hideMinimap = !this.props.document!.layout_hideMinimap;
+ })}>
+ <FontAwesomeIcon icon="globe-asia" size="lg" />
+ </div>
+ </Tooltip>
+ </>
);
}
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e6f8f3071..ba31916a7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1053,7 +1053,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (this.layoutDoc._Transform || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
e.stopPropagation();
const docHeight = NumCast(this.rootDoc[Doc.LayoutFieldKey(this.rootDoc) + '_nativeHeight'], this.nativeHeight);
- const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling;
+ const scrollable = NumCast(this.layoutDoc[this.scaleFieldKey], 1) === 1 && docHeight > this.props.PanelHeight() / this.nativeDimScaling + 1e-4;
switch (!e.ctrlKey ? Doc.UserDoc().freeformScrollMode : freeformScrollMode.Pan) {
case freeformScrollMode.Pan:
// if ctrl is selected then zoom
@@ -2256,22 +2256,20 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor
export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY: number) {
const browseTransitionTime = 500;
SelectionManager.DeselectAll();
- if (
- dv.props.focus(dv.props.Document, {
- willZoomCentered: true,
- zoomScale: 0.8,
- zoomTime: browseTransitionTime,
- }) === undefined
- ) {
- const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
- let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
- while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
- const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview
- ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime);
- Doc.linkFollowHighlight(dv?.props.Document, false);
- } else {
- DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true });
- }
+ DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
+ if (!focused) {
+ const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
+ let containers = dv.props.docViewPath();
+ let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+ for (var cont of containers) {
+ parFfview = parFfview ?? cont.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+ }
+ while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+ const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it. Otherwise, zoom out on the parent ffview
+ ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime);
+ Doc.linkFollowHighlight(dv?.props.Document, false);
+ }
+ });
}
ScriptingGlobals.add(CollectionBrowseClick);
ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
index 821c8d804..f87a06033 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss
@@ -8,6 +8,11 @@
display: flex;
flex-direction: column;
width: 100%;
+ align-items: center;
+
+ .contentFittingDocumentView {
+ width: unset;
+ }
.label-wrapper {
display: flex;
@@ -15,7 +20,6 @@
justify-content: center;
height: 20px;
}
-
}
.multiColumnResizer {
@@ -30,5 +34,4 @@
transition: 0.5s background-color ease;
}
}
-
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 6dcd2d422..10532b9d9 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -238,7 +238,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
? true
: undefined;
};
- getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
+ getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => {
return (
<DocumentView
Document={layout}
@@ -250,6 +250,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
renderDepth={this.props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
+ shouldNotScale={shouldNotScale}
rootSelected={this.rootSelected}
dragAction={(this.props.Document.childDragAction ?? this.props.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
@@ -287,15 +288,19 @@ export class CollectionMulticolumnView extends CollectionSubView() {
const collector: JSX.Element[] = [];
for (let i = 0; i < childLayoutPairs.length; i++) {
const { layout } = childLayoutPairs[i];
+ const aspect = Doc.NativeAspect(layout, undefined, true);
+ const width = () => this.lookupPixels(layout);
+ const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
+ const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(height() * aspect, width()));
+ const docheight = () => Math.min(docwidth() / aspect, height());
const dxf = () =>
this.lookupIndividualTransform(layout)
- .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin))
+ .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin))
.scale(this.props.NativeDimScaling?.() || 1);
- const width = () => this.lookupPixels(layout);
- const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
+ const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox);
collector.push(
- <div className={'document-wrapper'} key={'wrapper' + i} style={{ width: width() }}>
- {this.getDisplayDoc(layout, dxf, width, height)}
+ <div className="document-wrapper" key={'wrapper' + i} style={{ width: width() }}>
+ {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)}
<WidthLabel layout={layout} collectionDoc={Document} />
</div>,
<ResizeBar
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
index 79fb195e8..ec7200a03 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss
@@ -9,6 +9,12 @@
display: flex;
flex-direction: row;
height: 100%;
+ align-items: center;
+ margin: auto;
+
+ .contentFittingDocumentView {
+ height: unset;
+ }
.label-wrapper {
display: flex;
@@ -16,7 +22,6 @@
justify-content: center;
height: 20px;
}
-
}
.multiRowResizer {
@@ -31,5 +36,4 @@
transition: 0.5s background-color ease;
}
}
-
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4df5dad5a..04cfc5456 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -238,7 +238,7 @@ export class CollectionMultirowView extends CollectionSubView() {
? true
: undefined;
};
- getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
+ getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number, shouldNotScale: () => boolean) => {
return (
<DocumentView
Document={layout}
@@ -250,6 +250,7 @@ export class CollectionMultirowView extends CollectionSubView() {
renderDepth={this.props.renderDepth + 1}
PanelWidth={width}
PanelHeight={height}
+ shouldNotScale={shouldNotScale}
rootSelected={this.rootSelected}
dropAction={StrCast(this.rootDoc.childDragAction) as dropActionType}
onClick={this.onChildClickHandler}
@@ -287,15 +288,19 @@ export class CollectionMultirowView extends CollectionSubView() {
const collector: JSX.Element[] = [];
for (let i = 0; i < childLayoutPairs.length; i++) {
const { layout } = childLayoutPairs[i];
+ const aspect = Doc.NativeAspect(layout, undefined, true);
+ const height = () => this.lookupPixels(layout);
+ const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
+ const docheight = () => Math.min(width() / aspect, height());
+ const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(width(), docheight() * aspect));
const dxf = () =>
this.lookupIndividualTransform(layout)
- .translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin))
+ .translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin) - (height() - docheight()) / 2)
.scale(this.props.NativeDimScaling?.() || 1);
- const height = () => this.lookupPixels(layout);
- const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
+ const shouldNotScale = () => this.props.fitContentsToBox?.() || BoolCast(layout.freeform_fitContentsToBox);
collector.push(
- <div className={'document-wrapper'} style={{ height: height() }} key={'wrapper' + i}>
- {this.getDisplayDoc(layout, dxf, width, height)}
+ <div className="document-wrapper" style={{ height: height() }} key={'wrapper' + i}>
+ {this.getDisplayDoc(layout, dxf, docwidth, docheight, shouldNotScale)}
<HeightLabel layout={layout} collectionDoc={Document} />
</div>,
<ResizeBar
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 0fe24fe8d..d548ab9f1 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -71,13 +71,14 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => {
- const anchor =
- this._chartRenderer?.getAnchor(pinProps) ??
- Docs.Create.ConfigDocument({
- // when we clear selection -> we should have it so chartBox getAnchor returns undefined
- // this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker)
- /*put in some options*/
- });
+ const anchor = !pinProps
+ ? this.rootDoc
+ : this._chartRenderer?.getAnchor(pinProps) ??
+ Docs.Create.ConfigDocument({
+ // when we clear selection -> we should have it so chartBox getAnchor returns undefined
+ // this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker)
+ /*put in some options*/
+ });
anchor.presDataVizView = this.dataVizView;
anchor.presDataVizAxes = this.axes.length ? new List<string>(this.axes) : undefined;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6b37dc419..8a35ca2a4 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -561,6 +561,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (!Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, Date.now())) {
this.cleanupPointerEvents();
+ this._longPressSelector && clearTimeout(this._longPressSelector);
this.startDragging(this._downX, this._downY, ((e.ctrlKey || e.altKey) && 'embed') || ((this.Document.dragAction || this.props.dragAction || undefined) as dropActionType));
}
};
@@ -728,6 +729,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layout_fieldKey)], Doc, null);
const appearance = cm.findByDescription('UI Controls...');
const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : [];
+
+ if (this.props.renderDepth === 0) {
+ appearanceItems.push({ description: 'Open in Lightbox', event: () => LightboxView.SetLightboxDoc(this.rootDoc), icon: 'hand-point-right' });
+ }
!Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
!appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
@@ -900,8 +905,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
};
childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
- /// disable pointer events on content when there's an enabled onClick script, or if contents are marked inactive
- contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler) || this.isContentActive() === false ? 'none' : this.pointerEvents);
+ /// disable pointer events on content when there's an enabled onClick script (but not the browse script), or if contents are marked inactive
+ contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler && !this.props.onBrowseClick?.()) || this.isContentActive() === false ? 'none' : this.pointerEvents);
+
@computed get contents() {
TraceMobx();
const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index f67930a3f..909a420fe 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -135,7 +135,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
@action
drop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.docDragData) {
- let added = true;
+ let added: boolean | undefined = undefined;
const targetIsBullseye = (ele: HTMLElement): boolean => {
if (!ele) return false;
if (ele === this._overlayIconRef.current) return true;
@@ -156,8 +156,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
}
}
- !added && e.preventDefault();
- e.stopPropagation();
+ added === false && e.preventDefault();
+ added !== undefined && e.stopPropagation();
return added;
}
return false;
@@ -170,14 +170,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
setNativeSize = action(() => {
const scaling = (this.props.DocumentView?.().props.ScreenToLocalTransform().Scale || 1) / NumCast(this.rootDoc._freeform_scale, 1);
const nscale = NumCast(this.props.PanelWidth()) / scaling;
- const nh = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']);
const nw = nscale / NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
- this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nh;
- this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nh;
- this.rootDoc._freeform_panX = nh * NumCast(this.rootDoc._freeform_panX);
- this.rootDoc._freeform_panY = nh * NumCast(this.rootDoc._freeform_panY);
- this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nh * NumCast(this.dataDoc._freeform_panXMax) : undefined;
- this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nh * NumCast(this.dataDoc._freeform_panXMin) : undefined;
+ this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw;
+ this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw;
+ this.rootDoc._freeform_panX = nw * NumCast(this.rootDoc._freeform_panX);
+ this.rootDoc._freeform_panY = nw * NumCast(this.rootDoc._freeform_panY);
+ this.dataDoc._freeform_panXMax = this.dataDoc._freeform_panXMax ? nw * NumCast(this.dataDoc._freeform_panXMax) : undefined;
+ this.dataDoc._freeform_panXMin = this.dataDoc._freeform_panXMin ? nw * NumCast(this.dataDoc._freeform_panXMin) : undefined;
this.dataDoc._freeform_panYMax = this.dataDoc._freeform_panYMax ? nw * NumCast(this.dataDoc._freeform_panYMax) : undefined;
this.dataDoc._freeform_panYMin = this.dataDoc._freeform_panYMin ? nw * NumCast(this.dataDoc._freeform_panYMin) : undefined;
});
diff --git a/src/client/views/nodes/button/FontIconBox.scss b/src/client/views/nodes/button/FontIconBox.scss
index f3b43501b..9d9fa26b0 100644
--- a/src/client/views/nodes/button/FontIconBox.scss
+++ b/src/client/views/nodes/button/FontIconBox.scss
@@ -18,7 +18,7 @@
.fontIconBox-label {
color: $white;
- bottom: 0;
+ bottom: -1;
position: absolute;
text-align: center;
font-size: 7px;
@@ -27,7 +27,7 @@
border-radius: 8px;
padding: 0;
width: 100%;
- font-family: 'ROBOTO';
+ font-family: 'system-ui';
text-transform: uppercase;
font-weight: bold;
transition: 0.15s;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index da0fc9ffb..44cb56d53 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -879,11 +879,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
const optionItems = options && 'subitems' in options ? options.subitems : [];
optionItems.push({ description: `Generate Dall-E Image`, event: () => this.generateImage(), icon: 'star' });
optionItems.push({ description: `Ask GPT-3`, event: () => this.askGPT(), icon: 'lightbulb' });
- optionItems.push({
- description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
- event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
- icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
- });
+ this.props.renderDepth &&
+ optionItems.push({
+ description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
+ event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
+ icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
+ });
!Doc.noviceMode &&
optionItems.push({
description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`,
@@ -1520,8 +1521,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
} else if (curText && !FormattedTextBox.DontSelectInitialText) {
selectAll(this._editorView.state, this._editorView?.dispatch);
- } else {
- this._editorView.dispatch(this._editorView.state.tr.addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
}
}
selectOnLoad && this._editorView!.focus();
@@ -1534,7 +1533,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
this._editorView.dispatch(
this._editorView.state.tr.setStoredMarks([
...(this._editorView.state.storedMarks ?? []),
- ...(!this._editorView.state.storedMarks?.some(mark => mark.type === schema.marks.user_mark) ? [schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })] : []),
+ ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })],
...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []),
...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []),
...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []),
@@ -1555,6 +1554,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
componentWillUnmount() {
Object.values(this._disposers).forEach(disposer => disposer?.());
this.endUndoTypingBatch();
+ FormattedTextBox.LiveTextUndo?.end();
+ FormattedTextBox.LiveTextUndo = undefined;
this.unhighlightSearchTerms();
this._editorView?.destroy();
RichTextMenu.Instance?.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
@@ -2079,7 +2080,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
style={{
overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
- pointerEvents: Doc.ActiveTool === InkTool.None ? undefined : 'none',
+ pointerEvents: Doc.ActiveTool === InkTool.None && !this.props.onBrowseClick?.() ? undefined : 'none',
}}
onContextMenu={this.specificContextMenu}
onKeyDown={this.onKeyDown}
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 470aa3eb1..cfe07f6cb 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -26,15 +26,9 @@
.textLayer {
opacity: unset;
mix-blend-mode: multiply; // bcz: makes text fuzzy!
-
- // span {
- // padding-right: 5px;
- // padding-bottom: 4px;
- // }
}
-
.textLayer ::selection {
- background: #accef7;
+ background: #accef76a;
}
// should match the backgroundColor in createAnnotation()
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 8f6b8cd41..0fd93868a 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -488,14 +488,12 @@ export class PDFViewer extends React.Component<IViewerProps> {
? 'all' //
: 'none';
@computed get annotationLayer() {
+ const inlineAnnos = this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).filter(anno => !anno.hidden);
return (
<div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}>
- {this.inlineTextAnnotations
- .sort((a, b) => NumCast(a.y) - NumCast(b.y))
- .filter(anno => !anno.hidden)
- .map(anno => (
- <Annotation {...this.props} fieldKey={this.props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />
- ))}
+ {inlineAnnos.map(anno => (
+ <Annotation {...this.props} fieldKey={this.props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />
+ ))}
</div>
);
}
@@ -560,7 +558,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
</div>
);
@computed get overlayTransparentAnnotations() {
- return this.renderAnnotations(this.transparentFilter, 'multiply', DragManager.docsBeingDragged.length && this.props.isContentActive() ? 'none' : undefined);
+ const transparentChildren = DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '_annotations']), this.transparentFilter(), []);
+ return !transparentChildren.length ? null : this.renderAnnotations(this.transparentFilter, 'multiply', DragManager.docsBeingDragged.length && this.props.isContentActive() ? 'none' : undefined);
}
@computed get overlayOpaqueAnnotations() {
return this.renderAnnotations(this.opaqueFilter, this.allAnnotations.some(anno => anno.mixBlendMode) ? 'hard-light' : undefined);
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index c9f7e4114..f13dab68c 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1430,6 +1430,8 @@ export namespace Doc {
}
}
+ export const FilterSep = '::';
+
// filters document in a container collection:
// all documents with the specified value for the specified key are included/excluded
// based on the modifiers :"check", "x", undefined
@@ -1439,7 +1441,7 @@ export namespace Doc {
const childFilters = StrListCast(container[filterField]);
runInAction(() => {
for (let i = 0; i < childFilters.length; i++) {
- const fields = childFilters[i].split(':'); // split key:value:modifier
+ const fields = childFilters[i].split(FilterSep); // split key:value:modifier
if (fields[0] === key && (fields[1] === value || modifiers === 'match' || (fields[2] === 'match' && modifiers === 'remove'))) {
if (fields[2] === modifiers && modifiers && fields[1] === value) {
if (toggle) modifiers = 'remove';
@@ -1454,7 +1456,7 @@ export namespace Doc {
container[filterField] = undefined;
} else if (modifiers !== 'remove') {
!append && (childFilters.length = 0);
- childFilters.push(key + ':' + value + ':' + modifiers);
+ childFilters.push(key + FilterSep + value + FilterSep + modifiers);
container[filterField] = new List<string>(childFilters);
}
});
diff --git a/src/fields/util.ts b/src/fields/util.ts
index e439768ee..0f164a709 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -34,9 +34,8 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number
return true;
}
- if (value !== undefined) {
- value = value[SelfProxy] || value;
- }
+ value = value?.[SelfProxy] ?? value; // convert any Doc type values to Proxy's
+
const curValue = target.__fieldTuples[prop];
if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) {
// TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically