aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-08-23 15:23:07 -0400
committerbobzel <zzzman@gmail.com>2024-08-23 15:23:07 -0400
commitac580dab29fc5867680a54b2fbfd68f9d4e2a895 (patch)
tree0d4e286f626c90ecaaa08e788510c6e618fac48d
parentdc7bb2ff07139c45efd3bf66ace0042b76c91ccf (diff)
changed keyword items to use a doc symbol for storage instead of a field. fixed sizing of docDecoartions around keyeword box to dynaically update accurately. Aded expand/collapse button for editing keywords
-rw-r--r--src/client/views/DocumentDecorations.tsx4
-rw-r--r--src/client/views/KeywordBox.tsx91
-rw-r--r--src/client/views/StyleProvider.scss5
-rw-r--r--src/client/views/StyleProvider.tsx2
-rw-r--r--src/fields/Doc.ts4
-rw-r--r--src/fields/DocSymbols.ts3
6 files changed, 47 insertions, 62 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index ce1138b7a..19c4a097b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -9,7 +9,7 @@ import { lightOrDark, returnFalse, setupMoveUpEvents } from '../../ClientUtils';
import { Utils, emptyFunction, numberValue } from '../../Utils';
import { DateField } from '../../fields/DateField';
import { Doc, DocListCast, Field, FieldType, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
-import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols';
+import { AclAdmin, AclAugment, AclEdit, DocData, KeywordsHeight } from '../../fields/DocSymbols';
import { Id } from '../../fields/FieldSymbols';
import { InkField } from '../../fields/InkField';
import { ScriptField } from '../../fields/ScriptField';
@@ -835,7 +835,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
<div
className="link-button-container"
style={{
- top: `${doc[DocData].showLabels ? 4 + (doc[DocData].keywordHeight as number) : 4}px`,
+ top: `${doc[DocData].showLabels ? 4 + doc[KeywordsHeight] : 4}px`,
transform: `translate(${-this._resizeBorderWidth / 2 + 10}px, ${this._resizeBorderWidth + bounds.b - bounds.y + this._titleHeight}px) `,
}}>
<DocumentButtonBar views={() => DocumentView.Selected()} />
diff --git a/src/client/views/KeywordBox.tsx b/src/client/views/KeywordBox.tsx
index 1460501db..841c5394b 100644
--- a/src/client/views/KeywordBox.tsx
+++ b/src/client/views/KeywordBox.tsx
@@ -1,19 +1,22 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, Colors, IconButton } from 'browndash-components';
-import { action, computed, makeObservable, observable, reaction } from 'mobx';
+import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import React from 'react';
+import ResizeObserver from 'resize-observer-polyfill';
import { returnFalse, setupMoveUpEvents } from '../../ClientUtils';
import { Utils, emptyFunction } from '../../Utils';
import { Doc, DocListCast, StrListCast } from '../../fields/Doc';
-import { DocData } from '../../fields/DocSymbols';
+import { DocData, KeywordsHeight } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
import { NumCast, StrCast } from '../../fields/Types';
import { DocumentType } from '../documents/DocumentTypes';
import { DragManager } from '../util/DragManager';
-import { SelectionManager } from '../util/SelectionManager';
import { SnappingManager } from '../util/SnappingManager';
import { undoable } from '../util/UndoManager';
import { ObservableReactComponent } from './ObservableReactComponent';
+import { DocumentView } from './nodes/DocumentView';
+import { FontIconBox } from './nodes/FontIconBox/FontIconBox';
interface KeywordItemProps {
doc: Doc;
@@ -163,20 +166,18 @@ export class KeywordItem extends ObservableReactComponent<KeywordItemProps> {
@action
handleDragStart = (e: React.PointerEvent) => {
- if (this._props.isEditing) {
- setupMoveUpEvents(
- this,
- e,
- () => {
- const dragData = new DragManager.DocumentDragData([this.createCollection()]);
- DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {});
- return true;
- },
- returnFalse,
- emptyFunction
- );
- e.preventDefault();
- }
+ setupMoveUpEvents(
+ this,
+ e,
+ () => {
+ const dragData = new DragManager.DocumentDragData([this.createCollection()]);
+ DragManager.StartDocumentDrag([this._ref.current!], dragData, e.clientX, e.clientY, {});
+ return true;
+ },
+ returnFalse,
+ emptyFunction
+ );
+ e.preventDefault();
};
render() {
@@ -197,7 +198,7 @@ export class KeywordItem extends ObservableReactComponent<KeywordItemProps> {
<IconButton
tooltip="Remove label"
onPointerDown={undoable(() => KeywordItem.RemoveLabel(this._props.doc, this._props.keyword, this._props.keywordDoc), `remove label ${this._props.keyword}`)}
- icon={'X'}
+ icon={<FontAwesomeIcon icon="times" size="sm" />}
style={{ width: '8px', height: '8px', marginLeft: '10px' }}
/>
)}
@@ -207,7 +208,7 @@ export class KeywordItem extends ObservableReactComponent<KeywordItemProps> {
}
interface KeywordBoxProps {
- Document: Doc;
+ View: DocumentView;
}
/**
@@ -215,50 +216,28 @@ interface KeywordBoxProps {
*/
@observer
export class KeywordBox extends ObservableReactComponent<KeywordBoxProps> {
- private _height: number = 0;
private _ref: React.RefObject<HTMLDivElement>;
constructor(props: any) {
super(props);
makeObservable(this);
this._ref = React.createRef();
-
- reaction(
- () => this.cur_height,
- () => {
- this._props.Document[DocData].keywordHeight = this._height;
- }
- );
}
@observable _currentInput = '';
- @observable _isEditing = !StrListCast(this._props.Document[DocData].tags).length;
+ @observable _isEditing = !StrListCast(this._props.View.dataDoc.tags).length;
@computed get currentScale() {
- return NumCast((this._props.Document.embedContainer as Doc)?._freeform_scale, 1);
+ return NumCast((this._props.View.Document.embedContainer as Doc)?._freeform_scale, 1);
}
-
- @computed get cur_height() {
- return this._ref.current?.offsetHeight ?? 0;
- }
-
@computed get isEditing() {
- return this._isEditing && SelectionManager.Docs().includes(this._props.Document);
- }
-
- componentDidMount() {
- this._height = this._ref.current?.offsetHeight ?? 0;
- this._props.Document[DocData].keywordHeight = this._height;
- }
-
- componentDidUpdate(prevProps: Readonly<KeywordBoxProps>): void {
- this._height = this._ref.current?.offsetHeight ?? 0;
- this._props.Document[DocData].keywordHeight = this._height;
+ return this._isEditing && DocumentView.SelectedDocs().includes(this._props.View.Document);
}
@action
- setToEditing = () => {
- this._isEditing = true;
+ setToEditing = (editing = true) => {
+ this._isEditing = editing;
+ editing && this._props.View.select(false);
};
/**
@@ -267,17 +246,17 @@ export class KeywordBox extends ObservableReactComponent<KeywordBoxProps> {
*/
submitLabel = undoable((keyword: string) => {
const submittedLabel = keyword.trim();
- submittedLabel && KeywordItem.addLabelToDoc(this._props.Document, '#' + submittedLabel.replace(/^#/, ''));
+ submittedLabel && KeywordItem.addLabelToDoc(this._props.View.Document, '#' + submittedLabel.replace(/^#/, ''));
this._currentInput = ''; // Clear the input box
}, 'added doc label');
render() {
- const keywordsList = StrListCast(this._props.Document[DocData].tags);
+ const keywordsList = StrListCast(this._props.View.dataDoc.tags);
- return !this._props.Document.showLabels ? null : (
+ return !this._props.View.Document.showLabels ? null : (
<div
className="keywords-container"
- ref={this._ref}
+ ref={r => r && new ResizeObserver(action(() => (this._props.View.Document[KeywordsHeight] = r?.getBoundingClientRect().height ?? 0))).observe(r)}
style={{
transformOrigin: 'top left',
maxWidth: `${100 * this.currentScale}%`,
@@ -288,8 +267,11 @@ export class KeywordBox extends ObservableReactComponent<KeywordBoxProps> {
}}>
<div className="keywords-content" style={{ width: '100%' }}>
<div className="keywords-list">
+ {!keywordsList.length ? null : ( //
+ <IconButton style={{ width: '8px' }} tooltip="Close Menu" onPointerDown={() => this.setToEditing(!this._isEditing)} icon={<FontAwesomeIcon icon={this._isEditing ? 'chevron-up' : 'chevron-down'} size="sm" />} />
+ )}
{keywordsList.map(keyword => (
- <KeywordItem key={keyword} doc={this._props.Document} keyword={keyword} keywordDoc={KeywordItem.findKeywordCollectionDoc(keyword)} setToEditing={this.setToEditing} isEditing={this.isEditing} />
+ <KeywordItem key={keyword} doc={this._props.View.Document} keyword={keyword} keywordDoc={KeywordItem.findKeywordCollectionDoc(keyword)} setToEditing={this.setToEditing} isEditing={this.isEditing} />
))}
</div>
{this.isEditing ? (
@@ -325,11 +307,6 @@ export class KeywordBox extends ObservableReactComponent<KeywordBoxProps> {
);
})}
</div>
- <div className="keyword-buttons">
- {!keywordsList.length ? null : ( //
- <IconButton style={{ width: '4px' }} tooltip="Close Menu" onPointerDown={action(() => (this._isEditing = false))} icon="x" />
- )}
- </div>
</div>
) : null}
</div>
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss
index 1d41697f5..6f6939d54 100644
--- a/src/client/views/StyleProvider.scss
+++ b/src/client/views/StyleProvider.scss
@@ -65,10 +65,13 @@
.keywords-list {
display: flex;
flex-wrap: wrap;
+ .iconButton-container {
+ min-height: unset !important;
+ }
}
.keyword {
- padding: 5px 5px;
+ padding: 1px 5px;
background-color: lightblue;
border: 1px solid black;
border-radius: 5px;
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 0fb4f7dd1..a841ec63a 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -363,7 +363,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps &
</Tooltip>
);
};
- const keywords = () => doc && CollectionFreeFormDocumentView.from(props?.DocumentView?.()) ? <KeywordBox Document={doc}/> : null;
+ const keywords = () => props?.DocumentView?.() && CollectionFreeFormDocumentView.from(props.DocumentView()) ? <KeywordBox View={props.DocumentView()}/> : null;
return (
<>
{paint()}
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index ffb5aab79..f246f49e5 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -11,7 +11,7 @@ import { ClientUtils, incrementTitleCopy } from '../ClientUtils';
import {
AclAdmin, AclAugment, AclEdit, AclPrivate, AclReadonly, Animation, AudioPlay, Brushed, CachedUpdates, DirectLinks,
DocAcl, DocCss, DocData, DocLayout, DocViews, FieldKeys, FieldTuples, ForceServerWrite, Height, Highlight,
- Initializing, Self, SelfProxy, TransitionTimer, UpdatingFromServer, Width
+ Initializing, KeywordsHeight, Self, SelfProxy, TransitionTimer, UpdatingFromServer, Width
} from './DocSymbols'; // prettier-ignore
import { Copy, FieldChanged, HandleUpdate, Id, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols';
import { InkTool } from './InkField';
@@ -303,6 +303,7 @@ export class Doc extends RefField {
Height,
Highlight,
Initializing,
+ KeywordsHeight,
Self,
SelfProxy,
UpdatingFromServer,
@@ -368,6 +369,7 @@ export class Doc extends RefField {
@observable public [Highlight]: boolean = false;
@observable public [Brushed]: boolean = false;
@observable public [DocViews] = new ObservableSet<unknown /* DocumentView */>();
+ @observable public [KeywordsHeight]: number = 0;
private [Self] = this;
private [SelfProxy]: Doc;
diff --git a/src/fields/DocSymbols.ts b/src/fields/DocSymbols.ts
index 837fcc90e..9e091ab29 100644
--- a/src/fields/DocSymbols.ts
+++ b/src/fields/DocSymbols.ts
@@ -1,3 +1,5 @@
+// NOTE: These symbols must be added to Doc.ts constructor !!
+
// Symbols for fundamental Doc operations such as: permissions, field and proxy access and server interactions
export const AclPrivate = Symbol('DocAclOwnerOnly');
export const AclReadonly = Symbol('DocAclReadOnly');
@@ -30,5 +32,6 @@ export const DocViews = Symbol('DocViews');
export const Brushed = Symbol('DocBrushed');
export const DocCss = Symbol('DocCss');
export const TransitionTimer = Symbol('DocTransitionTimer');
+export const KeywordsHeight = Symbol('DocKeywordsHeight');
export const DashVersion = 'v0.8.0';