Skip to content

Commit

Permalink
Merge pull request #4 from IGNF/fix/dialog-portals
Browse files Browse the repository at this point in the history
fix(#3): add portal for dialogs
  • Loading branch information
tonai authored Jan 23, 2025
2 parents d32638b + ad5700e commit dc09407
Show file tree
Hide file tree
Showing 6 changed files with 24 additions and 19 deletions.
8 changes: 4 additions & 4 deletions packages/react-dsfr-tiptap/src/components/Loader.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { LazyExoticComponent, ReactNode, useEffect, useMemo, useState } from "react";
import { ReactNode, useEffect, useMemo, useState } from "react";
import { AnyExtension } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";

import { Control } from "../types/controls";
import { richTextEditorControls } from "../utils/controls";
import { ControlComponent, richTextEditorControls } from "../utils/controls";

import RichTextEditorContent from "./Content";
import RichTextEditorMenu from "./Menu";
Expand All @@ -24,8 +24,8 @@ export type Extension =
| "youtube";

export interface ILoaderProps extends Omit<IProviderProps, "children"> {
controlMap?: Partial<Record<Control, (() => ReactNode) | LazyExoticComponent<() => ReactNode>>>;
controls: (Control | (() => ReactNode) | LazyExoticComponent<() => ReactNode>)[][];
controlMap?: Partial<Record<Control, ControlComponent>>;
controls: (Control | ControlComponent)[][];
extensionLoader?: Partial<Record<Extension, () => Promise<AnyExtension | AnyExtension[]>>>;
menu?: "top" | "bottom";
}
Expand Down
8 changes: 4 additions & 4 deletions packages/react-dsfr-tiptap/src/components/MarkdownEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { LazyExoticComponent, ReactNode } from "react";
import { ReactNode } from "react";
import { EditorEvents } from "@tiptap/react";

import { markdownEditorDefaultControls, markdownEditorDefaultExtensions } from "../constants/markdownEditor";
import { MarkdownControl } from "../types/controls";
import { markdownControls } from "../utils/controls";
import { ControlComponent, markdownControls } from "../utils/controls";

import RichTextEditorProvider from "./Provider";
import RichTextEditorLoader, { ILoaderProps } from "./Loader";
Expand All @@ -12,12 +12,12 @@ import RichTextEditorContent from "./Content";
import RichTextEditorGroup from "./Group";

export interface IMarkdownEditorProps extends Omit<ILoaderProps, "controls"> {
controls?: (MarkdownControl | (() => ReactNode) | LazyExoticComponent<() => ReactNode>)[][];
controls?: (MarkdownControl | ControlComponent)[][];
onContentUpdate?: (content: string) => void;
}

type MarkdownControls = {
[key in MarkdownControl]: (() => ReactNode) | LazyExoticComponent<() => ReactNode>;
[key in MarkdownControl]: ControlComponent;
};

interface IMarkdownEditor extends MarkdownControls {
Expand Down
8 changes: 4 additions & 4 deletions packages/react-dsfr-tiptap/src/components/RichTextEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { LazyExoticComponent, ReactNode } from "react";
import { ReactNode } from "react";
import { EditorEvents } from "@tiptap/react";

import { richTextEditorDefaultControls, richTextEditorDefaultExtensions } from "../constants/richTextEditor";
import { Control } from "../types/controls";
import { richTextEditorControls } from "../utils/controls";
import { ControlComponent, richTextEditorControls } from "../utils/controls";

import RichTextEditorProvider from "./Provider";
import RichTextEditorLoader, { ILoaderProps } from "./Loader";
Expand All @@ -12,12 +12,12 @@ import RichTextEditorMenu from "./Menu";
import RichTextEditorGroup from "./Group";

export interface IRichTextEditorProps extends Omit<ILoaderProps, "controls"> {
controls?: (Control | (() => ReactNode) | LazyExoticComponent<() => ReactNode>)[][];
controls?: (Control | ControlComponent)[][];
onContentUpdate?: (content: string) => void;
}

type RichTextEditorControls = {
[key in Control]: (() => ReactNode) | LazyExoticComponent<() => ReactNode>;
[key in Control]: ControlComponent;
};

interface IRichTextEditor extends RichTextEditorControls {
Expand Down
5 changes: 3 additions & 2 deletions packages/react-dsfr-tiptap/src/controls/createControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ interface IEditorState {
interface ICreateCustomControlProps {
Control: (editor: Editor, editorState: IEditorState, ref: RefObject<IDialogHandle | null>) => ReactNode;
DialogContent?: ElementType;
container?: Element | DocumentFragment;
isActive?: { name: string; attributes?: Record<string, unknown> | string };
isDisabled?: (editor: Editor) => boolean;
}

export function createCustomControl(configuration: ICreateCustomControlProps) {
const { Control, DialogContent, isActive, isDisabled } = configuration;
const { Control, DialogContent, container, isActive, isDisabled } = configuration;
return function CustomControl(): ReactNode {
const editor = useEditor();
const ref = useRef<IDialogHandle>(null);
Expand All @@ -34,7 +35,7 @@ export function createCustomControl(configuration: ICreateCustomControlProps) {
<>
{Control(editor, editorState, ref)}
{DialogContent && (
<Dialog ref={ref}>
<Dialog ref={ref} container={container}>
<DialogContent />
</Dialog>
)}
Expand Down
8 changes: 5 additions & 3 deletions packages/react-dsfr-tiptap/src/dialogs/Dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { forwardRef, ReactNode, useCallback, useId, useImperativeHandle, useMemo, useRef } from "react";
import { createModal } from "@codegouvfr/react-dsfr/Modal/index.js";
import { useIsModalOpen } from "@codegouvfr/react-dsfr/Modal/useIsModalOpen.js";
import { createPortal } from "react-dom";

import { dialogContext } from "../contexts/dialog";

Expand All @@ -9,12 +10,13 @@ export interface IDialogHandle {
open: () => void;
}

interface IDialogProps {
export interface IDialogProps {
children: ReactNode;
container?: Element | DocumentFragment;
}

const Dialog = forwardRef<IDialogHandle, IDialogProps>((props, ref) => {
const { children } = props;
const { children, container = document.body } = props;

const id = useId();
const { current: modal } = useRef(
Expand Down Expand Up @@ -45,7 +47,7 @@ const Dialog = forwardRef<IDialogHandle, IDialogProps>((props, ref) => {
[close, isOpened, modal]
);

return <dialogContext.Provider value={context}>{children}</dialogContext.Provider>;
return <dialogContext.Provider value={context}>{createPortal(children, container)}</dialogContext.Provider>;
});

export default Dialog;
6 changes: 4 additions & 2 deletions packages/react-dsfr-tiptap/src/utils/controls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ import {
} from "../controls/Controls";
import { ControlColor } from "../controls/CustomControls";

export const markdownControls: Record<Exclude<MarkdownControl, DialogControl>, (() => ReactNode) | LazyExoticComponent<() => ReactNode>> = {
export type ControlComponent = (() => ReactNode) | LazyExoticComponent<() => ReactNode>;

export const markdownControls: Record<Exclude<MarkdownControl, DialogControl>, ControlComponent> = {
Blockquote: ControlBlockquote,
Bold: ControlBold,
BulletList: ControlBulletList,
Expand All @@ -55,7 +57,7 @@ export const markdownControls: Record<Exclude<MarkdownControl, DialogControl>, (
Undo: ControlUndo,
};

export const richTextEditorControls: Record<Exclude<Control, DialogControl>, (() => ReactNode) | LazyExoticComponent<() => ReactNode>> = {
export const richTextEditorControls: Record<Exclude<Control, DialogControl>, ControlComponent> = {
...markdownControls,
AlignCenter: ControlAlignCenter,
AlignJustify: ControlAlignJustify,
Expand Down

0 comments on commit dc09407

Please sign in to comment.