From 7d8b0c8d969601a9964112d162951b23632c02f3 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Mon, 16 Dec 2024 16:42:15 +0100 Subject: [PATCH 1/2] fix: multiple feedbacks fix --- .../rich-text-web/src/components/Editor.tsx | 4 ++- .../src/components/EditorWrapper.tsx | 26 +++++++++-------- .../rich-text-web/src/utils/themes/mxTheme.ts | 28 ++++++++++--------- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx index 26d5bcc34f..bb3cb07e42 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx @@ -26,11 +26,13 @@ export interface EditorProps { className?: string; toolbarId?: string | Array; readOnly?: boolean; + tabIndex?: number; } // Editor is an uncontrolled React component const Editor = forwardRef((props: EditorProps, ref: MutableRefObject) => { - const { theme, defaultValue, style, className, toolbarId, onTextChange, onSelectionChange, readOnly } = props; + const { theme, defaultValue, style, className, toolbarId, onTextChange, onSelectionChange, readOnly, tabIndex } = + props; const containerRef = useRef(null); const modalRef = useRef(null); const onTextChangeRef = useRef(onTextChange); diff --git a/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx b/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx index e84226ae39..8fd2c2db06 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx @@ -37,7 +37,8 @@ export default function EditorWrapper(props: EditorWrapperProps): ReactElement { onLoad, readOnlyStyle, toolbarOptions, - enableStatusBar + enableStatusBar, + tabIndex } = props; const isFirstLoad = useRef(false); const quillRef = useRef(null); @@ -100,7 +101,6 @@ export default function EditorWrapper(props: EditorWrapperProps): ReactElement { if (!isFocus) { setIsFocus(true); executeAction(onFocus); - editorValueRef.current = quillRef.current?.getText() || ""; } } else { @@ -145,24 +145,17 @@ export default function EditorWrapper(props: EditorWrapperProps): ReactElement { } }} spellCheck={props.spellCheck} + tabIndex={tabIndex} > {toolbarLocation === "auto" && }
- - - + + +
{enableStatusBar && (
diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/themes/mxTheme.ts b/packages/pluggableWidgets/rich-text-web/src/utils/themes/mxTheme.ts index 89a4a9c9d3..ada0221d36 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/themes/mxTheme.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/themes/mxTheme.ts @@ -37,21 +37,23 @@ export default class MendixTheme extends SnowTheme { /** updating font picker selected item based on current's selection font */ updateFontPicker(range: Range): void { - const currentRange = range || { index: 0, length: 0 }; - if (!this.fontPicker) { - this.fontPicker = this.pickers.find(picker => picker.container.classList.contains("ql-font")); - } + if (this.pickers) { + const currentRange = range || { index: 0, length: 0 }; + if (!this.fontPicker) { + this.fontPicker = this.pickers.find(picker => picker.container.classList.contains("ql-font")); + } - const format = this.quill.getFormat(currentRange.index, currentRange.length); - let font = format ? (format.font as string) : undefined; - if (!font) { - // default font - font = "helvetica"; - } + const format = this.quill.getFormat(currentRange.index, currentRange.length); + let font = format ? (format.font as string) : undefined; + if (!font) { + // default font + font = "helvetica"; + } - const currentOption = this.fontPicker?.container.querySelector(`[data-value=${font}]`); - if (currentOption) { - this.fontPicker?.selectItem(currentOption as HTMLElement, false); + const currentOption = this.fontPicker?.container.querySelector(`[data-value=${font}]`); + if (currentOption) { + this.fontPicker?.selectItem(currentOption as HTMLElement, false); + } } } } From 8da57c94d5f5566479d8de3f231d17aafacf9865 Mon Sep 17 00:00:00 2001 From: gjulivan Date: Mon, 6 Jan 2025 17:55:31 +0100 Subject: [PATCH 2/2] fix: dimension configurations --- .../src/RichText.editorConfig.ts | 18 ++++++-- .../rich-text-web/src/RichText.tsx | 11 +---- .../rich-text-web/src/RichText.xml | 42 +++++++++++++++++-- .../src/components/EditorWrapper.tsx | 21 ++++++---- .../rich-text-web/src/utils/helpers.ts | 32 +++++++++----- .../rich-text-web/typings/RichTextProps.d.ts | 16 ++++++- 6 files changed, 104 insertions(+), 36 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/RichText.editorConfig.ts b/packages/pluggableWidgets/rich-text-web/src/RichText.editorConfig.ts index 35806cfe1f..38af23bcf9 100644 --- a/packages/pluggableWidgets/rich-text-web/src/RichText.editorConfig.ts +++ b/packages/pluggableWidgets/rich-text-web/src/RichText.editorConfig.ts @@ -30,12 +30,24 @@ export function getProperties(values: RichTextPreviewProps, defaultProperties: P hidePropertiesIn(defaultProperties, values, toolbarGroupKeys); } - if (values.heightUnit === "pixels") { + if (values.heightUnit === "percentageOfWidth") { + hidePropertyIn(defaultProperties, values, "height"); + } else { + hidePropertiesIn(defaultProperties, values, [ + "minHeight", + "minHeightUnit", + "maxHeight", + "maxHeightUnit", + "OverflowY" + ]); + } + + if (values.minHeightUnit === "none") { hidePropertyIn(defaultProperties, values, "minHeight"); } - if (values.widthUnit === "percentage" && values.heightUnit === "percentageOfWidth") { - hidePropertyIn(defaultProperties, values, "height"); + if (values.maxHeightUnit === "none") { + hidePropertiesIn(defaultProperties, values, ["maxHeight", "OverflowY"]); } if (!values.onChange) { diff --git a/packages/pluggableWidgets/rich-text-web/src/RichText.tsx b/packages/pluggableWidgets/rich-text-web/src/RichText.tsx index b5d9d9042f..b8e97601f9 100644 --- a/packages/pluggableWidgets/rich-text-web/src/RichText.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/RichText.tsx @@ -1,5 +1,4 @@ import { ValidationAlert } from "@mendix/widget-plugin-component-kit/Alert"; -import { getDimensions } from "@mendix/widget-plugin-platform/utils/get-dimensions"; import classNames from "classnames"; import { createElement, Fragment, useEffect, useState } from "react"; import { RichTextContainerProps } from "../typings/RichTextProps"; @@ -8,15 +7,9 @@ import "./ui/RichText.scss"; import { constructWrapperStyle } from "./utils/helpers"; export default function RichText(props: RichTextContainerProps): JSX.Element { - const { stringAttribute, width: w, height: h, widthUnit, heightUnit, readOnlyStyle } = props; + const { stringAttribute, readOnlyStyle } = props; - const { width, height } = getDimensions({ - width: w, - widthUnit, - height: h, - heightUnit - }); - const wrapperStyle = constructWrapperStyle(props, { width, height }); + const wrapperStyle = constructWrapperStyle(props); const [isIncubator, setIsIncubator] = useState(true); useEffect(() => { diff --git a/packages/pluggableWidgets/rich-text-web/src/RichText.xml b/packages/pluggableWidgets/rich-text-web/src/RichText.xml index a16851f8e2..c2e6d0cecb 100644 --- a/packages/pluggableWidgets/rich-text-web/src/RichText.xml +++ b/packages/pluggableWidgets/rich-text-web/src/RichText.xml @@ -64,7 +64,7 @@ Width unit - Percentage: portion of parent size. Pixels: absolute amount of pixels. + Percentage Pixels @@ -78,18 +78,52 @@ Height unit - Percentage of width + Auto Pixels - Percentage of parent + Percentage + Viewport Height + + Minimum Height unit + + + None + Pixels + Percentage + Viewport + + Minimum height - Editor's minimum height. The number value is in pixels. + + + + Maximum Height unit + + + None + Pixels + Percentage + Viewport + + + + Maximum height + + + + Vertical Overflow + + + Auto + Scroll + Hidden + diff --git a/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx b/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx index 8fd2c2db06..89d5fe5b93 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx @@ -132,16 +132,17 @@ export default function EditorWrapper(props: EditorWrapperProps): ReactElement { "flex-column", `${stringAttribute?.readOnly ? `editor-${readOnlyStyle}` : ""}` )} - style={{ - maxWidth: style?.maxWidth - }} + style={{ width: style?.width }} onClick={e => { // click on other parts of editor, such as the toolbar, should also set focus - if ( - toolbarRef.current === (e.target as HTMLDivElement) || - toolbarRef.current?.contains(e.target as Node) - ) { - quillRef?.current?.focus(); + if (!quillRef?.current?.hasFocus()) { + if ( + toolbarRef.current === (e.target as HTMLDivElement) || + toolbarRef.current?.contains(e.target as Node) || + e.target === quillRef?.current?.container.parentElement + ) { + quillRef?.current?.focus(); + } } }} spellCheck={props.spellCheck} @@ -159,10 +160,12 @@ export default function EditorWrapper(props: EditorWrapperProps): ReactElement { theme={"snow"} ref={quillRef} defaultValue={stringAttribute.value} + // style={{height: style?.height}} style={{ height: style?.height, minHeight: style?.minHeight, - maxHeight: style?.maxHeight + maxHeight: style?.maxHeight, + overflowY: style?.overflowY }} toolbarId={shouldHideToolbar ? undefined : toolbarOptions ? toolbarOptions : toolbarId} onTextChange={onTextChange} diff --git a/packages/pluggableWidgets/rich-text-web/src/utils/helpers.ts b/packages/pluggableWidgets/rich-text-web/src/utils/helpers.ts index 3aa679cbc2..399318d213 100644 --- a/packages/pluggableWidgets/rich-text-web/src/utils/helpers.ts +++ b/packages/pluggableWidgets/rich-text-web/src/utils/helpers.ts @@ -3,19 +3,31 @@ import Quill from "quill"; import { Delta, Op } from "quill/core"; import { RichTextContainerProps } from "typings/RichTextProps"; -export function constructWrapperStyle(props: RichTextContainerProps, currentStyle: CSSProperties): CSSProperties { - const { width, height } = currentStyle; - const { minHeight, heightUnit, widthUnit } = props; +function getHeightScale(height: number, heightUnit: "pixels" | "percentageOfParent" | "percentageOfView") { + return `${height}${heightUnit === "pixels" ? "px" : heightUnit === "percentageOfView" ? "vh" : "%"}`; +} - const wrapperStyle: Pick = { width, height }; +export function constructWrapperStyle(props: RichTextContainerProps): CSSProperties { + const { widthUnit, heightUnit, minHeightUnit, maxHeightUnit, width, height, minHeight, maxHeight, OverflowY } = + props; - if (heightUnit !== "pixels") { - wrapperStyle.minHeight = minHeight; - delete wrapperStyle.height; - } + const wrapperStyle: Pick = + {}; + + wrapperStyle.width = `${width}${widthUnit === "pixels" ? "px" : "%"}`; + if (heightUnit === "percentageOfWidth") { + wrapperStyle.height = "auto"; - if (widthUnit === "pixels") { - wrapperStyle.maxWidth = width; + if (minHeightUnit !== "none") { + wrapperStyle.minHeight = getHeightScale(minHeight, minHeightUnit); + } + + if (maxHeightUnit !== "none") { + wrapperStyle.maxHeight = getHeightScale(maxHeight, maxHeightUnit); + wrapperStyle.overflowY = OverflowY; + } + } else { + wrapperStyle.height = getHeightScale(height, heightUnit); } return wrapperStyle; diff --git a/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts b/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts index 8f48b4bbbe..bcadd55b33 100644 --- a/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts +++ b/packages/pluggableWidgets/rich-text-web/typings/RichTextProps.d.ts @@ -13,7 +13,13 @@ export type ReadOnlyStyleEnum = "text" | "bordered" | "readPanel"; export type WidthUnitEnum = "percentage" | "pixels"; -export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent"; +export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type MinHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type MaxHeightUnitEnum = "none" | "pixels" | "percentageOfParent" | "percentageOfView"; + +export type OverflowYEnum = "auto" | "scroll" | "hidden"; export type OnChangeTypeEnum = "onLeave" | "onDataChange"; @@ -42,7 +48,11 @@ export interface RichTextContainerProps { width: number; heightUnit: HeightUnitEnum; height: number; + minHeightUnit: MinHeightUnitEnum; minHeight: number; + maxHeightUnit: MaxHeightUnitEnum; + maxHeight: number; + OverflowY: OverflowYEnum; onChange?: ActionValue; onFocus?: ActionValue; onBlur?: ActionValue; @@ -76,7 +86,11 @@ export interface RichTextPreviewProps { width: number | null; heightUnit: HeightUnitEnum; height: number | null; + minHeightUnit: MinHeightUnitEnum; minHeight: number | null; + maxHeightUnit: MaxHeightUnitEnum; + maxHeight: number | null; + OverflowY: OverflowYEnum; onChange: {} | null; onFocus: {} | null; onBlur: {} | null;