Skip to content

Commit

Permalink
Merge branch 'main' of github.com:locoworks/reusejs-react-v2
Browse files Browse the repository at this point in the history
  • Loading branch information
Shrey Dhyani authored and Shrey Dhyani committed Dec 9, 2023
2 parents 976ca96 + 61ad643 commit 608cde3
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 45 deletions.
9 changes: 9 additions & 0 deletions components/text-editor/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# @locoworks/reusejs-react-text-editor

## 0.1.4

### Patch Changes

- d7871ed: Changes:

- Added prop for prepopulation of editor using htmlData.
- Removed AutoFocusPlugin

## 0.1.3

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion components/text-editor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@locoworks/reusejs-react-text-editor",
"version": "0.1.3",
"version": "0.1.4",
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/types/index.d.ts",
Expand Down
34 changes: 25 additions & 9 deletions components/text-editor/src/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useEffect } from "react";
import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin";
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
Expand All @@ -8,7 +7,7 @@ import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
import { ListPlugin } from "@lexical/react/LexicalListPlugin";
import LexicalClickableLinkPlugin from "@lexical/react/LexicalClickableLinkPlugin";
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
import { $generateHtmlFromNodes } from "@lexical/html";
import { $generateHtmlFromNodes, $generateNodesFromDOM } from "@lexical/html";
import {
AutoLinkPlugin,
createLinkMatcherWithRegExp,
Expand All @@ -18,7 +17,7 @@ import { HeadingNode } from "@lexical/rich-text";
import { ListNode, ListItemNode } from "@lexical/list";
import { LinkNode, AutoLinkNode } from "@lexical/link";
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
import { EditorState, LexicalEditor } from "lexical";
import { $getRoot, $insertNodes, EditorState, LexicalEditor } from "lexical";

import { EditorTheme } from "../theme";
import { MentionNode } from "../plugins/MentionPlugin/MentionNode";
Expand All @@ -38,6 +37,8 @@ type EditorProps = {
}>;
convertFilesToImageUrl: (files: FileList | null) => Array<string> | null;
onChangeCallback?: (editorRef: LexicalEditor | null, payload: any) => void;
placeholderText?: string;
htmlData?: string;
};
function Editor({
editorRef,
Expand All @@ -46,6 +47,8 @@ function Editor({
useMentionLookupService,
convertFilesToImageUrl,
onChangeCallback,
placeholderText = "Start Typing...",
htmlData,
}: EditorProps): JSX.Element {
const [editor] = useLexicalComposerContext();
const isEditable = useLexicalEditable();
Expand All @@ -54,20 +57,36 @@ function Editor({
editor.setEditable(editState);
}, [editState, editor]);

const text = "Enter some text";
const placeholder = <div className="placeholder">{text}</div>;
const placeholder = <div className="placeholder">{placeholderText}</div>;

const onChange = (_editorState: EditorState, editor: LexicalEditor) => {
editor.update(() => {
const payload: any = {};
const htmlString = $generateHtmlFromNodes(editor, null);
payload["html"] = htmlString;
payload["json"] = JSON.stringify(editor.getEditorState());

onChangeCallback?.(editorRef.current, payload);
});

return (editorRef.current = editor);
};

useEffect(() => {
editor.update(() => {
if (htmlData) {
const parser = new DOMParser();
const dom = parser.parseFromString(htmlData, "text/html");

if ($getRoot().getFirstChild() === null) {
const nodes = $generateNodesFromDOM(editor, dom);
$getRoot().select();
$insertNodes(nodes);
}
}
});
}, []);

const URL_REGEX =
/(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,}|http:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|http:\/\/www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|http:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|http:\/\/www\.[a-zA-Z0-9]+\.[^\s]{2,})/;
const EMAIL_REGEX =
Expand All @@ -81,6 +100,7 @@ function Editor({
return `mailto:${text}`;
}),
];

const cellEditorConfig = {
namespace: "Table",
nodes: [
Expand All @@ -107,7 +127,6 @@ function Editor({
setEditable={setEditable}
/>
<ListPlugin />
<AutoFocusPlugin />
<RichTextPlugin
contentEditable={
<div className="editor-scroller">
Expand All @@ -121,12 +140,10 @@ function Editor({
/>
<HistoryPlugin />
<AutoLinkPlugin matchers={MATCHERS} />
<AutoFocusPlugin />
<TabIndentationPlugin />
<ImagesPlugin />
<MentionPlugin useMentionLookupService={useMentionLookupService} />
<NewTablePlugin cellEditorConfig={cellEditorConfig}>
<AutoFocusPlugin />
<RichTextPlugin
contentEditable={
<ContentEditable className="TableNode__contentEditable" />
Expand All @@ -137,7 +154,6 @@ function Editor({
<HistoryPlugin />
<LexicalClickableLinkPlugin />
</NewTablePlugin>

{isEditable && <LexicalClickableLinkPlugin />}
<OnChangePlugin onChange={onChange} />
</div>
Expand Down
11 changes: 8 additions & 3 deletions components/text-editor/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ type Props = {
wrapperClass?: string;
editable: boolean;
setEditable: React.Dispatch<React.SetStateAction<boolean>>;
prePopulate?: () => void;
placeholderText?: string;
htmlData?: string;
};

const TextEditor = ({
Expand All @@ -33,11 +34,13 @@ const TextEditor = ({
wrapperClass,
editable,
setEditable,
prePopulate,
placeholderText,
htmlData,
}: Props) => {
const editorRef = useRef<LexicalEditor>(null);

const initialConfig = {
editorState: prePopulate || null,
editorState: null,
namespace: "Editor",
theme: EditorTheme,
onError: (error: Error) => {
Expand All @@ -62,12 +65,14 @@ const TextEditor = ({
<TableContext>
<div className="editor-shell">
<Editor
htmlData={htmlData}
convertFilesToImageUrl={convertFilesToImageUrl}
useMentionLookupService={useMentionLookupService}
onChangeCallback={onChangeCallback}
editState={editable}
setEditable={setEditable}
editorRef={editorRef}
placeholderText={placeholderText}
/>
</div>
</TableContext>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useState } from "react";
import { $getRoot, $createTextNode, $createParagraphNode } from "lexical";
import { TextEditor } from "@locoworks/reusejs-react-text-editor";
import "@locoworks/reusejs-react-text-editor/css";

const PrepopulatedTextEditor = () => {
const htmlData = `<p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">Delivery was increasing prior to 2020 and became particularly important during the COVID-19 pandemic. The Delivery Experience tracker helps Chick-fil-A identify best in class delivery brands in and out of the QSR industry. This research also helps Chick-fil-A determine drivers of excellent delivery experiences across QSRs and then track Chick-fil-A performance vs competitors on those drivers over time.</span></p><table class="html_table"><colgroup><col><col><col><col><col></colgroup><tbody><tr><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">fsdjhfksfdsf</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsdddd</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdsakjdsn</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsdsadasdas</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dadsadas</span></p></th></tr><tr><th class="html_cell"><p class="EditorTheme__paragraph"><span style="white-space: pre-wrap;">fsdjhfksfdsf</span></p></th><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td></tr><tr><th class="html_cell"><p class="EditorTheme__paragraph"><span style="white-space: pre-wrap;">fsdjhfksfdsf</span></p></th><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td></tr></tbody></table><p class="EditorTheme__paragraph"><img src="https://plus.unsplash.com/premium_photo-1668104454442-a251cc42ee58?q=80&amp;w=1887&amp;auto=format&amp;fit=crop&amp;ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="random" width="205" height="307.55126876831054"></p>`;

const [editable, setEditable] = useState(false);
const [data, setData] = useState("");
const [data, setData] = useState(htmlData);

function useMentionLookupService() {
return [
Expand Down Expand Up @@ -33,19 +34,10 @@ const PrepopulatedTextEditor = () => {
setData(payload["html"]);
}

function prepopulatedRichText() {
const root = $getRoot();
if (root.getFirstChild() === null) {
const paragraph = $createParagraphNode();
paragraph.append($createTextNode("Start here!"));
root.append(paragraph);
}
}

return (
<div className="flex flex-col items-center justify-center py-10 mt-10 bg-gray-100 border rounded gap-x-3">
<TextEditor
prePopulate={prepopulatedRichText}
htmlData={htmlData}
editable={editable}
setEditable={setEditable}
useMentionLookupService={useMentionLookupService}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import React, { useState } from "react";
import {
$getRoot,
$createTextNode,
$createParagraphNode,
LexicalEditor,
} from "lexical";
import { LexicalEditor } from "lexical";
import { TextEditor } from "@locoworks/reusejs-react-text-editor";
import "@locoworks/reusejs-react-text-editor/css";

const PrepopulatedTextEditor = () => {
const htmlData: string = `<p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">Delivery was increasing prior to 2020 and became particularly important during the COVID-19 pandemic. The Delivery Experience tracker helps Chick-fil-A identify best in class delivery brands in and out of the QSR industry. This research also helps Chick-fil-A determine drivers of excellent delivery experiences across QSRs and then track Chick-fil-A performance vs competitors on those drivers over time.</span></p><table class="html_table"><colgroup><col><col><col><col><col></colgroup><tbody><tr><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">fsdjhfksfdsf</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsdddd</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdsakjdsn</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsdsadasdas</span></p></th><th class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dadsadas</span></p></th></tr><tr><th class="html_cell"><p class="EditorTheme__paragraph"><span style="white-space: pre-wrap;">fsdjhfksfdsf</span></p></th><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">dsadbmnad</span></p></td></tr><tr><th class="html_cell"><p class="EditorTheme__paragraph"><span style="white-space: pre-wrap;">fsdjhfksfdsf</span></p></th><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td><td class="html_cell"><p class="EditorTheme__paragraph" dir="ltr"><span style="white-space: pre-wrap;">sdadad</span></p></td></tr></tbody></table><p class="EditorTheme__paragraph"><img src="https://plus.unsplash.com/premium_photo-1668104454442-a251cc42ee58?q=80&amp;w=1887&amp;auto=format&amp;fit=crop&amp;ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="random" width="205" height="307.55126876831054"></p>`;

const [editable, setEditable] = useState<boolean>(false);
const [data, setData] = useState<string | TrustedHTML>("");
const [data, setData] = useState<string | TrustedHTML>(htmlData);

function useMentionLookupService() {
return [
Expand Down Expand Up @@ -38,19 +35,10 @@ const PrepopulatedTextEditor = () => {
setData(payload["html"]);
}

function prepopulatedRichText() {
const root = $getRoot();
if (root.getFirstChild() === null) {
const paragraph = $createParagraphNode();
paragraph.append($createTextNode("Start here!"));
root.append(paragraph);
}
}

return (
<div className="flex flex-col items-center justify-center py-10 mt-10 bg-gray-100 border rounded gap-x-3">
<TextEditor
prePopulate={prepopulatedRichText}
htmlData={htmlData}
editable={editable}
setEditable={setEditable}
useMentionLookupService={useMentionLookupService}
Expand Down
8 changes: 5 additions & 3 deletions development/text-editor-app/pages/text-editor/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ The `TextEditor` component accepts the following props:
- `wrapperClass`: An optional class for styling the editor wrapper.
- `editable`: A boolean indicating the edit state of the editor.
- `setEditable`: A function to set the editable state of the editor. It is a React state setter function that accepts a boolean value.
- `prePopulate`: An optional function to set the intialState of the editor.
- `htmlData`: An optional string to set the intialState of the editor. You can pass the html data directly to the editor as its initial state.
- `placeholderText`: An optional string for the placeholder inside the editor. Its value is "Start Typing..." by default.

## Usage/Examples

Expand All @@ -59,7 +60,7 @@ The `TextEditor` component accepts the following props:
```js path=../../components/text-editor/Example name=Example
```

### PrepopulatedTextEditor
### PrepopulatedTextEditor
<PrepopulatedTextEditor/>
```js path=../../components/text-editor/PrepopulatedTextEditor name=PrepopulatedTextEditor
```
Expand Down Expand Up @@ -88,7 +89,8 @@ import "@locoworks/reusejs-react-text-editor/css";
| `wrapperClass` | `String` | An optional class for styling the editor wrapper. |
| `editable` | `Boolean` | A boolean indicating the edit state of the editor. |
| `setEditable` | `React.Dispatch<React.SetStateAction<boolean>>` | Sets the editable state of the editor. |
| `prePopulate` | `() => void` | An optional function to set the initial state of the editor. |
| `htmlData` | `string` | An optional string to set the initial state of the editor. |
| `placeholderText` | `string` | An optional string for the placeholder inside the editor. Its value is "Start Typing..." by default |

## Notes
>The TextEditor component uses the Lexical library for rich text editing.
Expand Down

0 comments on commit 608cde3

Please sign in to comment.