返回 presentation-ai
block-list.tsx
根目录 / src / components / plate / ui / block-list.tsx
1 "use client";
2
3 import { isOrderedList } from "@platejs/list";
4 import {
5 useTodoListElement,
6 useTodoListElementState,
7 } from "@platejs/list/react";
8 import { type TListElement } from "platejs";
9 import {
10 useReadOnly,
11 type PlateElementProps,
12 type RenderNodeWrapper,
13 } from "platejs/react";
14 import type React from "react";
15
16 import { Checkbox } from "@/components/plate/ui/checkbox";
17 import { cn } from "@/lib/utils";
18
19 const config: Record<
20 string,
21 {
22 Li: React.FC<PlateElementProps>;
23 Marker: React.FC<PlateElementProps>;
24 }
25 > = {
26 todo: {
27 Li: TodoLi,
28 Marker: TodoMarker,
29 },
30 };
31
32 export const BlockList: RenderNodeWrapper = (props) => {
33 if (!props.element.listStyleType) return;
34
35 return (props) => <List {...props} />;
36 };
37
38 function List(props: PlateElementProps) {
39 const { listStart, listStyleType } = props.element as TListElement;
40 const { Li, Marker } = config[listStyleType] ?? {};
41 const List = isOrderedList(props.element) ? "ol" : "ul";
42
43 return (
44 <List className="relative m-0" style={{ listStyleType }} start={listStart}>
45 {Marker && <Marker {...props} />}
46 {Li ? <Li {...props} /> : <li>{props.children}</li>}
47 </List>
48 );
49 }
50
51 function TodoMarker(props: PlateElementProps) {
52 const state = useTodoListElementState({ element: props.element });
53 const { checkboxProps } = useTodoListElement(state);
54 const readOnly = useReadOnly();
55
56 return (
57 <div contentEditable={false}>
58 <Checkbox
59 className={cn(
60 "absolute top-1 -left-6",
61 readOnly && "pointer-events-none",
62 )}
63 {...checkboxProps}
64 />
65 </div>
66 );
67 }
68
69 function TodoLi(props: PlateElementProps) {
70 return (
71 <li
72 className={cn(
73 "list-none",
74 (props.element.checked as boolean) &&
75 "text-muted-foreground line-through",
76 )}
77 >
78 {props.children}
79 </li>
80 );
81 }
82
82 lines Plain Text