Skip to content

Commit

Permalink
Merge pull request #3073 from udecode/feat/checked-marker
Browse files Browse the repository at this point in the history
Feat/checked marker
  • Loading branch information
zbeyens authored Mar 27, 2024
2 parents 7e1c1be + 66de99b commit d009f53
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 90 deletions.
5 changes: 5 additions & 0 deletions .changeset/strong-cups-rhyme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@udecode/plate-indent-list": minor
---

Add listStyleTypes option to custom indent list
17 changes: 14 additions & 3 deletions apps/www/src/lib/plate/demo/values/indentListValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,24 @@ 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.
</hp>
<hp indent={1} listStyleType="todo" checked={true}>
Todo 1
</hp>

<hp indent={1} listStyleType="fire">
Icon 1
</hp>
<hp indent={2} listStyleType="fire">
Icon 2
</hp>
<hp indent={3} listStyleType="todo" checked={false}>
Todo 2
</hp>
<hp indent={1} listStyleType="upper-roman">
Roman 1
</hp>
Expand Down
26 changes: 24 additions & 2 deletions apps/www/src/registry/default/example/playground-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ({
Expand Down Expand Up @@ -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({
Expand Down
Original file line number Diff line number Diff line change
@@ -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 (
<div contentEditable={false}>
<span style={{ left: -26, top: -1, position: 'absolute' }}>
{(element as TIndentElement).indent % 2 === 0 ? '🔥' : '🚀'}
</span>
</div>
);
};

export const FireLiComponent = (props: LiComponentProps) => {
const { children } = props;
return <span>{children}</span>;
};
Original file line number Diff line number Diff line change
@@ -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 (
<div contentEditable={false}>
<Checkbox
style={{ left: -24, top: 4, position: 'absolute' }}
checked={element.checked as boolean}
onCheckedChange={onChange}
/>
</div>
);
};

export const IndentTodoLiComponent = (props: LiComponentProps) => {
const { element, children } = props;
return (
<Checkbox
style={{ left: -24, top: 4, position: 'absolute' }}
onCheckedChange={onChange}
checked={checked}
/>
<span
className={cn(
(element.checked as boolean) && 'text-muted-foreground line-through'
)}
>
{children}
</span>
);
};
17 changes: 10 additions & 7 deletions packages/indent-list/src/createIndentListPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -29,12 +29,15 @@ export interface IndentListPlugin {
*/
getListStyleType?: (element: HTMLElement) => ListStyleType;

markerComponent?: React.FC<IMarkerComponentProps>;
}

export interface IMarkerComponentProps {
onChange: (checked: boolean) => void;
checked: boolean;
listStyleTypes?: Record<
string,
{
type: string;
markerComponent?: React.FC<MarkerComponentProps>;
liComponent?: React.FC<LiComponentProps>;
isNumbered?: boolean;
}
>;
}

export const createIndentListPlugin = createPluginFactory<IndentListPlugin>({
Expand Down
95 changes: 25 additions & 70 deletions packages/indent-list/src/injectIndentListComponent.tsx
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<IndentListPlugin>(
editor,
KEY_LIST_STYLE_TYPE
);

return function Ul({ children }) {
return (
<ul style={style} className={className}>
<li>{children}</li>
</ul>
);
};
}
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 (
<ol style={style} className={className} start={listStart}>
<li>{children}</li>
</ol>
);
};
}
const {
markerComponent = null,
// eslint-disable-next-line @typescript-eslint/no-shadow
liComponent = ({ children }: any) => <li>{children}</li>,
} = 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<IndentListPlugin>(
editor,
KEY_LIST_STYLE_TYPE
);
const Wrap = isNumbered ? 'ol' : 'ul';

return (
<div className={`${className}`} style={style}>
<div contentEditable={false}>
{markerComponent ? (
markerComponent({
checked: checked,
onChange: (v: boolean) => {
const path = findNodePath(editor, element);
setNodes(editor, { checked: v }, { at: path });
},
})
) : (
<input
type="checkbox"
style={{ position: 'absolute', left: -19, top: 6 }}
checked={checked}
onChange={(v) => {
const path = findNodePath(editor, element);
setNodes(editor, { checked: v.target.checked }, { at: path });
}}
/>
)}
</div>
<span>{children}</span>
</div>
<Wrap style={style} className={className} start={listStart}>
{markerComponent && markerComponent({ editor, element })}
{liComponent({
children,
element,
})}
</Wrap>
);
};
}
Expand Down
13 changes: 13 additions & 0 deletions packages/indent-list/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { PlateEditor, TElement, Value } from '@udecode/plate-common';

export enum ListStyleType {
// The marker is traditional Armenian numbering
Armenian = 'armenian',
Expand Down Expand Up @@ -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<Value>;
}

0 comments on commit d009f53

Please sign in to comment.