Skip to content

Commit

Permalink
Integrate Lexical's ChecklistPlugin (#69)
Browse files Browse the repository at this point in the history
* Add support for checklists

* Define list indentation styles on `theme.ts` itself

* Add CheckListIcon

* Add CheckListTransformer

* Bump lexical to 0.13.0

* Add a hitbox when a checkbox is hovered

* Fix breaking changes on LexicalNode

---------

Co-authored-by: Luis Jose Nivar <[email protected]>
  • Loading branch information
BrianUribe6 and LuisNivar authored Feb 7, 2024
1 parent 4474195 commit 2ba7038
Show file tree
Hide file tree
Showing 10 changed files with 1,581 additions and 1,501 deletions.
18 changes: 9 additions & 9 deletions apps/front-end/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
},
"dependencies": {
"@hocuspocus/provider": "^2.8.1",
"@lexical/code": "^0.12.5",
"@lexical/link": "^0.12.5",
"@lexical/list": "^0.12.5",
"@lexical/markdown": "^0.12.5",
"@lexical/react": "^0.12.5",
"@lexical/selection": "^0.12.5",
"@lexical/utils": "^0.12.5",
"@lexical/yjs": "^0.12.5",
"@lexical/code": "^0.13.0",
"@lexical/link": "^0.13.0",
"@lexical/list": "^0.13.0",
"@lexical/markdown": "^0.13.0",
"@lexical/react": "^0.13.0",
"@lexical/selection": "^0.13.0",
"@lexical/utils": "^0.13.0",
"@lexical/yjs": "^0.13.0",
"@radix-ui/react-accordion": "^1.1.1",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-context-menu": "^2.1.3",
Expand All @@ -39,7 +39,7 @@
"eslint": "^8.51.0",
"eslint-config-next": "^13.5.6",
"jotai": "^2.4.3",
"lexical": "^0.12.5",
"lexical": "^0.13.0",
"nanoid": "^5.0.2",
"next": "^13.5.6",
"react": "18.2.0",
Expand Down
1 change: 1 addition & 0 deletions apps/front-end/public/assets/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions apps/front-end/src/app/[workspace]/note/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ListPlugin } from "@lexical/react/LexicalListPlugin";
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
import { TabIndentationPlugin } from "@lexical/react/LexicalTabIndentationPlugin";
import { HeadingNode, QuoteNode } from "@lexical/rich-text";
import { CheckListPlugin } from "@lexical/react/LexicalCheckListPlugin";
import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
import dynamic from "next/dynamic";
import { lazy, useCallback, useState } from "react";
Expand Down Expand Up @@ -119,6 +120,7 @@ function Editor({ params }: { params: { id: string } }) {
username={user?.name}
cursorColor={user?.color}
/>
<CheckListPlugin />
</LexicalComposer>
</div>
);
Expand Down
19 changes: 19 additions & 0 deletions apps/front-end/src/app/[workspace]/note/[id]/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,28 @@ const theme: EditorThemeClasses = {
},
code: "block rounded-md border border-slate-700 p-4 pt-10 bg-neutral-900",
list: {
checklist: "pl-0",
listitemChecked:
"list-none line-through relative mx-2 px-6 outline-none " +
// Checkbox
"before:absolute before:top-1.5 before:left-0 before:border " +
"before:border-transparent before:rounded before:w-4 before:h-4 before:cursor-pointer before:bg-cyan-600 " +
"before:bg-[url('/assets/check.svg')] " +
// Aura (hitbox)
"after:absolute after:-top-0.5 after:-left-2 after:rounded-full after:w-8 after:h-8 " +
"after:rounded after:bg-transparent after:hover:bg-neutral-400/30 after:cursor-pointer",
listitemUnchecked:
"list-none relative mx-2 px-6 outline-none " +
// Checkbox
"before:absolute before:top-1.5 before:left-0 before:border " +
"before:border-slate-600 before:rounded before:w-4 before:h-4 " +
// Aura(hitbox)
"after:absolute after:-top-0.5 after:-left-2 after:rounded-full after:w-8 after:h-8 " +
"after:rounded after:bg-transparent after:hover:bg-neutral-400/30 after:cursor-pointer",
nested: {
listitem: "list-none",
},
ulDepth: ["", "list-[circle]", "list-[square]"],
},
link: "dark:text-cyan-400 dark:visited:text-indigo-400 text-cyan-600 cursor-pointer",
codeHighlight: codeHighlightTheme,
Expand Down
8 changes: 0 additions & 8 deletions apps/front-end/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@
.underline-through {
text-decoration: underline line-through;
}

.prose ul ul {
list-style-type: circle;
}

.prose ul ul ul {
list-style-type: square;
}
}

@layer base {
Expand Down
2 changes: 2 additions & 0 deletions apps/front-end/src/components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
import {
IoImageOutline as ImageOutlineIcon,
IoCheckmark as CheckIcon,
IoCheckboxOutline as CheckListIcon,
} from "react-icons/io5";
import { BsTextParagraph as ParagraphIcon } from "react-icons/bs";
import { MdOutlineClose as CloseIcon } from "react-icons/md";
Expand Down Expand Up @@ -54,4 +55,5 @@ export {
TextIcon,
InlineCodeIcon,
CodeBlockIcon,
CheckListIcon,
};
15 changes: 12 additions & 3 deletions apps/front-end/src/plugins/CommandPickerPlugin/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import {
BoldIcon,
CheckListIcon,
CodeIcon,
HeadingIcon,
InlineCodeIcon,
ItalicIcon,
ParagraphIcon,
QuoteIcon,
StrikethroughIcon,
UnderlineIcon,
TextIcon,
InlineCodeIcon,
UnderlineIcon,
} from "@/components/Icons";
import {
INSERT_CHECK_LIST_COMMAND,
INSERT_ORDERED_LIST_COMMAND,
INSERT_UNORDERED_LIST_COMMAND,
} from "@lexical/list";
Expand All @@ -33,6 +35,7 @@ import {
import { INSERT_IMAGE_COMMAND } from "../ImagePlugin";
import useLexicalCommand from "../useLexicalCommand";
import CommandPicker, { CommandPickerItem } from "./CommandPicker";
import { InsertImageCommand } from "./InsertImageDialog";
import {
CLEAR_FORMAT_TEXT_COMMAND,
FORMAT_PARAGRAPH_COMMAND,
Expand All @@ -49,7 +52,6 @@ import {
useRemoveCaretCommand,
} from "./commads";
import { $getQueryTextForSearch } from "./utils";
import { InsertImageCommand } from "./InsertImageDialog";

export type ComponentPickerMenuPluginProps = {
/**
Expand Down Expand Up @@ -197,6 +199,13 @@ export default function ComponentPickerMenuPlugin({
label="Ordered List"
/>

<CommandPickerItem
onSelect={() => dispatch(INSERT_CHECK_LIST_COMMAND, undefined)}
keywords="list checklist todo"
icon={<CheckListIcon />}
label="Check List"
/>

<CommandPickerItem
onSelect={() => dispatch(FORMAT_TEXT_COMMAND, "code")}
keywords="code inline inlinecode "
Expand Down
6 changes: 3 additions & 3 deletions apps/front-end/src/plugins/ImagePlugin/ImageNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ const NODE_VERSION = 1;

class ImageNode extends DecoratorNode<ReactNode> {
constructor(
private src: string,
private alt: string = "",
public src: string,
public alt: string = "",
key?: NodeKey,
) {
super(key);
Expand Down Expand Up @@ -62,7 +62,7 @@ function $createImageNode(src: string, alt?: string) {
return new ImageNode(src, alt);
}

function $isImageNode(node: unknown) {
function $isImageNode(node: unknown): node is ImageNode {
return node instanceof ImageNode;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import {
CHECK_LIST,
ElementTransformer,
TRANSFORMERS as LEXICAL_TRANSFORMERS,
TextMatchTransformer,
} from "@lexical/markdown";
import {
ImageNode,
$isImageNode,
$createImageNode,
$isImageNode,
ImageNode,
} from "../ImagePlugin/ImageNode";

const IMAGE_TRANFORMER: TextMatchTransformer = {
Expand All @@ -27,13 +29,17 @@ const IMAGE_TRANFORMER: TextMatchTransformer = {
return null;
}

return `![${node.getAltText()}](${node.getSrc()})`;
return `![${node.alt}](${node.src})`;
},
};

const CHECK_LIST_TRANSFORMER: ElementTransformer = CHECK_LIST;
CHECK_LIST_TRANSFORMER.regExp = /^(\s*)(?:-)?\s?(\[(\s|x)?\])\s/i;

// Register all transformers here
const MARKDOWN_TRANFORMS: typeof LEXICAL_TRANSFORMERS = [
IMAGE_TRANFORMER,
CHECK_LIST_TRANSFORMER,
...LEXICAL_TRANSFORMERS,
];

Expand Down
Loading

0 comments on commit 2ba7038

Please sign in to comment.