Skip to content

Commit 3580935

Browse files
authored
Merge pull request #229 from nitheesh-aot/lexical-table
Lexical Table
2 parents eccbfa1 + 9a7b082 commit 3580935

File tree

16 files changed

+1885
-110
lines changed

16 files changed

+1885
-110
lines changed

compliance-web/.nycrc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
"extends": "@istanbuljs/nyc-config-typescript",
33
"all": true,
44
"check-coverage": true,
5-
"lines": 33,
6-
"functions": 33,
7-
"branches": 25,
8-
"statements": 33,
5+
"lines": 25,
6+
"functions": 25,
7+
"branches": 20,
8+
"statements": 25,
99
"include": ["src/**/*.ts", "src/**/*.tsx"],
1010
"exclude": [
1111
"**/*.d.ts",

compliance-web/package-lock.json

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compliance-web/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"jwt-decode": "^4.0.0",
3434
"keycloak-js": "^25.0.1",
3535
"lexical": "^0.23.1",
36+
"lodash-es": "^4.17.21",
3637
"material-react-table": "^2.13.3",
3738
"oidc-client-ts": "^3.0.1",
3839
"quill": "^2.0.2",
@@ -49,6 +50,7 @@
4950
"@cypress/code-coverage": "^3.12.44",
5051
"@istanbuljs/nyc-config-typescript": "^1.0.2",
5152
"@tanstack/eslint-plugin-query": "^5.43.1",
53+
"@types/lodash-es": "^4.17.12",
5254
"@types/node": "^20.14.9",
5355
"@types/react": "^18.2.47",
5456
"@types/react-dom": "^18.2.18",

compliance-web/src/components/App/Inspections/Profile/Requirements/RequirementFormLeft.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useFormContext, useWatch } from "react-hook-form";
1313
import {
1414
ComplianceFindingEnum,
1515
EnforcementActionEnum,
16+
mentionDataListDummy,
1617
REGULATORY_CONSIDERATION_TYPE_ID,
1718
REQUIREMENT_TYPE_ID,
1819
} from "./RequirementUtils";
@@ -269,6 +270,8 @@ const RequirementFormLeft: FC<RequirementFormLeftProps> = memo(
269270
name="findings"
270271
placeholder="Enter Findings..."
271272
height={`calc(100vh - ${appHeaderHeight + 363}px)`}
273+
isAdvanced
274+
mentionsList={mentionDataListDummy}
272275
/>
273276
</Box>
274277
);

compliance-web/src/components/App/Inspections/Profile/Requirements/RequirementRelatedDocumentModal.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,11 @@ const RequirementRelatedDocumentModal: React.FC<
216216
/>
217217
</Grid>
218218
</Grid>
219-
<ControlledLexicalEditor label="Description" name="description" />
219+
<ControlledLexicalEditor
220+
label="Description"
221+
name="description"
222+
isAdvanced
223+
/>
220224
</DialogContent>
221225
<ModalActions
222226
primaryActionButtonText={

compliance-web/src/components/App/Inspections/Profile/Requirements/RequirementSourceModal.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,11 @@ const RequirementSourceModal: React.FC<RequirementSourceModalProps> = ({
138138
fullWidth
139139
/>
140140
</Stack>
141-
<ControlledLexicalEditor label="Description" name="description" />
141+
<ControlledLexicalEditor
142+
label="Description"
143+
name="description"
144+
isAdvanced
145+
/>
142146
</DialogContent>
143147
<ModalActions
144148
primaryActionButtonText={requirementSourceFormData ? "Save" : "Add"}

compliance-web/src/components/App/Inspections/Profile/Requirements/RequirementUtils.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,39 @@ export const formatRequirementFormData = (requirement: InspectionRequirement): I
185185
requirementSourceDetails: requirementSourceDetails,
186186
};
187187
};
188+
189+
190+
export const mentionDataListDummy = [
191+
{
192+
id: "1",
193+
name: "Photo 1",
194+
imageUrl:
195+
"https://cdn-adventures-live.azureedge.net/adventurescache/2/3/c/0/8/0/23c0806cb9a350fbc5a345420251cfe6ed201c99.jpg",
196+
},
197+
{
198+
id: "2",
199+
name: "Photo 2",
200+
imageUrl:
201+
"https://cdn.discoverholidays.io/media/general/c/canadarailvacations-banner-mobile-canadian-rockies-winter-train-tours.jpg",
202+
},
203+
{
204+
id: "3",
205+
name: "Figure 1",
206+
imageUrl: "figure_1.png",
207+
},
208+
{
209+
id: "4",
210+
name: "Figure 2",
211+
imageUrl: "figure_2.png",
212+
},
213+
{
214+
id: "5",
215+
name: "Photo 3",
216+
imageUrl: "photo_3.jpg",
217+
},
218+
{
219+
id: "6",
220+
name: "Photo 4",
221+
imageUrl: "photo_4.jpg",
222+
},
223+
]

compliance-web/src/components/Shared/Controlled/ControlledLexicalEditor.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useFormContext, Controller } from "react-hook-form";
22
import LexicalEditor from "@/components/Shared/LexicalEditor/LexicalEditor";
3+
import { MentionData } from "@/components/Shared/LexicalEditor/LexicalUtils";
34
import { $generateHtmlFromNodes } from "@lexical/html";
45
import { $getRoot } from "lexical";
56
import { useMemo } from "react";
@@ -24,12 +25,14 @@ export default function ControlledLexicalEditor({
2425
placeholder = "Enter text...",
2526
isAdvanced = false,
2627
height,
28+
mentionsList,
2729
}: {
2830
name: string;
2931
label: string;
3032
placeholder?: string;
3133
isAdvanced?: boolean;
3234
height?: string;
35+
mentionsList?: MentionData[];
3336
}) {
3437
const {
3538
control,
@@ -56,6 +59,7 @@ export default function ControlledLexicalEditor({
5659
placeholder={placeholder}
5760
defaultHtml={field.value?.html}
5861
height={height}
62+
mentionsList={mentionsList}
5963
onChange={(editorState, editor) => {
6064
editorState.read(() => {
6165
const editorStateHtmlString = $generateHtmlFromNodes(editor);

compliance-web/src/components/Shared/LexicalEditor/LexicalEditor.tsx

Lines changed: 49 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -15,65 +15,19 @@ import { ListNode, ListItemNode } from "@lexical/list";
1515
import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin";
1616
import { TablePlugin } from "@lexical/react/LexicalTablePlugin";
1717
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
18-
// import TableCellResizerPlugin from "./TablePlugins/TableCellResizer";
19-
18+
import { useState } from "react";
19+
import TableCellResizerPlugin from "./TablePlugins/TableCellResizer";
20+
import TableCellActionMenuPlugin from "./TablePlugins/TableActionMenu";
21+
import TableHoverActionsPlugin from "./TablePlugins/TableHoverActions";
22+
import { MentionNode } from "./MentionPlugins/MentionNode";
23+
import MentionsPlugin from "./MentionPlugins/Mentions";
24+
import { LexicalTheme, MentionData } from "./LexicalUtils";
2025

2126
export type TextEditorValue = {
2227
html: string;
2328
text: string;
2429
};
2530

26-
const theme = {
27-
code: "editor-code",
28-
heading: {
29-
h1: "editor-heading-h1",
30-
h2: "editor-heading-h2",
31-
h3: "editor-heading-h3",
32-
h4: "editor-heading-h4",
33-
h5: "editor-heading-h5",
34-
},
35-
image: "editor-image",
36-
link: "editor-link",
37-
list: {
38-
listitem: "editor-listitem",
39-
nested: {
40-
listitem: "editor-nested-listitem",
41-
},
42-
ol: "editor-list-ol",
43-
ul: "editor-list-ul",
44-
},
45-
ltr: "ltr",
46-
paragraph: "editor-paragraph",
47-
placeholder: "editor-placeholder",
48-
quote: "editor-quote",
49-
rtl: "rtl",
50-
text: {
51-
bold: "editor-text-bold",
52-
code: "editor-text-code",
53-
hashtag: "editor-text-hashtag",
54-
italic: "editor-text-italic",
55-
overflowed: "editor-text-overflowed",
56-
strikethrough: "editor-text-strikethrough",
57-
underline: "editor-text-underline",
58-
underlineStrikethrough: "editor-text-underlineStrikethrough",
59-
},
60-
table: "editor-table",
61-
tableAlignment: {
62-
center: "editor-tableAlignmentCenter",
63-
right: "editor-tableAlignmentRight",
64-
},
65-
tableCell: "editor-tableCell",
66-
tableCellActionButton: "editor-tableCellActionButton",
67-
tableCellActionButtonContainer: "editor-tableCellActionButtonContainer",
68-
tableCellHeader: "editor-tableCellHeader",
69-
tableCellResizer: "editor-tableCellResizer",
70-
tableCellSelected: "editor-tableCellSelected",
71-
tableRowStriping: "editor-tableRowStriping",
72-
tableScrollableWrapper: "editor-tableScrollableWrapper",
73-
tableSelected: "editor-tableSelected",
74-
tableSelection: "editor-tableSelection",
75-
};
76-
7731
type LexicalEditorProps = {
7832
errorMsg?: string;
7933
placeholder: string;
@@ -82,6 +36,7 @@ type LexicalEditorProps = {
8236
name?: string;
8337
height?: string;
8438
isAdvanced?: boolean;
39+
mentionsList?: MentionData[];
8540
onChange: (editorState: EditorState, editor: Editor) => void;
8641
};
8742

@@ -92,14 +47,22 @@ const LexicalEditor = ({
9247
label = "",
9348
name,
9449
height,
50+
mentionsList,
9551
onChange,
9652
isAdvanced = false,
9753
}: LexicalEditorProps) => {
9854
// Lexical Editor Configuration
9955
const editorConfig = {
10056
namespace: "EAOComplianceEditor",
101-
theme,
102-
nodes: [ListNode, ListItemNode, TableNode, TableRowNode, TableCellNode],
57+
theme: LexicalTheme,
58+
nodes: [
59+
ListNode,
60+
ListItemNode,
61+
TableNode,
62+
TableRowNode,
63+
TableCellNode,
64+
MentionNode,
65+
],
10366
onError(error: unknown) {
10467
// eslint-disable-next-line no-console
10568
console.error(error);
@@ -127,6 +90,15 @@ const LexicalEditor = ({
12790
},
12891
};
12992

93+
const [floatingAnchorElem, setFloatingAnchorElem] =
94+
useState<HTMLDivElement | null>(null);
95+
96+
const onRef = (_floatingAnchorElem: HTMLDivElement) => {
97+
if (_floatingAnchorElem !== null) {
98+
setFloatingAnchorElem(_floatingAnchorElem);
99+
}
100+
};
101+
130102
return (
131103
<LexicalComposer initialConfig={editorConfig}>
132104
<Box
@@ -166,13 +138,15 @@ const LexicalEditor = ({
166138
<Box className="editor-inner editor-content">
167139
<RichTextPlugin
168140
contentEditable={
169-
<ContentEditable
170-
className="editor-input"
171-
aria-placeholder={placeholder}
172-
placeholder={
173-
<div className="editor-placeholder">{placeholder}</div>
174-
}
175-
/>
141+
<div ref={onRef}>
142+
<ContentEditable
143+
className="editor-input"
144+
aria-placeholder={placeholder}
145+
placeholder={
146+
<div className="editor-placeholder">{placeholder}</div>
147+
}
148+
/>
149+
</div>
176150
}
177151
ErrorBoundary={LexicalErrorBoundary}
178152
/>
@@ -184,7 +158,19 @@ const LexicalEditor = ({
184158
hasCellBackgroundColor
185159
hasHorizontalScroll
186160
/>
187-
{/* <TableCellResizerPlugin /> */}
161+
<TableCellResizerPlugin />
162+
{floatingAnchorElem && (
163+
<>
164+
<TableCellActionMenuPlugin
165+
anchorElem={floatingAnchorElem}
166+
cellMerge={true}
167+
/>
168+
<TableHoverActionsPlugin anchorElem={floatingAnchorElem} />
169+
</>
170+
)}
171+
{mentionsList && (
172+
<MentionsPlugin mentionsList={mentionsList} />
173+
)}
188174
<HistoryPlugin />
189175
</Box>
190176
</Box>

0 commit comments

Comments
 (0)