Skip to content

Commit 1d6a530

Browse files
authored
Merge pull request #1 from aaryan610/lexical
Lexical
2 parents 3e5e1ab + b8ad8a7 commit 1d6a530

File tree

20 files changed

+440
-254
lines changed

20 files changed

+440
-254
lines changed

apps/app/components/command-palette/addAsSubIssue.tsx

Lines changed: 102 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1+
// react
12
import React, { useState } from "react";
23
// swr
34
import { mutate } from "swr";
45
// react hook form
56
import { useForm } from "react-hook-form";
67
// headless ui
78
import { Combobox, Dialog, Transition } from "@headlessui/react";
9+
// services
10+
import issuesServices from "lib/services/issues.services";
811
// hooks
912
import useUser from "lib/hooks/useUser";
1013
// icons
11-
import { MagnifyingGlassIcon } from "@heroicons/react/20/solid";
12-
import { FolderIcon } from "@heroicons/react/24/outline";
14+
import { RectangleStackIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
1315
// commons
1416
import { classNames } from "constants/common";
1517
// types
1618
import { IIssue, IssueResponse } from "types";
17-
import { Button } from "ui";
18-
import { PROJECT_ISSUES_DETAILS, PROJECT_ISSUES_LIST } from "constants/fetch-keys";
19-
import issuesServices from "lib/services/issues.services";
19+
// constants
20+
import { PROJECT_ISSUES_LIST } from "constants/fetch-keys";
2021

2122
type Props = {
2223
isOpen: boolean;
@@ -41,18 +42,13 @@ const AddAsSubIssue: React.FC<Props> = ({ isOpen, setIsOpen, parentId }) => {
4142
[];
4243

4344
const {
44-
register,
4545
formState: { errors, isSubmitting },
46-
handleSubmit,
47-
control,
4846
reset,
49-
setError,
5047
} = useForm<FormInput>();
5148

5249
const handleCommandPaletteClose = () => {
5350
setIsOpen(false);
5451
setQuery("");
55-
reset();
5652
};
5753

5854
const addAsSubIssue = (issueId: string) => {
@@ -78,118 +74,112 @@ const AddAsSubIssue: React.FC<Props> = ({ isOpen, setIsOpen, parentId }) => {
7874
};
7975

8076
return (
81-
<>
82-
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
83-
<Dialog as="div" className="relative z-10" onClose={handleCommandPaletteClose}>
77+
<Transition.Root show={isOpen} as={React.Fragment} afterLeave={() => setQuery("")} appear>
78+
<Dialog as="div" className="relative z-10" onClose={handleCommandPaletteClose}>
79+
<Transition.Child
80+
as={React.Fragment}
81+
enter="ease-out duration-300"
82+
enterFrom="opacity-0"
83+
enterTo="opacity-100"
84+
leave="ease-in duration-200"
85+
leaveFrom="opacity-100"
86+
leaveTo="opacity-0"
87+
>
88+
<div className="fixed inset-0 bg-gray-500 bg-opacity-25 transition-opacity" />
89+
</Transition.Child>
90+
91+
<div className="fixed inset-0 z-10 overflow-y-auto p-4 sm:p-6 md:p-20">
8492
<Transition.Child
8593
as={React.Fragment}
8694
enter="ease-out duration-300"
87-
enterFrom="opacity-0"
88-
enterTo="opacity-100"
95+
enterFrom="opacity-0 scale-95"
96+
enterTo="opacity-100 scale-100"
8997
leave="ease-in duration-200"
90-
leaveFrom="opacity-100"
91-
leaveTo="opacity-0"
98+
leaveFrom="opacity-100 scale-100"
99+
leaveTo="opacity-0 scale-95"
92100
>
93-
<div className="fixed inset-0 bg-gray-500 bg-opacity-25 transition-opacity" />
94-
</Transition.Child>
101+
<Dialog.Panel className="relative mx-auto max-w-2xl transform divide-y divide-gray-500 divide-opacity-10 rounded-xl bg-white bg-opacity-80 shadow-2xl ring-1 ring-black ring-opacity-5 backdrop-blur backdrop-filter transition-all">
102+
<Combobox>
103+
<div className="relative m-1">
104+
<MagnifyingGlassIcon
105+
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-gray-900 text-opacity-40"
106+
aria-hidden="true"
107+
/>
108+
<Combobox.Input
109+
className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-gray-900 placeholder-gray-500 focus:ring-0 sm:text-sm outline-none"
110+
placeholder="Search..."
111+
onChange={(e) => setQuery(e.target.value)}
112+
/>
113+
</div>
95114

96-
<div className="fixed inset-0 z-10 overflow-y-auto p-4 sm:p-6 md:p-20">
97-
<Transition.Child
98-
as={React.Fragment}
99-
enter="ease-out duration-300"
100-
enterFrom="opacity-0 scale-95"
101-
enterTo="opacity-100 scale-100"
102-
leave="ease-in duration-200"
103-
leaveFrom="opacity-100 scale-100"
104-
leaveTo="opacity-0 scale-95"
105-
>
106-
<Dialog.Panel className="relative mx-auto max-w-2xl transform divide-y divide-gray-500 divide-opacity-10 rounded-xl bg-white bg-opacity-80 shadow-2xl ring-1 ring-black ring-opacity-5 backdrop-blur backdrop-filter transition-all">
107-
<Combobox
108-
// onChange={(item: ItemType) => {
109-
// const { url, onClick } = item;
110-
// if (url) router.push(url);
111-
// else if (onClick) onClick();
112-
// handleCommandPaletteClose();
113-
// }}
115+
<Combobox.Options
116+
static
117+
className="max-h-80 scroll-py-2 divide-y divide-gray-500 divide-opacity-10 overflow-y-auto"
114118
>
115-
<div className="relative m-1">
116-
<MagnifyingGlassIcon
117-
className="pointer-events-none absolute top-3.5 left-4 h-5 w-5 text-gray-900 text-opacity-40"
119+
{filteredIssues.length > 0 && (
120+
<>
121+
<li className="p-2">
122+
{query === "" && (
123+
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-gray-900">
124+
Issues
125+
</h2>
126+
)}
127+
<ul className="text-sm text-gray-700">
128+
{filteredIssues.map((issue) => {
129+
if (
130+
(issue.parent === "" || issue.parent === null) &&
131+
issue.id !== parentId
132+
)
133+
return (
134+
<Combobox.Option
135+
key={issue.id}
136+
value={{
137+
name: issue.name,
138+
}}
139+
className={({ active }) =>
140+
classNames(
141+
"flex items-center gap-2 cursor-pointer select-none rounded-md px-3 py-2",
142+
active ? "bg-gray-900 bg-opacity-5 text-gray-900" : ""
143+
)
144+
}
145+
onClick={() => {
146+
addAsSubIssue(issue.id);
147+
setIsOpen(false);
148+
}}
149+
>
150+
<span
151+
className={`h-1.5 w-1.5 block rounded-full`}
152+
style={{
153+
backgroundColor: issue.state_detail.color,
154+
}}
155+
/>
156+
{issue.name}
157+
</Combobox.Option>
158+
);
159+
})}
160+
</ul>
161+
</li>
162+
</>
163+
)}
164+
</Combobox.Options>
165+
166+
{query !== "" && filteredIssues.length === 0 && (
167+
<div className="py-14 px-6 text-center sm:px-14">
168+
<RectangleStackIcon
169+
className="mx-auto h-6 w-6 text-gray-900 text-opacity-40"
118170
aria-hidden="true"
119171
/>
120-
<Combobox.Input
121-
className="h-12 w-full border-0 bg-transparent pl-11 pr-4 text-gray-900 placeholder-gray-500 focus:ring-0 sm:text-sm outline-none"
122-
placeholder="Search..."
123-
onChange={(e) => setQuery(e.target.value)}
124-
/>
172+
<p className="mt-4 text-sm text-gray-900">
173+
We couldn{"'"}t find any issue with that term. Please try again.
174+
</p>
125175
</div>
126-
127-
<Combobox.Options
128-
static
129-
className="max-h-80 scroll-py-2 divide-y divide-gray-500 divide-opacity-10 overflow-y-auto"
130-
>
131-
{filteredIssues.length > 0 && (
132-
<>
133-
<li className="p-2">
134-
{query === "" && (
135-
<h2 className="mt-4 mb-2 px-3 text-xs font-semibold text-gray-900">
136-
Issues
137-
</h2>
138-
)}
139-
<ul className="text-sm text-gray-700">
140-
{filteredIssues.map((issue) => {
141-
if (issue.parent === "" || issue.parent === null)
142-
return (
143-
<Combobox.Option
144-
key={issue.id}
145-
value={{
146-
name: issue.name,
147-
}}
148-
className={({ active }) =>
149-
classNames(
150-
"flex items-center gap-2 cursor-pointer select-none rounded-md px-3 py-2",
151-
active ? "bg-gray-900 bg-opacity-5 text-gray-900" : ""
152-
)
153-
}
154-
onClick={() => {
155-
addAsSubIssue(issue.id);
156-
setIsOpen(false);
157-
}}
158-
>
159-
<span
160-
className={`h-1.5 w-1.5 block rounded-full`}
161-
style={{
162-
backgroundColor: issue.state_detail.color,
163-
}}
164-
/>
165-
{issue.name}
166-
</Combobox.Option>
167-
);
168-
})}
169-
</ul>
170-
</li>
171-
</>
172-
)}
173-
</Combobox.Options>
174-
175-
{query !== "" && filteredIssues.length === 0 && (
176-
<div className="py-14 px-6 text-center sm:px-14">
177-
<FolderIcon
178-
className="mx-auto h-6 w-6 text-gray-900 text-opacity-40"
179-
aria-hidden="true"
180-
/>
181-
<p className="mt-4 text-sm text-gray-900">
182-
We couldn{"'"}t find any issue with that term. Please try again.
183-
</p>
184-
</div>
185-
)}
186-
</Combobox>
187-
</Dialog.Panel>
188-
</Transition.Child>
189-
</div>
190-
</Dialog>
191-
</Transition.Root>
192-
</>
176+
)}
177+
</Combobox>
178+
</Dialog.Panel>
179+
</Transition.Child>
180+
</div>
181+
</Dialog>
182+
</Transition.Root>
193183
);
194184
};
195185

apps/app/components/lexical/editor.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { EditorState, LexicalEditor, $getRoot, $getSelection } from "lexical";
1+
import {
2+
EditorState,
3+
$getRoot,
4+
$getSelection,
5+
SerializedEditorState,
6+
LexicalEditor,
7+
} from "lexical";
28
import { LexicalComposer } from "@lexical/react/LexicalComposer";
39
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
410
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
@@ -21,7 +27,7 @@ import { getValidatedValue } from "./helpers/editor";
2127
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
2228

2329
export interface RichTextEditorProps {
24-
onChange: (state: string) => void;
30+
onChange: (state: SerializedEditorState) => void;
2531
id: string;
2632
value: string;
2733
placeholder?: string;
@@ -33,11 +39,17 @@ const RichTextEditor: React.FC<RichTextEditorProps> = ({
3339
value,
3440
placeholder = "Enter some text...",
3541
}) => {
36-
function handleChange(state: EditorState, editor: LexicalEditor) {
37-
state.read(() => {
38-
onChange(JSON.stringify(state.toJSON()));
42+
const handleChange = (editorState: EditorState) => {
43+
editorState.read(() => {
44+
let editorData = editorState.toJSON();
45+
if (onChange) onChange(editorData);
3946
});
40-
}
47+
};
48+
// function handleChange(state: EditorState, editor: LexicalEditor) {
49+
// state.read(() => {
50+
// onChange(state.toJSON());
51+
// });
52+
// }
4153

4254
return (
4355
<LexicalComposer

apps/app/components/lexical/helpers/editor.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ export const positionEditorElement = (editor: any, rect: any) => {
66
editor.style.left = "-1000px";
77
} else {
88
editor.style.opacity = "1";
9-
editor.style.top = `${
10-
rect.top + rect.height + window.pageYOffset + 10
11-
}px`;
9+
editor.style.top = `${rect.top + rect.height + window.pageYOffset + 10}px`;
1210
editor.style.left = `${
1311
rect.left + window.pageXOffset - editor.offsetWidth / 2 + rect.width / 2
1412
}px`;
@@ -22,9 +20,9 @@ export const getValidatedValue = (value: string) => {
2220

2321
if (value) {
2422
try {
25-
const json = JSON.parse(value);
26-
return JSON.stringify(json);
27-
} catch (error) {
23+
console.log(value);
24+
return value;
25+
} catch (e) {
2826
return defaultValue;
2927
}
3028
}

apps/app/components/lexical/viewer.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { FC } from "react";
21
import { LexicalComposer } from "@lexical/react/LexicalComposer";
32
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
43
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
@@ -17,14 +16,11 @@ import { getValidatedValue } from "./helpers/editor";
1716
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
1817

1918
export interface RichTextViewerProps {
20-
id: string;
2119
value: string;
20+
id: string;
2221
}
2322

24-
const RichTextViewer: FC<RichTextViewerProps> = (props) => {
25-
// props
26-
const { value, id } = props;
27-
23+
const RichTextViewer: React.FC<RichTextViewerProps> = ({ value, id }) => {
2824
return (
2925
<LexicalComposer
3026
initialConfig={{
@@ -37,7 +33,7 @@ const RichTextViewer: FC<RichTextViewerProps> = (props) => {
3733
<div className="relative">
3834
<RichTextPlugin
3935
contentEditable={
40-
<ContentEditable className='className="h-[450px] outline-none py-[15px] resize-none overflow-hidden text-ellipsis' />
36+
<ContentEditable className='className="h-[450px] outline-none resize-none overflow-hidden text-ellipsis' />
4137
}
4238
ErrorBoundary={LexicalErrorBoundary}
4339
placeholder={

apps/app/components/project/issues/CreateUpdateIssueModal/SelectAssignee.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const SelectAssignee: React.FC<Props> = ({ control }) => {
4444
multiple={true}
4545
value={value}
4646
onChange={onChange}
47-
icon={<UserIcon className="h-4 w-4 text-gray-400" />}
47+
icon={<UserIcon className="h-3 w-3 text-gray-500" />}
4848
/>
4949
)}
5050
/>

apps/app/components/project/issues/CreateUpdateIssueModal/SelectCycles.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const SelectSprint: React.FC<Props> = ({ control, setIsOpen }) => {
3333
<>
3434
<div className="relative">
3535
<Listbox.Button className="flex items-center gap-1 hover:bg-gray-100 relative border rounded-md shadow-sm px-2 py-1 cursor-pointer focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm duration-300">
36-
<ArrowPathIcon className="h-3 w-3" />
36+
<ArrowPathIcon className="h-3 w-3 text-gray-500" />
3737
<span className="block truncate">
3838
{cycles?.find((i) => i.id.toString() === value?.toString())?.name ?? "Cycle"}
3939
</span>

apps/app/components/project/issues/CreateUpdateIssueModal/SelectLabels.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ const SelectLabels: React.FC<Props> = ({ control }) => {
8383
<>
8484
<div className="relative">
8585
<Listbox.Button className="flex items-center gap-1 hover:bg-gray-100 relative border rounded-md shadow-sm px-2 py-1 cursor-pointer focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm duration-300">
86-
<TagIcon className="h-3 w-3" />
86+
<TagIcon className="h-3 w-3 text-gray-500" />
8787
<span className="block truncate">
8888
{value && value.length > 0
8989
? value.map((id) => issueLabels?.find((i) => i.id === id)?.name).join(", ")

0 commit comments

Comments
 (0)