From 5a9dce1cd218c0200bce23896be508e8729ff6ce Mon Sep 17 00:00:00 2001 From: Yordan Date: Mon, 4 Aug 2025 16:02:06 +0200 Subject: [PATCH 1/5] feat: add form orientation property to rich text modal dialogs and components --- .../rich-text-web/src/RichText.xml | 8 +++++ .../rich-text-web/src/components/Editor.tsx | 2 ++ .../src/components/EditorWrapper.tsx | 4 ++- .../src/components/ModalDialog/Dialog.scss | 14 ++++++++ .../src/components/ModalDialog/Dialog.tsx | 32 ++++++++++++++++--- .../components/ModalDialog/DialogContent.tsx | 18 +++++++++-- .../components/ModalDialog/ImageDialog.tsx | 8 +++-- .../src/components/ModalDialog/LinkDialog.tsx | 8 +++-- .../components/ModalDialog/VideoDialog.tsx | 7 ++-- .../rich-text-web/typings/RichTextProps.d.ts | 4 +++ 10 files changed, 87 insertions(+), 18 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/RichText.xml b/packages/pluggableWidgets/rich-text-web/src/RichText.xml index 94e21433e3..92a508d6b9 100644 --- a/packages/pluggableWidgets/rich-text-web/src/RichText.xml +++ b/packages/pluggableWidgets/rich-text-web/src/RichText.xml @@ -55,6 +55,14 @@ Read panel + + Form orientation + The form orientation for modals (Insert link, Insert image, Insert video). + + Horizontal + Vertical + + diff --git a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx index fbf7a6a4a9..123fa991ca 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/Editor.tsx @@ -38,6 +38,7 @@ export interface EditorProps defaultValue?: string; onTextChange?: (...args: [delta: Delta, oldContent: Delta, source: EmitterSource]) => void; onSelectionChange?: (...args: [range: Range, oldRange: Range, source: EmitterSource]) => void; + formOrientation?: "horizontal" | "vertical"; theme: string; style?: CSSProperties; className?: string; @@ -216,6 +217,7 @@ const Editor = forwardRef((props: EditorProps, ref: MutableRefObject diff --git a/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx b/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx index 02a1957fbb..a078a92282 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/EditorWrapper.tsx @@ -52,7 +52,8 @@ function EditorWrapperInner(props: EditorWrapperProps): ReactElement { tabIndex, imageSource, imageSourceContent, - enableDefaultUpload + enableDefaultUpload, + formOrientation } = props; const globalState = useContext(EditorContext); @@ -215,6 +216,7 @@ function EditorWrapperInner(props: EditorWrapperProps): ReactElement { imageSource={imageSource} imageSourceContent={imageSourceContent} enableDefaultUpload={enableDefaultUpload} + formOrientation={formOrientation} /> {enableStatusBar && ( diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.scss b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.scss index 0638acf03e..624578a70b 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.scss +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.scss @@ -144,6 +144,20 @@ &-content { padding: 20px; flex: 1; + + &.form-vertical { + .form-group { + flex-direction: column; + + .col-sm-3, + .col-sm-9, + .col-sm-12 { + max-width: 100%; + padding-left: 0; + padding-right: 0; + } + } + } } &-footer { diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.tsx b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.tsx index 1256ec9fb4..b2780dfd10 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/Dialog.tsx @@ -9,6 +9,7 @@ import { useRole } from "@floating-ui/react"; import { If } from "@mendix/widget-plugin-component-kit/If"; +import classNames from "classnames"; import { createElement, Fragment, ReactElement } from "react"; import LinkDialog, { LinkDialogProps } from "./LinkDialog"; import VideoDialog, { VideoDialogProps } from "./VideoDialog"; @@ -51,13 +52,24 @@ export type ChildDialogProps = export type DialogProps = BaseDialogProps & ChildDialogProps & - Pick; + Pick & { + formOrientation?: "horizontal" | "vertical"; + }; /** * Dialog components that will be shown on toolbar's button */ export default function Dialog(props: DialogProps): ReactElement { - const { isOpen, onOpenChange, dialogType, config, imageSource, imageSourceContent, enableDefaultUpload } = props; + const { + isOpen, + onOpenChange, + dialogType, + config, + imageSource, + imageSourceContent, + enableDefaultUpload, + formOrientation + } = props; const { refs, context } = useFloating({ open: isOpen, onOpenChange @@ -81,17 +93,26 @@ export default function Dialog(props: DialogProps): ReactElement { >
- + - + @@ -101,6 +122,7 @@ export default function Dialog(props: DialogProps): ReactElement { imageSource={imageSource} imageSourceContent={imageSourceContent} enableDefaultUpload={enableDefaultUpload} + formOrientation={formOrientation} {...(config as ImageDialogProps)} > diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx index 1bdb66946c..1f4a800815 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx @@ -36,10 +36,22 @@ export function DialogHeader(props: DialogHeaderProps): ReactElement { ); } -export function DialogBody(props: PropsWithChildrenWithClass): ReactElement { - const { children, className } = props; +export function DialogBody( + props: PropsWithChildrenWithClass & { formOrientation?: "horizontal" | "vertical" } +): ReactElement { + const { children, className, formOrientation } = props; - return
{children}
; + return ( +
+ {children} +
+ ); } export interface FormControlProps extends PropsWithChildrenWithClass { diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx index d6dba5215d..83849883df 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx @@ -25,10 +25,12 @@ export interface ImageDialogProps extends Pick(); const imageUploadElementRef = useRef(null); @@ -127,9 +129,9 @@ export default function ImageDialog(props: ImageDialogProps): ReactElement { }, [imageUploadElementRef.current]); return ( - + {activeTab === "general" ? "Insert/Edit" : "Embed"} Images - +
{!disableEmbed && (
diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/LinkDialog.tsx b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/LinkDialog.tsx index 78be67ff2a..605be87d83 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/LinkDialog.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/LinkDialog.tsx @@ -1,4 +1,5 @@ import { ChangeEvent, createElement, ReactElement, useState } from "react"; +import classNames from "classnames"; import { type linkConfigType } from "../../utils/formats"; import { DialogBody, DialogContent, DialogFooter, DialogHeader, FormControl } from "./DialogContent"; @@ -6,10 +7,11 @@ export interface LinkDialogProps { onSubmit(value: linkConfigType): void; onClose(): void; defaultValue?: linkConfigType; + formOrientation?: "horizontal" | "vertical"; } export default function LinkDialog(props: LinkDialogProps): ReactElement { - const { onSubmit, onClose } = props; + const { onSubmit, onClose, formOrientation } = props; const [formState, setFormState] = useState({ text: props.defaultValue?.text ?? "", href: props.defaultValue?.href ?? "", @@ -22,9 +24,9 @@ export default function LinkDialog(props: LinkDialogProps): ReactElement { }; return ( - + Insert/Edit Link - + 0; return ( - + {activeTab === "general" ? "Insert/Edit" : "Embed"} Media - +
  • Date: Wed, 6 Aug 2025 15:32:57 +0200 Subject: [PATCH 2/5] feat: add form orientation accessibility support to dialog forms --- .../components/ModalDialog/DialogContent.tsx | 26 ++++++++++++---- .../components/ModalDialog/ImageDialog.tsx | 30 ++++++++++++++++--- .../src/components/ModalDialog/LinkDialog.tsx | 23 ++++++++++---- .../components/ModalDialog/VideoDialog.tsx | 16 ++++++---- 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx index 1f4a800815..9f048ceaf4 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/DialogContent.tsx @@ -56,16 +56,32 @@ export function DialogBody( export interface FormControlProps extends PropsWithChildrenWithClass { label?: string; + formOrientation?: "horizontal" | "vertical"; + inputId?: string; } -export function FormControl(props: FormControlProps): ReactElement { - const { children, className, label } = props; +export function FormControl(props: FormControlProps & { formOrientation?: "horizontal" | "vertical" }): ReactElement { + const { children, className, label, formOrientation, inputId } = props; + + console.log("Form orientation:", props.formOrientation); return ( -
    - {label && } -
    {children}
    +
    + {label && ( + + )} + {formOrientation === "vertical" ? ( + children + ) : ( +
    {children}
    + )}
    ); diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx index 83849883df..a8a700e413 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/ImageDialog.tsx @@ -163,7 +163,11 @@ export default function ImageDialog(props: ImageDialogProps): ReactElement { )}
    - + {defaultValue?.src ? ( ) : enableDefaultUpload ? ( ) : undefined} - + - +
    - + Insert/Edit Link - + - + - + - - diff --git a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/VideoDialog.tsx b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/VideoDialog.tsx index eee0c91f68..7719a82425 100644 --- a/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/VideoDialog.tsx +++ b/packages/pluggableWidgets/rich-text-web/src/components/ModalDialog/VideoDialog.tsx @@ -23,7 +23,7 @@ export function getValueType(value: VideoFormType): VideoFormType { } function GeneralVideoDialog(props: VideoDialogProps): ReactElement { - const { onSubmit, onClose, defaultValue } = props; + const { onSubmit, onClose, defaultValue, formOrientation } = props; const [formState, setFormState] = useState({ src: defaultValue?.src ?? "", width: defaultValue?.width ?? 560, @@ -48,11 +48,12 @@ function GeneralVideoDialog(props: VideoDialogProps): ReactElement { return ( - + {defaultValue?.src ? ( {defaultValue?.src} ) : ( )} - + - + ({ embedcode: "" }); @@ -96,9 +99,10 @@ function EmbedVideoDialog(props: VideoDialogProps): ReactElement { return ( - + {" "}