diff options
Diffstat (limited to 'src/client/views/nodes/FontIconBox/FontIconBox.tsx')
-rw-r--r-- | src/client/views/nodes/FontIconBox/FontIconBox.tsx | 190 |
1 files changed, 107 insertions, 83 deletions
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index d4898eb3c..8c138c2ee 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -4,7 +4,7 @@ import { Button, ColorPicker, Dropdown, DropdownType, IconButton, IListItemProps import { action, computed, makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { ClientUtils, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; +import { ClientUtils, DashColor, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; import { Doc, DocListCast, StrListCast } from '../../../../fields/Doc'; import { BoolCast, DocCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { emptyFunction } from '../../../../Utils'; @@ -21,6 +21,8 @@ import { FieldView, FieldViewProps } from '../FieldView'; import { OpenWhere } from '../OpenWhere'; import './FontIconBox.scss'; import TrailsIcon from './TrailsIcon'; +import { InkTool } from '../../../../fields/InkField'; +import { ScriptField } from '../../../../fields/ScriptField'; export enum ButtonType { TextButton = 'textBtn', @@ -126,7 +128,8 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { background={SnappingManager.userBackgroundColor} numberDropdownType={type} showPlusMinus={false} - tooltip={this.label} + formLabel={(StrCast(this.Document.title).startsWith(' ') ? '\u00A0' : '') + StrCast(this.Document.title)} + tooltip={StrCast(this.Document.toolTip, this.label)} type={Type.PRIM} min={NumCast(this.dataDoc.numBtnMin, 0)} max={NumCast(this.dataDoc.numBtnMax, 100)} @@ -149,64 +152,79 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { }; /** + * Displays custom dropdown menu for fonts -- this is a HACK -- fix for generality, don't copy + */ + handleFontDropdown = (script: () => string, buttonList: string[]) => { + // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); + return { + buttonList, + jsx: undefined, + selectedVal: script(), + getStyle: (val: string) => ({ fontFamily: val }), + }; + }; + /** + * Displays custom dropdown menu for view selection -- this is a HACK -- fix for generality, don't copy + */ + handleViewDropdown = (script: ScriptField, buttonList: string[]) => { + const selected = Array.from(script?.script.run({ _readOnly_: true }).result as Doc[]); + const noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Card, CollectionViewType.Carousel3D, CollectionViewType.Carousel, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; + return selected.length === 1 && selected[0].type === DocumentType.COL + ? { + buttonList: buttonList.filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value as CollectionViewType)), + getStyle: undefined, + selectedVal: StrCast(selected[0]._type_collection), + } + : { + jsx: selected.length ? ( + <Popup + icon={<FontAwesomeIcon size="1x" icon={selected.length > 1 ? 'caret-down' : (Doc.toIcon(selected.lastElement()) as IconProp)} />} + text={selected.length === 1 ? ClientUtils.cleanDocumentType(StrCast(selected[0].type) as DocumentType) : selected.length + ' selected'} + type={Type.TERT} + color={SnappingManager.userColor} + background={SnappingManager.userVariantColor} + popup={<SelectedDocView selectedDocs={selected} />} + fillWidth + /> + ) : ( + <Button + text={`${Doc.ActiveTool === InkTool.None ? 'Text box' : Doc.ActiveInk} defaults`} // + type={Type.TERT} + color={SnappingManager.userColor} + background={SnappingManager.userVariantColor} + fillWidth + inactive + /> + ), + }; + }; + + /** * Dropdown list */ @computed get dropdownListButton() { const script = ScriptCast(this.Document.script); - - let noviceList: string[] = []; - let text: string | undefined; - let getStyle: (val: string) => { [key: string]: string } = () => ({}); - let icon: IconProp = 'caret-down'; - const isViewDropdown = script?.script.originalScript.startsWith('{ return setView'); - if (isViewDropdown) { - const selected = Array.from(script?.script.run({ _readOnly_: true }).result as Doc[]); - // const selected = DocumentView.SelectedDocs(); - if (selected.lastElement()) { - if (StrCast(selected.lastElement().type) === DocumentType.COL) { - text = StrCast(selected.lastElement()._type_collection); - } else { - if (selected.length > 1) { - text = selected.length + ' selected'; - } else { - text = ClientUtils.cleanDocumentType(StrCast(selected.lastElement().type) as DocumentType, '' as CollectionViewType); - icon = Doc.toIcon(selected.lastElement()); - } - return ( - <Popup - icon={<FontAwesomeIcon size="1x" icon={icon} />} - text={text} - type={Type.TERT} - color={SnappingManager.userColor} - background={SnappingManager.userVariantColor} - popup={<SelectedDocView selectedDocs={selected} />} - fillWidth - /> - ); - } - } else { - return <Button text="None Selected" type={Type.TERT} color={SnappingManager.userColor} background={SnappingManager.userVariantColor} fillWidth inactive />; - } - noviceList = [CollectionViewType.Freeform, CollectionViewType.Schema, CollectionViewType.Card, CollectionViewType.Carousel3D, CollectionViewType.Carousel, CollectionViewType.Stacking, CollectionViewType.NoteTaking]; - } else { - text = script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string; - // text = StrCast((RichTextMenu.Instance?.TextView?.EditorView ? RichTextMenu.Instance : Doc.UserDoc()).fontFamily); - if (this.Document.title === 'Font') getStyle = (val: string) => ({ fontFamily: val }); // bcz: major hack to style the font dropdown items --- needs to become part of the dropdown's metadata - } + const selectedFunc = () => script?.script.run({ this: this.Document, value: '', _readOnly_: true }).result as string; + const { buttonList, selectedVal, getStyle, jsx } = (() => { + switch (this.Document.title) { + case 'Font': return this.handleFontDropdown(selectedFunc, this.buttonList); + case 'Perspective': return this.handleViewDropdown(script, this.buttonList); + default: return { buttonList: this.buttonList, selectedVal: selectedFunc(), jsx: undefined, getStyle: undefined }; + } // prettier-ignore + })(); + if (jsx) return jsx; // Get items to place into the list - const list: IListItemProps[] = this.buttonList - .filter(value => !Doc.noviceMode || !noviceList.length || noviceList.includes(value)) - .map(value => ({ - text: typeof value === 'string' ? value.charAt(0).toUpperCase() + value.slice(1) : StrCast(DocCast(value)?.title), - val: value, - style: getStyle(value), - // shortcut: '#', - })); + const list: IListItemProps[] = buttonList.map(value => ({ + text: typeof value === 'string' ? value.charAt(0).toUpperCase() + value.slice(1) : StrCast(DocCast(value)?.title), + val: value, + style: getStyle?.(value), + // shortcut: '#', + })); return ( <Dropdown - selectedVal={text} + selectedVal={selectedVal} setSelectedVal={undoable(value => script.script.run({ this: this.Document, value }), `dropdown select ${this.label}`)} color={SnappingManager.userColor} background={SnappingManager.userVariantColor} @@ -215,7 +233,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { dropdownType={DropdownType.SELECT} onItemDown={this.dropdownItemDown} items={list} - tooltip={this.label} + tooltip={StrCast(this.Document.toolTip, this.label)} fillWidth /> ); @@ -235,49 +253,53 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { const tooltip: string = StrCast(this.Document.toolTip); return ( - <ColorPicker - setSelectedColor={value => { - if (!this.colorBatch) this.colorBatch = UndoManager.StartBatch(`Set ${tooltip} color`); - this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); - }} - setFinalColor={value => { - this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); - this.colorBatch?.end(); - this.colorBatch = undefined; - }} - defaultPickerType="Classic" - selectedColor={curColor} - type={Type.PRIM} - color={color} - background={SnappingManager.userBackgroundColor} - icon={this.Icon(color) ?? undefined} - tooltip={tooltip} - label={this.label} - /> + <div + onPointerDown={e => { + e.stopPropagation(); + }}> + <ColorPicker + setSelectedColor={value => { + if (!this.colorBatch) this.colorBatch = UndoManager.StartBatch(`Set ${tooltip} color`); + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); + }} + setFinalColor={value => { + this.colorScript?.script.run({ this: this.Document, value: value, _readOnly_: false }); + this.colorBatch?.end(); + this.colorBatch = undefined; + }} + defaultPickerType="Classic" + selectedColor={curColor} + type={Type.PRIM} + color={color} + background={SnappingManager.userBackgroundColor} + icon={this.Icon(color) ?? undefined} + tooltip={tooltip} + label={this.label} + /> + </div> ); } @computed get multiToggleButton() { - // Determine the type of toggle button - const tooltip: string = StrCast(this.Document.toolTip); + const tooltip = StrCast(this.Document.toolTip); const script = ScriptCast(this.Document.onClick)?.script; const toggleStatus = script?.run({ this: this.Document, value: undefined, _readOnly_: true }).result as boolean; - // Colors + const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; - const background = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor) as string; const items = DocListCast(this.dataDoc.data); const selectedItems = items.filter(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, value: undefined, _readOnly_: true }).result).map(item => StrCast(item.toolType)); + return ( <MultiToggle - tooltip={`Toggle ${tooltip}`} + tooltip={`Click to Toggle ${tooltip} or select new option`} type={Type.PRIM} color={color} - background={background === SnappingManager.userBackgroundColor ? undefined : background} + background={undefined} multiSelect={true} onPointerDown={e => script && !toggleStatus && setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => script.run({ this: this.Document, value: undefined, _readOnly_: false }))} isToggle={false} toggleStatus={toggleStatus} - label={this.label} + label={selectedItems.length === 1 ? selectedItems[0] : this.label} items={items.map(item => ({ icon: <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={StrCast(item.icon) as IconProp} color={color} />, tooltip: StrCast(item.toolTip), @@ -290,7 +312,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { // it would be better to pas the 'added' flag to the callback script, but our script generator from currentUserUtils makes it hard to define // arbitrary parameter variables (but it could be done as a special case or with additional effort when creating the sript) const itemsChanged = items.filter(item => (val instanceof Array ? val.includes(item.toolType as string | number) : item.toolType === val)); - itemsChanged.forEach(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, _added_: added, itemDoc, _readOnly_: false })); + itemsChanged.forEach(itemDoc => ScriptCast(itemDoc.onClick).script.run({ this: itemDoc, _added_: added, value: toggleStatus, itemDoc, _readOnly_: false })); }} /> ); @@ -308,17 +330,19 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { const toggleStatus = (script?.script.run({ this: this.Document, value: undefined, _readOnly_: true }).result as boolean) ?? false; // Colors const color = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.Color) as string; - // const backgroundColor = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BackgroundColor); + // bcz: ink shapes are tri-state - off, one-shot, and on. Need to update Toggle buttons to allow this and update currentUserUtils to set the tri-state on the Doc + // in the meantime, if the button matches a tool type that is not locked, we want to set the background color to something distinct. + const inkShapeHack = ((this.Document.toolType && this.Document.toolType === SnappingManager.InkShape) || this.Document.toolType === Doc.ActiveTool) && !SnappingManager.KeepGestureMode; return ( <Toggle tooltip={`Toggle ${tooltip}`} toggleType={ToggleType.BUTTON} - type={Type.PRIM} + type={inkShapeHack ? Type.TERT : Type.PRIM} toggleStatus={toggleStatus} text={buttonText} color={color} - // background={SnappingManager.userBackgroundColor} + background={inkShapeHack ? DashColor(SnappingManager.userBackgroundColor).darken(0.05).toString() : undefined} icon={this.Icon(color)!} label={this.label} onPointerDown={e => @@ -392,7 +416,7 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() { render() { return ( - <div style={{ margin: 'auto', width: '100%' }} onContextMenu={this.specificContextMenu}> + <div className="fonticonbox" onContextMenu={this.specificContextMenu}> {this.renderButton()} </div> ); |