返回 presentation-ai
block-list-static.tsx
根目录 / src / components / plate / ui / block-list-static.tsx
1 import { isOrderedList } from "@platejs/list";
2 import { CheckIcon } from "lucide-react";
3 import { type TListElement } from "platejs";
4 import { type SlateRenderElementProps } from "platejs/static";
5 import type * as React from "react";
6
7 import { cn } from "@/lib/utils";
8
9 type RenderStaticNodeWrapper = (
10 props: SlateRenderElementProps,
11 ) =>
12 | ((props: SlateRenderElementProps) => React.ReactElement | null | undefined)
13 | undefined;
14
15 const config: Record<
16 string,
17 {
18 Li: React.FC<SlateRenderElementProps>;
19 Marker: React.FC<SlateRenderElementProps>;
20 }
21 > = {
22 todo: {
23 Li: TodoLiStatic,
24 Marker: TodoMarkerStatic,
25 },
26 };
27
28 export const BlockListStatic: RenderStaticNodeWrapper = (props) => {
29 if (!props.element.listStyleType) return;
30
31 return (props) => <List {...props} />;
32 };
33
34 function List(props: SlateRenderElementProps) {
35 const { listStart, listStyleType } = props.element as TListElement;
36 const { Li, Marker } = config[listStyleType] ?? {};
37 const List = isOrderedList(props.element) ? "ol" : "ul";
38
39 return (
40 <List
41 className="relative m-0 p-0"
42 style={{ listStyleType }}
43 start={listStart}
44 >
45 {Marker && <Marker {...props} />}
46 {Li ? <Li {...props} /> : <li>{props.children}</li>}
47 </List>
48 );
49 }
50
51 function TodoMarkerStatic(props: SlateRenderElementProps) {
52 const checked = props.element.checked as boolean;
53
54 return (
55 <div contentEditable={false}>
56 <button
57 className={cn(
58 "peer pointer-events-none absolute top-1 -left-6 size-4 shrink-0 rounded-sm border border-primary bg-background ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-hidden data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
59 props.className,
60 )}
61 data-state={checked ? "checked" : "unchecked"}
62 type="button"
63 >
64 <div className={cn("flex items-center justify-center text-current")}>
65 {checked && <CheckIcon className="size-4" />}
66 </div>
67 </button>
68 </div>
69 );
70 }
71
72 function TodoLiStatic(props: SlateRenderElementProps) {
73 return (
74 <li
75 className={cn(
76 "list-none",
77 (props.element.checked as boolean) &&
78 "text-muted-foreground line-through",
79 )}
80 >
81 {props.children}
82 </li>
83 );
84 }
85
85 lines Plain Text