diff --git a/.changeset/strong-cups-rhyme.md b/.changeset/strong-cups-rhyme.md new file mode 100644 index 0000000000..f1cbe424ce --- /dev/null +++ b/.changeset/strong-cups-rhyme.md @@ -0,0 +1,5 @@ +--- +"@udecode/plate-indent-list": minor +--- + +Add listStyleTypes option to custom indent list diff --git a/apps/www/src/lib/plate/demo/values/indentListValue.tsx b/apps/www/src/lib/plate/demo/values/indentListValue.tsx index c43616c70a..8a3fb8b5a1 100644 --- a/apps/www/src/lib/plate/demo/values/indentListValue.tsx +++ b/apps/www/src/lib/plate/demo/values/indentListValue.tsx @@ -7,13 +7,24 @@ jsx; export const indentListValue: any = ( Indent List - - Decimal 112 - + Create indented lists with multiple levels of indentation and customize the list style type for each level. + + Todo 1 + + + + Icon 1 + + + Icon 2 + + + Todo 2 + Roman 1 diff --git a/apps/www/src/registry/default/example/playground-demo.tsx b/apps/www/src/registry/default/example/playground-demo.tsx index dabc6aa916..07b62b30dd 100644 --- a/apps/www/src/registry/default/example/playground-demo.tsx +++ b/apps/www/src/registry/default/example/playground-demo.tsx @@ -118,7 +118,14 @@ 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 { + FireLiComponent, + FireMarker, +} from '@/registry/default/plate-ui/indent-fire-marker-component'; +import { + IndentTodoLiComponent, + TodoMarker, +} from '@/registry/default/plate-ui/indent-todo-marker-component'; import { MentionCombobox } from '@/registry/default/plate-ui/mention-combobox'; export const usePlaygroundPlugins = ({ @@ -234,7 +241,22 @@ export const usePlaygroundPlugins = ({ }, enabled: id === 'indentlist' || !!enabled.listStyleType, options: { - markerComponent: TodoMarker, + listStyleTypes: { + ['upper-roman']: { + type: 'upper-roman', + isNumbered: true, + }, + todo: { + type: 'todo', + markerComponent: TodoMarker, + liComponent: IndentTodoLiComponent, + }, + fire: { + type: 'fire', + markerComponent: FireMarker, + liComponent: FireLiComponent, + }, + }, }, }), createLineHeightPlugin({ diff --git a/apps/www/src/registry/default/plate-ui/indent-fire-marker-component.tsx b/apps/www/src/registry/default/plate-ui/indent-fire-marker-component.tsx new file mode 100644 index 0000000000..6924aeae9d --- /dev/null +++ b/apps/www/src/registry/default/plate-ui/indent-fire-marker-component.tsx @@ -0,0 +1,22 @@ +import { TIndentElement } from '@udecode/plate-indent'; +import { + LiComponentProps, + MarkerComponentProps, +} from '@udecode/plate-indent-list'; + +export const FireMarker = (props: MarkerComponentProps) => { + const { element } = props; + + return ( +
+ + {(element as TIndentElement).indent % 2 === 0 ? '🔥' : '🚀'} + +
+ ); +}; + +export const FireLiComponent = (props: LiComponentProps) => { + const { children } = props; + return {children}; +}; diff --git a/apps/www/src/registry/default/plate-ui/indent-todo-marker-component.tsx b/apps/www/src/registry/default/plate-ui/indent-todo-marker-component.tsx index 4db199d0b6..8f233b7ad8 100644 --- a/apps/www/src/registry/default/plate-ui/indent-todo-marker-component.tsx +++ b/apps/www/src/registry/default/plate-ui/indent-todo-marker-component.tsx @@ -1,14 +1,41 @@ -import { IMarkerComponentProps } from '@udecode/plate-indent-list'; +import { cn } from '@udecode/cn'; +import { + LiComponentProps, + MarkerComponentProps, +} from '@udecode/plate-indent-list'; +import { setNodes } from '@udecode/slate'; +import { findNodePath } from '@udecode/slate-react'; import { Checkbox } from './checkbox'; -export const TodoMarker = (props: IMarkerComponentProps) => { - const { onChange, checked } = props; +export const TodoMarker = (props: MarkerComponentProps) => { + const { editor, element } = props; + + const onChange = (v: boolean) => { + const path = findNodePath(editor, element); + setNodes(editor, { checked: v }, { at: path }); + }; + + return ( +
+ +
+ ); +}; + +export const IndentTodoLiComponent = (props: LiComponentProps) => { + const { element, children } = props; return ( - + + {children} + ); }; diff --git a/packages/indent-list/src/createIndentListPlugin.ts b/packages/indent-list/src/createIndentListPlugin.ts index 0e9c823020..073bd3a4ab 100644 --- a/packages/indent-list/src/createIndentListPlugin.ts +++ b/packages/indent-list/src/createIndentListPlugin.ts @@ -12,7 +12,7 @@ import { import { injectIndentListComponent } from './injectIndentListComponent'; import { onKeyDownIndentList } from './onKeyDownIndentList'; import { GetSiblingIndentListOptions } from './queries/getSiblingIndentList'; -import { ListStyleType } from './types'; +import { LiComponentProps, ListStyleType, MarkerComponentProps } from './types'; import { withIndentList } from './withIndentList'; export const KEY_LIST_STYLE_TYPE = 'listStyleType'; @@ -29,12 +29,15 @@ export interface IndentListPlugin { */ getListStyleType?: (element: HTMLElement) => ListStyleType; - markerComponent?: React.FC; -} - -export interface IMarkerComponentProps { - onChange: (checked: boolean) => void; - checked: boolean; + listStyleTypes?: Record< + string, + { + type: string; + markerComponent?: React.FC; + liComponent?: React.FC; + isNumbered?: boolean; + } + >; } export const createIndentListPlugin = createPluginFactory({ diff --git a/packages/indent-list/src/injectIndentListComponent.tsx b/packages/indent-list/src/injectIndentListComponent.tsx index ffb630f8dc..d84a6b8a41 100644 --- a/packages/indent-list/src/injectIndentListComponent.tsx +++ b/packages/indent-list/src/injectIndentListComponent.tsx @@ -1,21 +1,16 @@ import React from 'react'; import { - findNodePath, getPluginOptions, InjectComponentProps, InjectComponentReturnType, - setNodes, } from '@udecode/plate-common'; import { clsx } from 'clsx'; 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 = ( props: InjectComponentProps @@ -25,84 +20,44 @@ export const injectIndentListComponent = ( const listStyleType = element[KEY_LIST_STYLE_TYPE] as string; const listStart = element[KEY_LIST_START] as number; - const isTodo = - element.hasOwnProperty(KEY_LIST_CHECKED) && - listStyleType === KEY_TODO_STYLE_TYPE; - - if (listStyleType && !isTodo) { + if (listStyleType) { let className = clsx(`slate-${KEY_LIST_STYLE_TYPE}-${listStyleType}`); const style: React.CSSProperties = { padding: 0, margin: 0, listStyleType, + position: 'relative', }; - if ( - [ListStyleType.Disc, ListStyleType.Circle, ListStyleType.Square].includes( - listStyleType as ListStyleType - ) - ) { - className = clsx(className, 'slate-list-bullet'); + return function Ul({ editor, children }) { + const { listStyleTypes = {} } = getPluginOptions( + editor, + KEY_LIST_STYLE_TYPE + ); - return function Ul({ children }) { - return ( -
    -
  • {children}
  • -
- ); - }; - } + const targetList = listStyleTypes[listStyleType] ?? {}; + const isNumbered = targetList ? targetList.isNumbered : false; - className = clsx(className, 'slate-list-number'); + className = isNumbered + ? clsx(className, 'slate-list-number') + : clsx(className, 'slate-list-bullet'); - return function Ol({ children }) { - return ( -
    -
  1. {children}
  2. -
- ); - }; - } + const { + markerComponent = null, + // eslint-disable-next-line @typescript-eslint/no-shadow + liComponent = ({ children }: any) =>
  • {children}
  • , + } = targetList; - 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( - editor, - KEY_LIST_STYLE_TYPE - ); + const Wrap = isNumbered ? 'ol' : 'ul'; return ( -
    -
    - {markerComponent ? ( - markerComponent({ - checked: checked, - onChange: (v: boolean) => { - const path = findNodePath(editor, element); - setNodes(editor, { checked: v }, { at: path }); - }, - }) - ) : ( - { - const path = findNodePath(editor, element); - setNodes(editor, { checked: v.target.checked }, { at: path }); - }} - /> - )} -
    - {children} -
    + + {markerComponent && markerComponent({ editor, element })} + {liComponent({ + children, + element, + })} + ); }; } diff --git a/packages/indent-list/src/types.ts b/packages/indent-list/src/types.ts index 64ccdb04b5..efcdf20253 100644 --- a/packages/indent-list/src/types.ts +++ b/packages/indent-list/src/types.ts @@ -1,3 +1,5 @@ +import { PlateEditor, TElement, Value } from '@udecode/plate-common'; + export enum ListStyleType { // The marker is traditional Armenian numbering Armenian = 'armenian', @@ -68,3 +70,14 @@ export enum ListStyleType { // Inherits this property from its parent element. Read about inherit Inherit = 'inherit', } + +export interface LiComponentProps { + element: TElement; + children: any; +} + +export interface MarkerComponentProps { + onChange?: (checked: boolean) => void; + element: TElement; + editor: PlateEditor; +}