Skip to content

Commit 5c25d31

Browse files
authored
Merge branch 'main' into dependabot/npm_and_yarn/npm_and_yarn-security-group-29ffd4c3ca
2 parents 6f9942b + d067806 commit 5c25d31

29 files changed

+470
-34
lines changed

.changeset/late-pants-drum.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@udecode/plate-serializer-html": patch
3+
---
4+
5+
Fixes "The `useSlateStatic` hook must be used inside the <Slate> component's context." error in `serializeHtml`

.changeset/old-fireants-relate.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@udecode/plate-indent-list": minor
3+
"@udecode/plate-indent": minor
4+
---
5+
6+
Feature: todo lists

apps/www/src/components/icons.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ import {
6666
Settings,
6767
Settings2,
6868
Smile,
69+
Square,
6970
Strikethrough,
7071
Subscript,
7172
SunMedium,
@@ -255,6 +256,7 @@ const yarn = (props: LucideProps) => (
255256
);
256257

257258
export const Icons = {
259+
todo: Square,
258260
add: Plus,
259261
alignCenter: AlignCenter,
260262
alignJustify: AlignJustify,

apps/www/src/components/plate-ui/playground-fixed-toolbar-buttons.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { ColorDropdownMenu } from '@/registry/default/plate-ui/color-dropdown-me
2121
import { CommentToolbarButton } from '@/registry/default/plate-ui/comment-toolbar-button';
2222
import { EmojiDropdownMenu } from '@/registry/default/plate-ui/emoji-dropdown-menu';
2323
import { IndentListToolbarButton } from '@/registry/default/plate-ui/indent-list-toolbar-button';
24+
import { IndentTodoToolbarButton } from '@/registry/default/plate-ui/indent-todo-toolbar-button';
2425
import { IndentToolbarButton } from '@/registry/default/plate-ui/indent-toolbar-button';
2526
import { LineHeightDropdownMenu } from '@/registry/default/plate-ui/line-height-dropdown-menu';
2627
import { LinkToolbarButton } from '@/registry/default/plate-ui/link-toolbar-button';
@@ -115,6 +116,7 @@ export function PlaygroundFixedToolbarButtons({ id }: { id?: ValueId }) {
115116
<>
116117
<IndentListToolbarButton nodeType={ListStyleType.Disc} />
117118
<IndentListToolbarButton nodeType={ListStyleType.Decimal} />
119+
<IndentTodoToolbarButton />
118120
</>
119121
)}
120122

apps/www/src/lib/plate/demo/plugins/autoformatIndentLists.ts

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { AutoformatRule } from '@udecode/plate-autoformat';
2-
import { ListStyleType, toggleIndentList } from '@udecode/plate-indent-list';
2+
import {
3+
KEY_TODO_STYLE_TYPE,
4+
ListStyleType,
5+
toggleIndentList,
6+
} from '@udecode/plate-indent-list';
7+
import { setNodes } from '@udecode/slate';
38

49
export const autoformatIndentLists: AutoformatRule[] = [
510
{
@@ -21,4 +26,32 @@ export const autoformatIndentLists: AutoformatRule[] = [
2126
listStyleType: ListStyleType.Decimal,
2227
}),
2328
},
29+
{
30+
mode: 'block',
31+
type: 'list',
32+
match: ['[] '],
33+
format: (editor) => {
34+
toggleIndentList(editor, {
35+
listStyleType: KEY_TODO_STYLE_TYPE,
36+
});
37+
setNodes(editor, {
38+
listStyleType: KEY_TODO_STYLE_TYPE,
39+
checked: false,
40+
});
41+
},
42+
},
43+
{
44+
mode: 'block',
45+
type: 'list',
46+
match: ['[x] '],
47+
format: (editor) => {
48+
toggleIndentList(editor, {
49+
listStyleType: KEY_TODO_STYLE_TYPE,
50+
});
51+
setNodes(editor, {
52+
listStyleType: KEY_TODO_STYLE_TYPE,
53+
checked: true,
54+
});
55+
},
56+
},
2457
];

apps/www/src/lib/plate/demo/values/indentListValue.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ jsx;
77
export const indentListValue: any = (
88
<fragment>
99
<hh2>Indent List</hh2>
10+
<hp indent={1} listStyleType="todo" checked={true}>
11+
Decimal 112
12+
</hp>
1013
<hp>
1114
Create indented lists with multiple levels of indentation and customize
1215
the list style type for each level.
@@ -23,6 +26,7 @@ export const indentListValue: any = (
2326
<hp indent={3} listStyleType="decimal" listStart={2}>
2427
Decimal 112
2528
</hp>
29+
2630
{/* <hp indent={3} listStyleType="lower-latin"> */}
2731
{/* 7K-T */}
2832
{/* </hp> */}

apps/www/src/registry/default/example/playground-demo.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ import { CursorOverlay } from '@/registry/default/plate-ui/cursor-overlay';
118118
import { Editor } from '@/registry/default/plate-ui/editor';
119119
import { FixedToolbar } from '@/registry/default/plate-ui/fixed-toolbar';
120120
import { FloatingToolbar } from '@/registry/default/plate-ui/floating-toolbar';
121+
import { TodoMarker } from '@/registry/default/plate-ui/indent-todo-marker-component';
121122
import { MentionCombobox } from '@/registry/default/plate-ui/mention-combobox';
122123

123124
export const usePlaygroundPlugins = ({
@@ -232,6 +233,9 @@ export const usePlaygroundPlugins = ({
232233
},
233234
},
234235
enabled: id === 'indentlist' || !!enabled.listStyleType,
236+
options: {
237+
markerComponent: TodoMarker,
238+
},
235239
}),
236240
createLineHeightPlugin({
237241
...lineHeightPlugin,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { IMarkerComponentProps } from '@udecode/plate-indent-list';
2+
3+
import { Checkbox } from './checkbox';
4+
5+
export const TodoMarker = (props: IMarkerComponentProps) => {
6+
const { onChange, checked } = props;
7+
return (
8+
<Checkbox
9+
style={{ left: -24, top: 4, position: 'absolute' }}
10+
onCheckedChange={onChange}
11+
checked={checked}
12+
/>
13+
);
14+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {
2+
useIndentTodoToolBarButton,
3+
useIndentTodoToolBarButtonState,
4+
} from '@udecode/plate-indent-list';
5+
import { withRef } from '@udecode/react-utils';
6+
7+
import { Icons } from '@/components/icons';
8+
9+
import { ToolbarButton } from './toolbar';
10+
11+
export const IndentTodoToolbarButton = withRef<typeof ToolbarButton>(
12+
(rest, ref) => {
13+
const state = useIndentTodoToolBarButtonState({ nodeType: 'todo' });
14+
const { props } = useIndentTodoToolBarButton(state);
15+
16+
return (
17+
<ToolbarButton ref={ref} tooltip="Todo" {...props} {...rest}>
18+
<Icons.todo />
19+
</ToolbarButton>
20+
);
21+
}
22+
);

packages/indent-list/src/createIndentListPlugin.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,23 @@ import { withIndentList } from './withIndentList';
1818
export const KEY_LIST_STYLE_TYPE = 'listStyleType';
1919
export const KEY_LIST_START = 'listStart';
2020
export const KEY_LIST_RESTART = 'listRestart';
21+
export const KEY_LIST_CHECKED = 'checked';
22+
export const KEY_TODO_STYLE_TYPE = 'todo';
2123

2224
export interface IndentListPlugin {
2325
getSiblingIndentListOptions?: GetSiblingIndentListOptions<TElement>;
2426

25-
/**
27+
/**x
2628
* Map html element to list style type.
2729
*/
2830
getListStyleType?: (element: HTMLElement) => ListStyleType;
31+
32+
markerComponent?: React.FC<IMarkerComponentProps>;
33+
}
34+
35+
export interface IMarkerComponentProps {
36+
onChange: (checked: boolean) => void;
37+
checked: boolean;
2938
}
3039

3140
export const createIndentListPlugin = createPluginFactory<IndentListPlugin>({
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
getAboveNode,
3+
getNodeString,
4+
isCollapsed,
5+
isDefined,
6+
PlateEditor,
7+
Value,
8+
} from '@udecode/plate-common';
9+
import { TextUnit } from 'slate';
10+
11+
import { KEY_LIST_STYLE_TYPE } from '../createIndentListPlugin';
12+
import { outdentList } from '../transforms';
13+
14+
export const deleteBackwardIndentList = <V extends Value>(
15+
editor: PlateEditor<V>
16+
) => {
17+
const { deleteBackward } = editor;
18+
19+
return function (unit: TextUnit) {
20+
deleteBackwardHelper(editor);
21+
deleteBackward(unit);
22+
};
23+
};
24+
25+
function deleteBackwardHelper<V extends Value>(editor: PlateEditor<V>) {
26+
if (isCollapsed(editor.selection)) {
27+
const str = getNodeString(editor);
28+
if (str) return;
29+
const entry = getAboveNode(editor);
30+
if (!entry) return;
31+
const node = entry[0];
32+
if (isDefined(node[KEY_LIST_STYLE_TYPE])) {
33+
outdentList(editor);
34+
}
35+
}
36+
}

packages/indent-list/src/hooks/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44

55
export * from './someIndentList';
66
export * from './useIndentListToolbarButton';
7+
export * from './useIndentTodoToolbarButton';

packages/indent-list/src/hooks/someIndentList.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { PlateEditor, someNode, Value } from '@udecode/plate-common';
22

3-
import { KEY_LIST_STYLE_TYPE, ListStyleType } from '../index';
3+
import { KEY_LIST_CHECKED, KEY_LIST_STYLE_TYPE, ListStyleType } from '../index';
44

55
export const someIndentList = <V extends Value>(
66
editor: PlateEditor<V>,
@@ -12,7 +12,8 @@ export const someIndentList = <V extends Value>(
1212
match: (n) => {
1313
const list = n[KEY_LIST_STYLE_TYPE];
1414
if (type === ListStyleType.Disc) return list === ListStyleType.Disc;
15-
return !!list && list !== ListStyleType.Disc;
15+
const isHasProperty = n.hasOwnProperty(KEY_LIST_CHECKED);
16+
return !!list && list !== ListStyleType.Disc && !isHasProperty;
1617
},
1718
})
1819
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { PlateEditor, someNode, Value } from '@udecode/plate-common';
2+
3+
import {
4+
KEY_LIST_CHECKED,
5+
KEY_LIST_STYLE_TYPE,
6+
KEY_TODO_STYLE_TYPE,
7+
} from '../index';
8+
9+
export const someIndentTodo = <V extends Value>(
10+
editor: PlateEditor<V>,
11+
type: string
12+
) => {
13+
return someNode(editor, {
14+
at: editor.selection!,
15+
match: (n) => {
16+
const list = n[KEY_LIST_STYLE_TYPE];
17+
const isHasProperty = n.hasOwnProperty(KEY_LIST_CHECKED);
18+
return n.type === 'p' && isHasProperty && list === KEY_TODO_STYLE_TYPE;
19+
},
20+
});
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useEditorRef, useEditorSelector } from '@udecode/plate-common';
2+
3+
import { ListStyleType, toggleIndentList } from '../index';
4+
import { someIndentTodo } from './someIndentTodo';
5+
6+
export const useIndentTodoToolBarButtonState = ({
7+
nodeType = ListStyleType.Disc,
8+
}: { nodeType?: string } = {}) => {
9+
const pressed = useEditorSelector(
10+
(editor) => someIndentTodo(editor, nodeType),
11+
[nodeType]
12+
);
13+
return {
14+
pressed,
15+
nodeType,
16+
};
17+
};
18+
19+
export const useIndentTodoToolBarButton = ({
20+
nodeType,
21+
pressed,
22+
}: ReturnType<typeof useIndentTodoToolBarButtonState>) => {
23+
const editor = useEditorRef();
24+
return {
25+
props: {
26+
pressed,
27+
onMouseDown: (e: React.MouseEvent<HTMLButtonElement>) => {
28+
e.preventDefault();
29+
},
30+
onClick: () => {
31+
toggleIndentList(editor, {
32+
listStyleType: nodeType,
33+
});
34+
},
35+
},
36+
};
37+
};

packages/indent-list/src/injectIndentListComponent.tsx

+62-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
import React from 'react';
22
import {
3+
findNodePath,
4+
getPluginOptions,
35
InjectComponentProps,
46
InjectComponentReturnType,
7+
setNodes,
58
} from '@udecode/plate-common';
69
import { clsx } from 'clsx';
710

8-
import { KEY_LIST_START, KEY_LIST_STYLE_TYPE } from './createIndentListPlugin';
11+
import {
12+
IndentListPlugin,
13+
KEY_LIST_CHECKED,
14+
KEY_LIST_START,
15+
KEY_LIST_STYLE_TYPE,
16+
KEY_TODO_STYLE_TYPE,
17+
} from './createIndentListPlugin';
918
import { ListStyleType } from './types';
1019

1120
export const injectIndentListComponent = (
@@ -16,7 +25,11 @@ export const injectIndentListComponent = (
1625
const listStyleType = element[KEY_LIST_STYLE_TYPE] as string;
1726
const listStart = element[KEY_LIST_START] as number;
1827

19-
if (listStyleType) {
28+
const isTodo =
29+
element.hasOwnProperty(KEY_LIST_CHECKED) &&
30+
listStyleType === KEY_TODO_STYLE_TYPE;
31+
32+
if (listStyleType && !isTodo) {
2033
let className = clsx(`slate-${KEY_LIST_STYLE_TYPE}-${listStyleType}`);
2134
const style: React.CSSProperties = {
2235
padding: 0,
@@ -50,4 +63,51 @@ export const injectIndentListComponent = (
5063
);
5164
};
5265
}
66+
67+
if (isTodo) {
68+
const className = clsx('slate-list-todo');
69+
const checked = element[KEY_LIST_CHECKED] as boolean;
70+
const style: React.CSSProperties = {
71+
position: 'relative',
72+
padding: 0,
73+
margin: 0,
74+
};
75+
return function Ol({ children, editor }) {
76+
const { markerComponent } = getPluginOptions<IndentListPlugin>(
77+
editor,
78+
KEY_LIST_STYLE_TYPE
79+
);
80+
81+
return (
82+
<div className={`${className}`} style={style}>
83+
{markerComponent ? (
84+
markerComponent({
85+
checked: checked,
86+
onChange: (v: boolean) => {
87+
const path = findNodePath(editor, element);
88+
setNodes(editor, { checked: v }, { at: path });
89+
},
90+
})
91+
) : (
92+
<input
93+
contentEditable={false}
94+
data-slate-void
95+
type="checkbox"
96+
style={{
97+
marginRight: 5,
98+
marginLeft: -17,
99+
paddingTop: -10,
100+
}}
101+
checked={checked}
102+
onChange={(v) => {
103+
const path = findNodePath(editor, element);
104+
setNodes(editor, { checked: v.target.checked }, { at: path });
105+
}}
106+
/>
107+
)}
108+
<span>{children}</span>
109+
</div>
110+
);
111+
};
112+
}
53113
};

0 commit comments

Comments
 (0)