Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/npm_and_yarn/npm_and_yarn-securit…
Browse files Browse the repository at this point in the history
…y-group-29ffd4c3ca
  • Loading branch information
zbeyens authored Mar 25, 2024
2 parents 6f9942b + d067806 commit 5c25d31
Show file tree
Hide file tree
Showing 29 changed files with 470 additions and 34 deletions.
5 changes: 5 additions & 0 deletions .changeset/late-pants-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@udecode/plate-serializer-html": patch
---

Fixes "The `useSlateStatic` hook must be used inside the <Slate> component's context." error in `serializeHtml`
6 changes: 6 additions & 0 deletions .changeset/old-fireants-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@udecode/plate-indent-list": minor
"@udecode/plate-indent": minor
---

Feature: todo lists
2 changes: 2 additions & 0 deletions apps/www/src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import {
Settings,
Settings2,
Smile,
Square,
Strikethrough,
Subscript,
SunMedium,
Expand Down Expand Up @@ -255,6 +256,7 @@ const yarn = (props: LucideProps) => (
);

export const Icons = {
todo: Square,
add: Plus,
alignCenter: AlignCenter,
alignJustify: AlignJustify,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ColorDropdownMenu } from '@/registry/default/plate-ui/color-dropdown-me
import { CommentToolbarButton } from '@/registry/default/plate-ui/comment-toolbar-button';
import { EmojiDropdownMenu } from '@/registry/default/plate-ui/emoji-dropdown-menu';
import { IndentListToolbarButton } from '@/registry/default/plate-ui/indent-list-toolbar-button';
import { IndentTodoToolbarButton } from '@/registry/default/plate-ui/indent-todo-toolbar-button';
import { IndentToolbarButton } from '@/registry/default/plate-ui/indent-toolbar-button';
import { LineHeightDropdownMenu } from '@/registry/default/plate-ui/line-height-dropdown-menu';
import { LinkToolbarButton } from '@/registry/default/plate-ui/link-toolbar-button';
Expand Down Expand Up @@ -115,6 +116,7 @@ export function PlaygroundFixedToolbarButtons({ id }: { id?: ValueId }) {
<>
<IndentListToolbarButton nodeType={ListStyleType.Disc} />
<IndentListToolbarButton nodeType={ListStyleType.Decimal} />
<IndentTodoToolbarButton />
</>
)}

Expand Down
35 changes: 34 additions & 1 deletion apps/www/src/lib/plate/demo/plugins/autoformatIndentLists.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { AutoformatRule } from '@udecode/plate-autoformat';
import { ListStyleType, toggleIndentList } from '@udecode/plate-indent-list';
import {
KEY_TODO_STYLE_TYPE,
ListStyleType,
toggleIndentList,
} from '@udecode/plate-indent-list';
import { setNodes } from '@udecode/slate';

export const autoformatIndentLists: AutoformatRule[] = [
{
Expand All @@ -21,4 +26,32 @@ export const autoformatIndentLists: AutoformatRule[] = [
listStyleType: ListStyleType.Decimal,
}),
},
{
mode: 'block',
type: 'list',
match: ['[] '],
format: (editor) => {
toggleIndentList(editor, {
listStyleType: KEY_TODO_STYLE_TYPE,
});
setNodes(editor, {
listStyleType: KEY_TODO_STYLE_TYPE,
checked: false,
});
},
},
{
mode: 'block',
type: 'list',
match: ['[x] '],
format: (editor) => {
toggleIndentList(editor, {
listStyleType: KEY_TODO_STYLE_TYPE,
});
setNodes(editor, {
listStyleType: KEY_TODO_STYLE_TYPE,
checked: true,
});
},
},
];
4 changes: 4 additions & 0 deletions apps/www/src/lib/plate/demo/values/indentListValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ jsx;
export const indentListValue: any = (
<fragment>
<hh2>Indent List</hh2>
<hp indent={1} listStyleType="todo" checked={true}>
Decimal 112
</hp>
<hp>
Create indented lists with multiple levels of indentation and customize
the list style type for each level.
Expand All @@ -23,6 +26,7 @@ export const indentListValue: any = (
<hp indent={3} listStyleType="decimal" listStart={2}>
Decimal 112
</hp>

{/* <hp indent={3} listStyleType="lower-latin"> */}
{/* 7K-T */}
{/* </hp> */}
Expand Down
4 changes: 4 additions & 0 deletions apps/www/src/registry/default/example/playground-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ import { CursorOverlay } from '@/registry/default/plate-ui/cursor-overlay';
import { Editor } from '@/registry/default/plate-ui/editor';
import { FixedToolbar } from '@/registry/default/plate-ui/fixed-toolbar';
import { FloatingToolbar } from '@/registry/default/plate-ui/floating-toolbar';
import { TodoMarker } from '@/registry/default/plate-ui/indent-todo-marker-component';
import { MentionCombobox } from '@/registry/default/plate-ui/mention-combobox';

export const usePlaygroundPlugins = ({
Expand Down Expand Up @@ -232,6 +233,9 @@ export const usePlaygroundPlugins = ({
},
},
enabled: id === 'indentlist' || !!enabled.listStyleType,
options: {
markerComponent: TodoMarker,
},
}),
createLineHeightPlugin({
...lineHeightPlugin,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { IMarkerComponentProps } from '@udecode/plate-indent-list';

import { Checkbox } from './checkbox';

export const TodoMarker = (props: IMarkerComponentProps) => {
const { onChange, checked } = props;
return (
<Checkbox
style={{ left: -24, top: 4, position: 'absolute' }}
onCheckedChange={onChange}
checked={checked}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
useIndentTodoToolBarButton,
useIndentTodoToolBarButtonState,
} from '@udecode/plate-indent-list';
import { withRef } from '@udecode/react-utils';

import { Icons } from '@/components/icons';

import { ToolbarButton } from './toolbar';

export const IndentTodoToolbarButton = withRef<typeof ToolbarButton>(
(rest, ref) => {
const state = useIndentTodoToolBarButtonState({ nodeType: 'todo' });
const { props } = useIndentTodoToolBarButton(state);

return (
<ToolbarButton ref={ref} tooltip="Todo" {...props} {...rest}>
<Icons.todo />
</ToolbarButton>
);
}
);
11 changes: 10 additions & 1 deletion packages/indent-list/src/createIndentListPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,23 @@ import { withIndentList } from './withIndentList';
export const KEY_LIST_STYLE_TYPE = 'listStyleType';
export const KEY_LIST_START = 'listStart';
export const KEY_LIST_RESTART = 'listRestart';
export const KEY_LIST_CHECKED = 'checked';
export const KEY_TODO_STYLE_TYPE = 'todo';

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

/**
/**x
* Map html element to list style type.
*/
getListStyleType?: (element: HTMLElement) => ListStyleType;

markerComponent?: React.FC<IMarkerComponentProps>;
}

export interface IMarkerComponentProps {
onChange: (checked: boolean) => void;
checked: boolean;
}

export const createIndentListPlugin = createPluginFactory<IndentListPlugin>({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {
getAboveNode,
getNodeString,
isCollapsed,
isDefined,
PlateEditor,
Value,
} from '@udecode/plate-common';
import { TextUnit } from 'slate';

import { KEY_LIST_STYLE_TYPE } from '../createIndentListPlugin';
import { outdentList } from '../transforms';

export const deleteBackwardIndentList = <V extends Value>(
editor: PlateEditor<V>
) => {
const { deleteBackward } = editor;

return function (unit: TextUnit) {
deleteBackwardHelper(editor);
deleteBackward(unit);
};
};

function deleteBackwardHelper<V extends Value>(editor: PlateEditor<V>) {
if (isCollapsed(editor.selection)) {
const str = getNodeString(editor);
if (str) return;
const entry = getAboveNode(editor);
if (!entry) return;
const node = entry[0];
if (isDefined(node[KEY_LIST_STYLE_TYPE])) {
outdentList(editor);
}
}
}
1 change: 1 addition & 0 deletions packages/indent-list/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

export * from './someIndentList';
export * from './useIndentListToolbarButton';
export * from './useIndentTodoToolbarButton';
5 changes: 3 additions & 2 deletions packages/indent-list/src/hooks/someIndentList.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PlateEditor, someNode, Value } from '@udecode/plate-common';

import { KEY_LIST_STYLE_TYPE, ListStyleType } from '../index';
import { KEY_LIST_CHECKED, KEY_LIST_STYLE_TYPE, ListStyleType } from '../index';

export const someIndentList = <V extends Value>(
editor: PlateEditor<V>,
Expand All @@ -12,7 +12,8 @@ export const someIndentList = <V extends Value>(
match: (n) => {
const list = n[KEY_LIST_STYLE_TYPE];
if (type === ListStyleType.Disc) return list === ListStyleType.Disc;
return !!list && list !== ListStyleType.Disc;
const isHasProperty = n.hasOwnProperty(KEY_LIST_CHECKED);
return !!list && list !== ListStyleType.Disc && !isHasProperty;
},
})
);
Expand Down
21 changes: 21 additions & 0 deletions packages/indent-list/src/hooks/someIndentTodo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { PlateEditor, someNode, Value } from '@udecode/plate-common';

import {
KEY_LIST_CHECKED,
KEY_LIST_STYLE_TYPE,
KEY_TODO_STYLE_TYPE,
} from '../index';

export const someIndentTodo = <V extends Value>(
editor: PlateEditor<V>,
type: string
) => {
return someNode(editor, {
at: editor.selection!,
match: (n) => {
const list = n[KEY_LIST_STYLE_TYPE];
const isHasProperty = n.hasOwnProperty(KEY_LIST_CHECKED);
return n.type === 'p' && isHasProperty && list === KEY_TODO_STYLE_TYPE;
},
});
};
37 changes: 37 additions & 0 deletions packages/indent-list/src/hooks/useIndentTodoToolbarButton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useEditorRef, useEditorSelector } from '@udecode/plate-common';

import { ListStyleType, toggleIndentList } from '../index';
import { someIndentTodo } from './someIndentTodo';

export const useIndentTodoToolBarButtonState = ({
nodeType = ListStyleType.Disc,
}: { nodeType?: string } = {}) => {
const pressed = useEditorSelector(
(editor) => someIndentTodo(editor, nodeType),
[nodeType]
);
return {
pressed,
nodeType,
};
};

export const useIndentTodoToolBarButton = ({
nodeType,
pressed,
}: ReturnType<typeof useIndentTodoToolBarButtonState>) => {
const editor = useEditorRef();
return {
props: {
pressed,
onMouseDown: (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
},
onClick: () => {
toggleIndentList(editor, {
listStyleType: nodeType,
});
},
},
};
};
64 changes: 62 additions & 2 deletions packages/indent-list/src/injectIndentListComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import React from 'react';
import {
findNodePath,
getPluginOptions,
InjectComponentProps,
InjectComponentReturnType,
setNodes,
} from '@udecode/plate-common';
import { clsx } from 'clsx';

import { KEY_LIST_START, KEY_LIST_STYLE_TYPE } from './createIndentListPlugin';
import {
IndentListPlugin,
KEY_LIST_CHECKED,
KEY_LIST_START,
KEY_LIST_STYLE_TYPE,
KEY_TODO_STYLE_TYPE,
} from './createIndentListPlugin';
import { ListStyleType } from './types';

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

if (listStyleType) {
const isTodo =
element.hasOwnProperty(KEY_LIST_CHECKED) &&
listStyleType === KEY_TODO_STYLE_TYPE;

if (listStyleType && !isTodo) {
let className = clsx(`slate-${KEY_LIST_STYLE_TYPE}-${listStyleType}`);
const style: React.CSSProperties = {
padding: 0,
Expand Down Expand Up @@ -50,4 +63,51 @@ export const injectIndentListComponent = (
);
};
}

if (isTodo) {
const className = clsx('slate-list-todo');
const checked = element[KEY_LIST_CHECKED] as boolean;
const style: React.CSSProperties = {
position: 'relative',
padding: 0,
margin: 0,
};
return function Ol({ children, editor }) {
const { markerComponent } = getPluginOptions<IndentListPlugin>(
editor,
KEY_LIST_STYLE_TYPE
);

return (
<div className={`${className}`} style={style}>
{markerComponent ? (
markerComponent({
checked: checked,
onChange: (v: boolean) => {
const path = findNodePath(editor, element);
setNodes(editor, { checked: v }, { at: path });
},
})
) : (
<input
contentEditable={false}
data-slate-void
type="checkbox"
style={{
marginRight: 5,
marginLeft: -17,
paddingTop: -10,
}}
checked={checked}
onChange={(v) => {
const path = findNodePath(editor, element);
setNodes(editor, { checked: v.target.checked }, { at: path });
}}
/>
)}
<span>{children}</span>
</div>
);
};
}
};
Loading

0 comments on commit 5c25d31

Please sign in to comment.