diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 4 | ||||
-rw-r--r-- | src/client/views/KeywordBox.tsx | 91 | ||||
-rw-r--r-- | src/client/views/StyleProvider.scss | 5 | ||||
-rw-r--r-- | src/client/views/StyleProvider.tsx | 2 | ||||
-rw-r--r-- | src/fields/Doc.ts | 4 | ||||
-rw-r--r-- | src/fields/DocSymbols.ts | 3 |
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'; |