From 4c768162e0436115a05b9c8b0e4d837d626d45ba Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 30 Oct 2024 18:54:52 -0400 Subject: reworked how context menu buttons for ink and text work. added disableMixBlend for making transparent docs not use 'multiply'. --- src/client/views/StyleProp.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/client/views/StyleProp.ts') diff --git a/src/client/views/StyleProp.ts b/src/client/views/StyleProp.ts index 44d3bf757..56367e70b 100644 --- a/src/client/views/StyleProp.ts +++ b/src/client/views/StyleProp.ts @@ -19,7 +19,9 @@ export enum StyleProp { FontColor = 'fontColor', // color o tet FontSize = 'fontSize', // size of text font FontFamily = 'fontFamily', // font family of text - FontWeight = 'fontWeight', // font weight of text + FontWeight = 'fontWeight', // font weight of text (eg bold) + FontStyle = 'fontStyle', // font style of text (eg italic) + FontDecoration = 'fontDecoration', // text decoration of text (eg underline) Highlighting = 'highlighting', // border highlighting ContextMenuItems = 'contextMenuItems', // menu items to add to context menu AnchorMenuItems = 'anchorMenuItems', -- cgit v1.2.3-70-g09d2 From 1c7c5bcadc7081e1a7e582413eee37b8201e1c4c Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 24 Feb 2025 18:07:36 -0500 Subject: added borders (width, color, and style) for DocumentViews. fixed dropdown slider buttons to show text labels. --- .../components/NumberDropdown/NumberDropdown.scss | 18 +- .../components/NumberDropdown/NumberDropdown.tsx | 182 +++++++++------------ packages/components/src/components/Popup/Popup.tsx | 8 +- packages/components/src/global/globalTypes.ts | 137 +++++++--------- src/client/documents/DocUtils.ts | 4 + src/client/documents/Documents.ts | 4 +- src/client/util/CurrentUserUtils.ts | 6 +- src/client/views/StyleProp.ts | 1 + src/client/views/StyleProvider.tsx | 51 +++--- src/client/views/global/globalScripts.ts | 55 +++++++ .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 21 +-- src/client/views/nodes/FontIconBox/FontIconBox.tsx | 1 + .../views/nodes/formattedText/FormattedTextBox.tsx | 2 +- 14 files changed, 263 insertions(+), 229 deletions(-) (limited to 'src/client/views/StyleProp.ts') diff --git a/packages/components/src/components/NumberDropdown/NumberDropdown.scss b/packages/components/src/components/NumberDropdown/NumberDropdown.scss index 0999afb98..4ed5855d9 100644 --- a/packages/components/src/components/NumberDropdown/NumberDropdown.scss +++ b/packages/components/src/components/NumberDropdown/NumberDropdown.scss @@ -1,5 +1,19 @@ @import '../../global/globalCssVariables.scss'; .numberDropdown-container { - -} \ No newline at end of file +} + +.form-wrapper { + .iconButton-label { + position: relative; + z-index: 2; + width: 100%; + overflow: hidden; + white-space: normal; + display: flex; + text-align: center; + justify-content: center; + align-items: center; + font-size: $xsmall-fontSize !important; + } +} diff --git a/packages/components/src/components/NumberDropdown/NumberDropdown.tsx b/packages/components/src/components/NumberDropdown/NumberDropdown.tsx index a26cd71ab..7f12198d5 100644 --- a/packages/components/src/components/NumberDropdown/NumberDropdown.tsx +++ b/packages/components/src/components/NumberDropdown/NumberDropdown.tsx @@ -1,137 +1,101 @@ -import * as React from 'react' -import { Colors, IGlobalProps, INumberProps, Size, Type, getFontSize , getFormLabelSize } from '../../global' -import { Popup } from '../Popup' -import { Toggle, ToggleType } from '../Toggle' -import { useState } from 'react' -import { Slider } from '../Slider' -import { ListBox } from '../ListBox' -import { IListItemProps } from '../ListItem' -import { Group } from '../Group' -import { IconButton } from '../IconButton' -import * as fa from 'react-icons/fa' +import * as React from 'react'; +import { Colors, INumberProps, Size, getFormLabelSize } from '../../global'; +import { Popup } from '../Popup'; +import { Toggle, ToggleType } from '../Toggle'; +import { useState } from 'react'; +import { Slider } from '../Slider'; +import { ListBox } from '../ListBox'; +import { IListItemProps } from '../ListItem'; +import { Group } from '../Group'; +import { IconButton } from '../IconButton'; +import * as fa from 'react-icons/fa'; +import './NumberDropdown.scss'; - -export type NumberDropdownType = 'slider' | 'dropdown' | 'input' +export type NumberDropdownType = 'slider' | 'dropdown' | 'input'; export interface INumberDropdownProps extends INumberProps { - numberDropdownType: NumberDropdownType, - showPlusMinus?: boolean + numberDropdownType: NumberDropdownType; + showPlusMinus?: boolean; } export const NumberDropdown = (props: INumberDropdownProps) => { - const [numberLoc, setNumberLoc] = useState(0) - const { - fillWidth, - numberDropdownType = false, - color = Colors.MEDIUM_BLUE, - type, - formLabelPlacement, - showPlusMinus, - min, - max, - unit, - step = 1, - number = numberLoc, - setNumber = setNumberLoc, - size, - formLabel, - tooltip } = - props; + const [numberLoc, setNumberLoc] = useState(0); + const { fillWidth, numberDropdownType = false, color = Colors.MEDIUM_BLUE, type, formLabelPlacement, showPlusMinus, min, max, unit, step = 1, number = numberLoc, setNumber = setNumberLoc, size, formLabel, tooltip } = props; const [isOpen, setOpen] = useState(false); let toggleText = number.toString(); - if (unit) toggleText = toggleText + unit - let toggle = setOpen(!isOpen)} - />; - + if (unit) toggleText = toggleText + unit; + let toggle = setOpen(!isOpen)} />; + if (showPlusMinus) { - toggle = - } - color={color} - onClick={(e) => { - e.stopPropagation(); - setNumber(number - step); - }} - fillWidth={fillWidth} - tooltip={`Subtract ${step}${unit}`} - /> - {toggle} - } - color={color} - onClick={(e) => { - e.stopPropagation(); - setNumber(number + step); - }} - fillWidth={fillWidth} - tooltip={`Add ${step}${unit}`} - /> - + toggle = ( + + } + color={color} + onClick={e => { + e.stopPropagation(); + setNumber(number - step); + }} + fillWidth={fillWidth} + tooltip={`Subtract ${step}${unit}`} + /> + {toggle} + } + color={color} + onClick={e => { + e.stopPropagation(); + setNumber(number + step); + }} + fillWidth={fillWidth} + tooltip={`Add ${step}${unit}`} + /> + + ); } - + let popup; switch (numberDropdownType) { case 'dropdown': - let items: IListItemProps[] = []; - for (let i = min; i <= max; i += step) { - let text = i.toString() - if (unit) text = i.toString() + unit - items.push( - { + { + const items: IListItemProps[] = []; + for (let i = min; i <= max; i += step) { + let text = i.toString(); + if (unit) text = i.toString() + unit; + items.push({ text: text, val: i, - style: { textAlign: 'center' } - } - ) + style: { textAlign: 'center' }, + }); + } + popup = setNumber(num as number)} items={items} />; } - popup = setNumber(num as number)} - items={items} - /> break; case 'slider': default: - popup = + popup = ; break; case 'input': - popup = + popup = ; break; } - const numberDropdown: JSX.Element =
- -
+ const numberDropdown: JSX.Element = ( +
+ +
+ ); - return ( - formLabel ? -
+ return formLabel ? ( +
{numberDropdown} -
{formLabel}
+
+ {formLabel} +
- : + ) : ( numberDropdown - ) -} \ No newline at end of file + ); +}; diff --git a/packages/components/src/components/Popup/Popup.tsx b/packages/components/src/components/Popup/Popup.tsx index 92e7227bd..aa732d568 100644 --- a/packages/components/src/components/Popup/Popup.tsx +++ b/packages/components/src/components/Popup/Popup.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState } from 'react'; -import { Colors, IGlobalProps, Placement, Size, getFormLabelSize, isDark } from '../../global'; +import { Colors, IGlobalProps, Placement, Size, isDark } from '../../global'; import { Toggle, ToggleType } from '../Toggle'; import './Popup.scss'; import { Popper } from '@mui/material'; @@ -16,7 +16,7 @@ export interface IPopupProps extends IGlobalProps { iconPlacement?: Placement; placement?: Placement; size?: Size; - height?: number; + height?: number | string; toggle?: JSX.Element; popup: JSX.Element | string | (() => JSX.Element); trigger?: PopupTrigger; @@ -62,12 +62,12 @@ export const Popup = (props: IPopupProps) => { } = props; const triggerRef = useRef(null); - const popperRef = useRef(null); + const popperRef = useRef(null); let timeout = setTimeout(() => {}); const handlePointerAwayDown = (e: PointerEvent) => { - const rect = (popperRef.current as any)?.getBoundingClientRect(); + const rect = popperRef.current?.getBoundingClientRect(); if (rect && !(rect.left < e.clientX && rect.top < e.clientY && rect.right > e.clientX && rect.bottom > e.clientY) && !popupContainsPt?.(e.clientX, e.clientY)) { e.preventDefault(); setOpen(false); diff --git a/packages/components/src/global/globalTypes.ts b/packages/components/src/global/globalTypes.ts index aa8451a9c..764fe7422 100644 --- a/packages/components/src/global/globalTypes.ts +++ b/packages/components/src/global/globalTypes.ts @@ -1,87 +1,76 @@ -import { PointerEventHandler } from "react" -import { Size } from "./globalEnums" +import { PointerEventHandler } from 'react'; +import { Size } from './globalEnums'; -export interface IGlobalProps { - // Size - size?: Size - height?: number - width?: number - fillWidth?: boolean - color?: string - background?: string +export enum Type { + PRIM = 'primary', + SEC = 'secondary', + TERT = 'tertiary', +} - // Type - type?: Type +export type Placement = 'bottom-end' | 'bottom-start' | 'bottom' | 'left-end' | 'left-start' | 'left' | 'right-end' | 'right-start' | 'right' | 'top-end' | 'top-start' | 'top'; - // Status - inactive?: boolean +export type Alignment = 'flex-start' | 'flex-end' | 'center'; - // Content - tooltip?: string - tooltipPlacement?: Placement +export type TextAlignment = 'center' | 'left' | 'right'; - // Label - label?: string - hideLabel?: boolean +export interface IGlobalProps { + // Size + size?: Size; + height?: number | string; + width?: number; + fillWidth?: boolean; + color?: string; + background?: string; - // Label when used in forms - formLabel?: string - formLabelPlacement?: Placement + // Type + type?: Type; - // Custom style - style?: React.CSSProperties + // Status + inactive?: boolean; - // Global pointer events - onPointerDown?: PointerEventHandler | undefined; - onPointerDownCapture?: PointerEventHandler | undefined; - onPointerMove?: PointerEventHandler | undefined; - onPointerMoveCapture?: PointerEventHandler | undefined; - onPointerUp?: PointerEventHandler | undefined; - onPointerUpCapture?: PointerEventHandler | undefined; - onPointerCancel?: PointerEventHandler | undefined; - onPointerCancelCapture?: PointerEventHandler | undefined; - onPointerEnter?: PointerEventHandler | undefined; - onPointerEnterCapture?: PointerEventHandler | undefined; - onPointerLeave?: PointerEventHandler | undefined; - onPointerLeaveCapture?: PointerEventHandler | undefined; - onPointerOver?: PointerEventHandler | undefined; - onPointerOverCapture?: PointerEventHandler | undefined; - onPointerOut?: PointerEventHandler | undefined; - onPointerOutCapture?: PointerEventHandler | undefined; - onGotPointerCapture?: PointerEventHandler | undefined; - onGotPointerCaptureCapture?: PointerEventHandler | undefined; - onLostPointerCapture?: PointerEventHandler | undefined; - onLostPointerCaptureCapture?: PointerEventHandler | undefined; -} + // Content + tooltip?: string; + tooltipPlacement?: Placement; -export interface INumberProps extends IGlobalProps { - min: number, - max: number, - step?: number, - number: number - setNumber?: (num: number) => unknown, - unit?: string -} + // Label + label?: string; + hideLabel?: boolean; -export enum Type { - PRIM = "primary", - SEC = "secondary", - TERT = "tertiary", -} + // Label when used in forms + formLabel?: string; + formLabelPlacement?: Placement; -export type Placement = 'bottom-end' - | 'bottom-start' - | 'bottom' - | 'left-end' - | 'left-start' - | 'left' - | 'right-end' - | 'right-start' - | 'right' - | 'top-end' - | 'top-start' - | 'top' + // Custom style + style?: React.CSSProperties; -export type Alignment = 'flex-start' | 'flex-end' | 'center' + // Global pointer events + onPointerDown?: PointerEventHandler | undefined; + onPointerDownCapture?: PointerEventHandler | undefined; + onPointerMove?: PointerEventHandler | undefined; + onPointerMoveCapture?: PointerEventHandler | undefined; + onPointerUp?: PointerEventHandler | undefined; + onPointerUpCapture?: PointerEventHandler | undefined; + onPointerCancel?: PointerEventHandler | undefined; + onPointerCancelCapture?: PointerEventHandler | undefined; + onPointerEnter?: PointerEventHandler | undefined; + onPointerEnterCapture?: PointerEventHandler | undefined; + onPointerLeave?: PointerEventHandler | undefined; + onPointerLeaveCapture?: PointerEventHandler | undefined; + onPointerOver?: PointerEventHandler | undefined; + onPointerOverCapture?: PointerEventHandler | undefined; + onPointerOut?: PointerEventHandler | undefined; + onPointerOutCapture?: PointerEventHandler | undefined; + onGotPointerCapture?: PointerEventHandler | undefined; + onGotPointerCaptureCapture?: PointerEventHandler | undefined; + onLostPointerCapture?: PointerEventHandler | undefined; + onLostPointerCaptureCapture?: PointerEventHandler | undefined; +} -export type TextAlignment = 'center' | 'left' | 'right' \ No newline at end of file +export interface INumberProps extends IGlobalProps { + min: number; + max: number; + step?: number; + number: number; + setNumber?: (num: number) => unknown; + unit?: string; +} diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index 23032b62e..f1de6fe36 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -692,6 +692,8 @@ export namespace DocUtils { // annotationOn, backgroundColor: backgroundColor ?? StrCast(Doc.UserDoc().textBackgroundColor), + borderColor: Doc.UserDoc().borderColor as string, + borderWidth: Doc.UserDoc().borderWidth as number, x, y, title, @@ -718,6 +720,8 @@ export namespace DocUtils { _layout_fitWidth: true, _layout_autoHeight: true, backgroundColor: StrCast(Doc.UserDoc().textBackgroundColor), + borderColor: Doc.UserDoc().borderColor as string, + borderWidth: Doc.UserDoc().borderWidth as number, text_fitBox: BoolCast(Doc.UserDoc().fitBox), text_align: StrCast(Doc.UserDoc().textAlign), text_fontColor: StrCast(Doc.UserDoc().fontColor), diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 891223952..1ce25165c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -240,8 +240,8 @@ export class DocumentOptions { dataViz?: string; dataViz_savedTemplates?: LISTt; - borderWidth?: STRt = new StrInfo('Width of user-added border', false); - borderColor?: STRt = new StrInfo('Color of user-added border', false); + borderWidth?: NUMt = new NumInfo('Width of docuent border', false); + borderColor?: STRt = new StrInfo('Color of document border', false); text_fontColor?: STRt = new StrInfo('Color of text', false); hCentering?: 'h-left' | 'h-center' | 'h-right'; isDefaultTemplateDoc?: BOOLt = new BoolInfo(''); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index fb349abd9..d2d7cabd2 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -734,7 +734,7 @@ pie title Minerals in my tap water } static viewTools(): Button[] { return [ - { title: "Show Tags", icon: "id-card", toolTip: "Toggle tags", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"toggle-tags",funcs: { }, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} }, + { title: "Tags", icon: "id-card", toolTip: "Toggle Tags display", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"toggle-tags",funcs: { }, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} }, { title: "Snap", icon: "th", toolTip: "Show Snap Lines", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"snaplines", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "Grid", icon: "border-all", toolTip: "Show Grid", btnType: ButtonType.ToggleButton, ignoreClick: true, expertMode: false, toolType:"grid", funcs: { hidden: `!SelectedDocType("${CollectionViewType.Freeform}", this.expertMode)`}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}}, // Only when floating document is selected in freeform { title: "Fit All", icon: "object-group", toolTip:"Fit Docs to View (double tap to persist)", @@ -833,11 +833,13 @@ pie title Minerals in my tap water { title: "Header", icon: "heading", toolTip: "Doc Titlebar Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'} }, { title: "Template",icon: "scroll", toolTip: "Default Note Template",btnType: ButtonType.ToggleButton, expertMode: false, toolType:DocumentType.RTF, scripts: { onClick: '{ return setDefaultTemplate(_readOnly_); }'} }, { title: "Fill", icon: "fill-drip", toolTip: "Fill/Background Color",btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'} }, // Only when a document is selected + { title: "Border", icon: "pen", toolTip: "Border Color", btnType: ButtonType.ColorButton, expertMode: false, ignoreClick: true, width: 30, scripts: { script: 'return setBorderColor(value, _readOnly_)'} }, // Only when a document is selected + { title: "B.Width", toolTip: "Border width", btnType: ButtonType.NumberSliderButton, ignoreClick: true, scripts: {script: '{ return setBorderWidth(value, _readOnly_);}'}, numBtnMin: 0, linearBtnWidth:40}, { title: "Overlay", icon: "layer-group", toolTip: "Overlay", btnType: ButtonType.ToggleButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode, true)'}, scripts: { onClick: '{ return toggleOverlay(_readOnly_); }'}}, // Only when floating document is selected in freeform { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, { title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, - { title: "Chat", icon:"lightbulb", toolTip: "Toggle Chat Assistant",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat", funcs: {}, width: 30, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} }, + { title: "Chat", icon: "lightbulb", toolTip: "Toggle Chat Assistant",btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat", funcs: {}, width: 30, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} }, { title: "Filter", icon: "=", toolTip: "Filter cards by tags", subMenu: CurrentUserUtils.filterTools(), ignoreClick:true, toolType:DocumentType.COL, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, btnType: ButtonType.MultiToggleButton, width: 30, backgroundColor: doc.userVariantColor as string}, { title: "Sort", icon: "Sort", toolTip: "Sort Documents", subMenu: CurrentUserUtils.sortTools(), expertMode: false, toolType:DocumentType.COL, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available diff --git a/src/client/views/StyleProp.ts b/src/client/views/StyleProp.ts index 56367e70b..1ef7a9e1f 100644 --- a/src/client/views/StyleProp.ts +++ b/src/client/views/StyleProp.ts @@ -5,6 +5,7 @@ export enum StyleProp { Opacity = 'opacity', // opacity of the document view BoxShadow = 'boxShadow', // box shadow - used for making collections standout and for showing clusters in free form views BorderRounding = 'borderRounding', // border radius of the document view + Border = 'border', // border of document view Color = 'color', // foreground color of Document view items BackgroundColor = 'backgroundColor', // background color of a document view FillColor = 'fillColor', // fill color of an ink stroke or shape diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index bebc9a341..b04b1ae65 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -206,33 +206,40 @@ export function DefaultStyleProvider(doc: Opt, props: Opt - - - -
- ), - }; - } + // const borderPath = doc && border(doc, NumCast(doc._width), NumCast(doc._height), radius, -ratio/2); + // return !borderPath + // ? null + // : { + // clipPath: `path('${borderPath}')`, + // jsx: ( + //
+ // + // + // + //
+ // ), + // }; + // } case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.NoteTaking, CollectionViewType.Masonry, CollectionViewType.Tree].includes(doc?._type_collection as CollectionViewType) || (doc?.type === DocumentType.RTF && !layoutShowTitle()?.includes('noMargin')) || diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index 79873ed8f..b455f76e4 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -66,6 +66,49 @@ ScriptingGlobals.add(function setView(view: string, shiftKey: boolean, checkResu return undefined; }); +// toggle: Set overlay status of selected document +// eslint-disable-next-line prefer-arrow-callback +ScriptingGlobals.add(function setBorderColor(color?: string, checkResult?: boolean) { + const selectedViews = DocumentView.Selected(); + const defaultBorder = () => StrCast(Doc.UserDoc().borderColor, 'transparent'); + const setDefaultBorder = (c: string) => { Doc.UserDoc().borderColor = c; }; // prettier-ignore + const fieldKey = 'borderColor'; + if (selectedViews.length) { + if (checkResult) { + const selView = selectedViews.lastElement(); + const layoutFrameNumber = Cast(selView.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values + const contentFrameNumber = Cast(selView.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed + return CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] || defaultBorder(); + } + setDefaultBorder(color ?? 'transparent'); + selectedViews.forEach(dv => { + const layoutFrameNumber = Cast(dv.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values + const contentFrameNumber = Cast(dv.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed + if (contentFrameNumber !== undefined) { + const obj: { [key: string]: Opt } = {}; + obj[fieldKey] = color; + CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.Document, obj); + } else { + const dataKey = Doc.LayoutFieldKey(dv.Document); + const alternate = (dv.layoutDoc[dataKey + '_usePath'] ? '_' + dv.layoutDoc[dataKey + '_usePath'] : '').replace(':hover', ''); + dv.layoutDoc[fieldKey + alternate] = undefined; + dv.dataDoc[fieldKey + alternate] = color; + } + }); + } else { + const selected = DocumentView.SelectedDocs().length ? DocumentView.SelectedDocs() : LinkManager.Instance.currentLink ? [LinkManager.Instance.currentLink] : []; + if (checkResult) { + return (selected.lastElement() ?? Doc.UserDoc()).borderColor ?? defaultBorder(); + } + if (!selected.length) setDefaultBorder(color ?? 'transparent'); + else + selected.forEach(doc => { + doc[DocData].borderColor = color; + }); + } + return ''; +}); + // toggle: Set overlay status of selected document // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: boolean) { @@ -408,6 +451,18 @@ ScriptingGlobals.add(function activeEraserTool() { return StrCast(Doc.UserDoc().activeEraserTool, InkEraserTool.Stroke); }, 'returns the current eraser tool'); +// eslint-disable-next-line prefer-arrow-callback +ScriptingGlobals.add(function setBorderWidth(value: number, checkResult?: boolean) { + const selected = DocumentView.SelectedDocs().lastElement(); + if (checkResult) return NumCast((selected ?? Doc.UserDoc()).borderWidth); + if (!selected) Doc.UserDoc().borderWidth = value; + else + DocumentView.SelectedDocs().map(doc => { + doc.borderWidth = value; + }); + return undefined; +}, 'sets the border width of the selected document'); + // toggle: Set overlay status of selected document // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function setInkProperty(option: InkProperty, value: string | number, checkResult?: boolean) { diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index beea6ab3c..76d6ed80b 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -69,7 +69,7 @@ export class CollectionFreeFormDocumentView extends DocComponent (Doc.LayoutFieldKey(doc) ? [Doc.LayoutFieldKey(doc)] : []); // fields that are configured to be animatable using animation frames public static from(dv?: DocumentView): CollectionFreeFormDocumentView | undefined { return dv?._props.reactParent instanceof CollectionFreeFormDocumentView ? dv._props.reactParent : undefined; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0193fd328..441d6053f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -131,6 +131,7 @@ export class DocumentViewInternal extends DocComponent this._props.styleProvider?.(doc, this._props, sprop); @computed get opacity() { return this.style(this.layoutDoc, StyleProp.Opacity) as number; } // prettier-ignore @computed get boxShadow() { return this.style(this.layoutDoc, StyleProp.BoxShadow) as string; } // prettier-ignore + @computed get border() { return this.style(this.layoutDoc, StyleProp.Border) as string || ""; } // prettier-ignore @computed get borderRounding() { return this.style(this.layoutDoc, StyleProp.BorderRounding) as string; } // prettier-ignore @computed get widgetDecorations() { return this.style(this.layoutDoc, StyleProp.Decorations) as JSX.Element; } // prettier-ignore @computed get backgroundBoxColor(){ return this.style(this.layoutDoc, StyleProp.BackgroundColor + ':docView') as string; } // prettier-ignore @@ -684,14 +685,14 @@ export class DocumentViewInternal extends DocComponent this._rootSelected; - panelHeight = () => this._props.PanelHeight() - this.headerMargin; + panelHeight = () => this._props.PanelHeight() - this.headerMargin - 2 * NumCast(this.Document.borderWidth); screenToLocalContent = () => this._props .ScreenToLocalTransform() - .translate(0, -this.headerMargin) + .translate(-NumCast(this.Document.borderWidth), -this.headerMargin - NumCast(this.Document.borderWidth)) .scale(this._props.showAIEditor ? (this._props.PanelHeight() || 1) / this.aiContentsHeight() : 1); onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHdlr; - setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height)); } // prettier-ignore + setHeight = (height: number) => { !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height + 2 * NumCast(this.Document.borderWidth))); } // prettier-ignore setContentView = action((view: ViewBoxInterface) => { this._componentView = view; }); // prettier-ignore isContentActive = (): boolean | undefined => this._isContentActive; childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)]; @@ -989,15 +990,11 @@ export class DocumentViewInternal extends DocComponent (!SnappingManager.IsDragging || SnappingManager.CanEmbed) && Doc.BrushDoc(this.Document)} onPointerLeave={e => !isParentOf(this._contentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.Document)} style={{ - borderRadius: this.borderRounding, + borderRadius: this._componentView?.isUnstyledView?.() ? undefined : this.borderRounding, pointerEvents: this._pointerEvents === 'visiblePainted' ? 'none' : this._pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here) }}> {this._componentView?.isUnstyledView?.() || this.Document.type === DocumentType.CONFIG || !renderDoc ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.Document[Animation], this.Document)} @@ -1487,7 +1484,7 @@ export class DocumentView extends DocComponent() { ShouldNotScale = () => this.shouldNotScale; NativeWidth = () => this.effectiveNativeWidth; NativeHeight = () => this.effectiveNativeHeight; - PanelWidth = () => this.panelWidth; + PanelWidth = () => this.panelWidth - 2 * NumCast(this.Document.borderWidth); PanelHeight = () => this.panelHeight; ReducedPanelWidth = () => this.panelWidth / 2; ReducedPanelHeight = () => this.panelWidth / 2; diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx index f58862028..f60c83343 100644 --- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx @@ -134,6 +134,7 @@ export class FontIconBox extends ViewBoxBaseComponent() { min={NumCast(this.dataDoc.numBtnMin, 0)} max={NumCast(this.dataDoc.numBtnMax, 100)} number={checkResult} + size={Size.XSMALL} setNumber={undoable(value => numScript(value), `${this.Document.title} button set from list`)} fillWidth /> diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 3abb39ff2..da2131940 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -1282,7 +1282,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, layoutAutoHeight: this.layout_autoHeight, marginsHeight: this.layout_autoHeightMargins }), + () => ({ border: this._props.PanelHeight(), sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, layoutAutoHeight: this.layout_autoHeight, marginsHeight: this.layout_autoHeightMargins }), ({ sidebarHeight, textHeight, layoutAutoHeight, marginsHeight }) => { const newHeight = this.contentScaling * (marginsHeight + Math.max(sidebarHeight, textHeight)); if ( -- cgit v1.2.3-70-g09d2